Modernize GUI appearance with contemporary styling, icons, and improved layout

This commit is contained in:
root
2025-09-18 11:41:53 +02:00
parent 05f40c04d0
commit 27bec75522

View File

@@ -41,9 +41,12 @@ import sys
class RDPClient:
def __init__(self):
self.root = tk.Tk()
self.root.title("RDP Client - Professional (Press F1 for shortcuts)")
self.root.geometry("1000x700")
self.root.minsize(800, 600)
self.root.title("RDP Client - Professional")
self.root.geometry("1200x800")
self.root.minsize(900, 650)
# Modern styling
self._setup_modern_theme()
# Configuration
self.config_dir = os.path.expanduser("~/.config/rdp-client")
@@ -83,6 +86,96 @@ class RDPClient:
self.logger.info("RDP Client initialized successfully")
def _setup_modern_theme(self):
"""Setup modern visual theme and styling"""
# Configure the main window
self.root.configure(bg='#f8f9fa')
# Create and configure a modern style
style = ttk.Style()
# Try to use a modern theme if available
try:
style.theme_use('clam') # More modern than default
except:
pass
# Define modern color palette
self.colors = {
'primary': '#0066cc', # Modern blue
'primary_dark': '#004499', # Darker blue for hover
'secondary': '#6c757d', # Muted gray
'success': '#28a745', # Green
'danger': '#dc3545', # Red
'warning': '#ffc107', # Yellow
'info': '#17a2b8', # Cyan
'light': '#f8f9fa', # Light gray
'dark': '#343a40', # Dark gray
'white': '#ffffff',
'border': '#dee2e6', # Light border
'hover': '#e9ecef' # Hover gray
}
# Configure ttk styles with modern colors
style.configure('Modern.TFrame',
background=self.colors['white'],
relief='flat',
borderwidth=1)
style.configure('Card.TFrame',
background=self.colors['white'],
relief='solid',
borderwidth=1,
bordercolor=self.colors['border'])
style.configure('Modern.TLabel',
background=self.colors['white'],
foreground=self.colors['dark'],
font=('Segoe UI', 10))
style.configure('Title.TLabel',
background=self.colors['white'],
foreground=self.colors['dark'],
font=('Segoe UI', 12, 'bold'))
style.configure('Modern.TButton',
background=self.colors['primary'],
foreground=self.colors['white'],
borderwidth=0,
focuscolor='none',
font=('Segoe UI', 9))
style.map('Modern.TButton',
background=[('active', self.colors['primary_dark']),
('pressed', self.colors['primary_dark'])])
style.configure('Success.TButton',
background=self.colors['success'],
foreground=self.colors['white'],
borderwidth=0,
focuscolor='none',
font=('Segoe UI', 9))
style.configure('Danger.TButton',
background=self.colors['danger'],
foreground=self.colors['white'],
borderwidth=0,
focuscolor='none',
font=('Segoe UI', 9))
style.configure('Modern.Treeview',
background=self.colors['white'],
foreground=self.colors['dark'],
fieldbackground=self.colors['white'],
borderwidth=1,
relief='solid')
style.configure('Modern.Treeview.Heading',
background=self.colors['light'],
foreground=self.colors['dark'],
relief='flat',
font=('Segoe UI', 9, 'bold'))
def _setup_logging(self):
"""Setup logging configuration"""
self.logger = logging.getLogger('rdp_client')
@@ -342,13 +435,9 @@ class RDPClient:
return fallback
def _setup_gui(self):
"""Setup the main GUI"""
# Configure style
style = ttk.Style()
style.theme_use('clam')
# Main container
main_frame = ttk.Frame(self.root, padding="10")
"""Setup the main GUI with modern styling"""
# Main container with modern styling
main_frame = ttk.Frame(self.root, style='Modern.TFrame', padding="20")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Configure grid weights
@@ -357,92 +446,149 @@ class RDPClient:
main_frame.columnconfigure(1, weight=1)
main_frame.rowconfigure(1, weight=1)
# Title
title_label = ttk.Label(main_frame, text="RDP Client - Professional",
font=('Arial', 16, 'bold'))
title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
# Modern header with icon and title
header_frame = ttk.Frame(main_frame, style='Modern.TFrame')
header_frame.grid(row=0, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 20))
header_frame.columnconfigure(1, weight=1)
# Left panel - Connections
left_frame = ttk.Frame(main_frame)
left_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 10))
left_frame.rowconfigure(1, weight=1)
left_frame.rowconfigure(1, weight=1) # Only saved connections now
left_frame.columnconfigure(0, weight=1)
# Title with modern styling
title_label = ttk.Label(header_frame, text="🖥️ RDP Client Professional",
style='Title.TLabel', font=('Segoe UI', 18, 'bold'))
title_label.grid(row=0, column=0, sticky=tk.W)
# Saved Connections (now the main/only connections list)
saved_label = ttk.Label(left_frame, text="Saved Connections", font=('Arial', 10, 'bold'))
saved_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 5))
# Help button in header
help_btn = ttk.Button(header_frame, text="❓ Help (F1)",
command=self._show_help, style='Modern.TButton')
help_btn.grid(row=0, column=2, sticky=tk.E)
# Saved connections frame with listbox and scrollbar
saved_frame = ttk.Frame(left_frame)
saved_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
saved_frame.rowconfigure(0, weight=1)
saved_frame.columnconfigure(0, weight=1)
# Left panel - Connections (modern card style)
left_card = ttk.Frame(main_frame, style='Card.TFrame', padding="15")
left_card.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 15))
left_card.rowconfigure(1, weight=1)
left_card.columnconfigure(0, weight=1)
self.connections_listbox = tk.Listbox(saved_frame, font=('Arial', 9), width=30)
scrollbar = ttk.Scrollbar(saved_frame, orient="vertical", command=self.connections_listbox.yview)
# Connections header with count
connections_header = ttk.Frame(left_card, style='Modern.TFrame')
connections_header.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 15))
connections_header.columnconfigure(0, weight=1)
self.connections_title = ttk.Label(connections_header, text="📁 Saved Connections",
style='Title.TLabel')
self.connections_title.grid(row=0, column=0, sticky=tk.W)
# Modern connections listbox with better styling
listbox_frame = ttk.Frame(left_card, style='Modern.TFrame')
listbox_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
listbox_frame.rowconfigure(0, weight=1)
listbox_frame.columnconfigure(0, weight=1)
# Replace old listbox with modern styling
self.connections_listbox = tk.Listbox(
listbox_frame,
font=('Segoe UI', 10),
bg=self.colors['white'],
fg=self.colors['dark'],
selectbackground=self.colors['primary'],
selectforeground=self.colors['white'],
borderwidth=0,
highlightthickness=1,
highlightcolor=self.colors['primary'],
relief='flat',
activestyle='none'
)
scrollbar = ttk.Scrollbar(listbox_frame, orient="vertical", command=self.connections_listbox.yview)
self.connections_listbox.configure(yscrollcommand=scrollbar.set)
self.connections_listbox.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
self.connections_listbox.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 2))
scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
# Connection buttons
conn_buttons_frame = ttk.Frame(left_frame)
conn_buttons_frame.grid(row=2, column=0, pady=(10, 0), sticky=(tk.W, tk.E))
# Modern action buttons with icons
buttons_frame = ttk.Frame(left_card, style='Modern.TFrame')
buttons_frame.grid(row=2, column=0, pady=(15, 0), sticky=(tk.W, tk.E))
buttons_frame.columnconfigure(0, weight=1)
buttons_frame.columnconfigure(1, weight=1)
buttons_frame.columnconfigure(2, weight=1)
ttk.Button(conn_buttons_frame, text="Connect",
command=self._connect_selected).pack(side=tk.LEFT, padx=(0, 5))
ttk.Button(conn_buttons_frame, text="Edit",
command=self._edit_selected).pack(side=tk.LEFT, padx=(0, 5))
ttk.Button(conn_buttons_frame, text="Delete",
command=self._delete_selected).pack(side=tk.LEFT)
# Primary action buttons
ttk.Button(buttons_frame, text="🔗 Connect",
command=self._connect_selected, style='Success.TButton').grid(
row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5))
# Right panel - Actions and Details
right_frame = ttk.Frame(main_frame)
right_frame.grid(row=1, column=1, sticky=(tk.W, tk.E, tk.N, tk.S))
right_frame.rowconfigure(1, weight=1)
right_frame.columnconfigure(0, weight=1)
ttk.Button(buttons_frame, text="✏️ Edit",
command=self._edit_selected, style='Modern.TButton').grid(
row=0, column=1, sticky=(tk.W, tk.E), padx=2.5)
# Actions frame
actions_frame = ttk.LabelFrame(right_frame, text="Actions", padding="10")
actions_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
ttk.Button(buttons_frame, text="🗑️ Delete",
command=self._delete_selected, style='Danger.TButton').grid(
row=0, column=2, sticky=(tk.W, tk.E), padx=(5, 0))
ttk.Button(actions_frame, text="New Connection",
command=self._new_connection, width=20).pack(pady=2)
ttk.Button(actions_frame, text="Test Connection",
command=self._test_selected_connection, width=20).pack(pady=2)
ttk.Button(actions_frame, text="Import Connections",
command=self._import_connections, width=20).pack(pady=2)
ttk.Button(actions_frame, text="Export Connections",
command=self._export_connections, width=20).pack(pady=2)
ttk.Button(actions_frame, text="Clear All Credentials",
command=self._clear_credentials, width=20).pack(pady=2)
# Right panel - Actions and Details (modern card style)
right_card = ttk.Frame(main_frame, style='Card.TFrame', padding="15")
right_card.grid(row=1, column=1, sticky=(tk.W, tk.E, tk.N, tk.S))
right_card.rowconfigure(1, weight=1)
right_card.columnconfigure(0, weight=1)
# Details frame
details_frame = ttk.LabelFrame(right_frame, text="Connection Details", padding="10")
details_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
details_frame.columnconfigure(1, weight=1)
# Actions section with modern styling
actions_header = ttk.Label(right_card, text="⚡ Quick Actions", style='Title.TLabel')
actions_header.grid(row=0, column=0, sticky=tk.W, pady=(0, 15))
# Details labels
actions_frame = ttk.Frame(right_card, style='Modern.TFrame')
actions_frame.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=(0, 15))
actions_frame.columnconfigure(0, weight=1)
actions_frame.columnconfigure(1, weight=1)
ttk.Button(actions_frame, text=" New Connection",
command=self._new_connection, style='Modern.TButton').grid(
row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5), pady=3)
ttk.Button(actions_frame, text="🧪 Test Connection",
command=self._test_selected_connection, style='Modern.TButton').grid(
row=0, column=1, sticky=(tk.W, tk.E), padx=(5, 0), pady=3)
ttk.Button(actions_frame, text="📥 Import",
command=self._import_connections, style='Modern.TButton').grid(
row=1, column=0, sticky=(tk.W, tk.E), padx=(0, 5), pady=3)
ttk.Button(actions_frame, text="📤 Export",
command=self._export_connections, style='Modern.TButton').grid(
row=1, column=1, sticky=(tk.W, tk.E), padx=(5, 0), pady=3)
ttk.Button(actions_frame, text="🔐 Clear Credentials",
command=self._clear_credentials, style='Danger.TButton').grid(
row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=3)
# Details section with modern card styling
details_label = ttk.Label(right_card, text="📋 Connection Details", style='Title.TLabel')
details_label.grid(row=1, column=0, sticky=tk.W, pady=(20, 15))
details_card = ttk.Frame(right_card, style='Card.TFrame', padding="10")
details_card.grid(row=2, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
details_card.columnconfigure(1, weight=1)
# Modern details labels with better styling
self.details_labels = {}
details_fields = [
("Server:", "server"),
("Username:", "username"),
("Domain:", "domain"),
("Resolution:", "resolution"),
("Color Depth:", "color_depth"),
("Multi-Monitor:", "multimon"),
("Sound:", "sound"),
("Clipboard:", "clipboard"),
("Drive Sharing:", "drives"),
("Created:", "created")
("🖥️ Server:", "server"),
("👤 Username:", "username"),
("🏢 Domain:", "domain"),
("📺 Resolution:", "resolution"),
("🎨 Color Depth:", "color_depth"),
("🖼️ Multi-Monitor:", "multimon"),
("🔊 Sound:", "sound"),
("📋 Clipboard:", "clipboard"),
("💾 Drive Sharing:", "drives"),
("📅 Created:", "created")
]
for i, (label, field) in enumerate(details_fields):
ttk.Label(details_frame, text=label, font=('Arial', 9, 'bold')).grid(
row=i, column=0, sticky=tk.W, pady=2)
value_label = ttk.Label(details_frame, text="", font=('Arial', 9))
value_label.grid(row=i, column=1, sticky=tk.W, padx=(10, 0), pady=2)
label_widget = ttk.Label(details_card, text=label, style='Modern.TLabel',
font=('Segoe UI', 9, 'bold'))
label_widget.grid(row=i, column=0, sticky=tk.W, pady=4, padx=(0, 10))
value_label = ttk.Label(details_card, text="", style='Modern.TLabel',
font=('Segoe UI', 9))
value_label.grid(row=i, column=1, sticky=tk.W, pady=4)
self.details_labels[field] = value_label
# Bind listbox selection
@@ -452,19 +598,19 @@ class RDPClient:
# Keyboard shortcuts
self._setup_keyboard_shortcuts()
# Bottom frame - Status
status_frame = ttk.Frame(main_frame)
status_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(10, 0))
# Modern status bar
status_frame = ttk.Frame(main_frame, style='Modern.TFrame')
status_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(20, 0))
status_frame.columnconfigure(0, weight=1)
self.status_var = tk.StringVar(value="Ready")
self.status_var = tk.StringVar(value="Ready")
status_label = ttk.Label(status_frame, textvariable=self.status_var,
font=('Arial', 9), foreground='gray')
style='Modern.TLabel', font=('Segoe UI', 9))
status_label.grid(row=0, column=0, sticky=tk.W)
# Exit button
ttk.Button(status_frame, text="Exit",
command=self.root.quit).grid(row=0, column=1, sticky=tk.E)
# Modern exit button
ttk.Button(status_frame, text="Exit",
command=self.root.quit, style='Danger.TButton').grid(row=0, column=1, sticky=tk.E)
def _setup_keyboard_shortcuts(self):
"""Setup keyboard shortcuts for the application"""
@@ -497,13 +643,11 @@ class RDPClient:
def _add_keyboard_shortcuts_info(self):
"""Add keyboard shortcuts information to the status bar or help"""
# You could create a help dialog or status tooltip here
# For now, we'll add it to the window title when focused
def show_shortcuts_hint(event):
self.status_var.set("Shortcuts: Ctrl+N=New, Enter=Connect, Del=Delete, F2=Edit, Ctrl+T=Test, F5=Refresh, Ctrl+Q=Quit")
self.status_var.set("⌨️ Shortcuts: Ctrl+N=New, Enter=Connect, Del=Delete, F2=Edit, Ctrl+T=Test, F5=Refresh, Ctrl+Q=Quit")
def clear_shortcuts_hint(event):
self.status_var.set("Ready")
self.status_var.set("Ready")
# Show shortcuts hint when connections listbox gets focus
self.connections_listbox.bind('<FocusIn>', show_shortcuts_hint)
@@ -555,10 +699,14 @@ Multi-Monitor Support:
for name in sorted(self.connections.keys(), key=str.lower):
self.connections_listbox.insert(tk.END, name)
# Update connections count in title
count = len(self.connections)
self.connections_title.config(text=f"📁 Saved Connections ({count})")
# Clear details if no connections
if not self.connections:
for label in self.details_labels.values():
label.config(text="")
label.config(text="")
def _update_details(self, conn):
"""Update the details panel with connection info"""
@@ -612,7 +760,7 @@ Multi-Monitor Support:
self._add_to_history(name)
self._refresh_connections_list()
self.status_var.set(f"Connection '{name}' saved successfully")
self.status_var.set(f"💾 Connection '{name}' saved successfully")
def _edit_selected(self):
"""Edit selected connection"""
@@ -676,7 +824,7 @@ Multi-Monitor Support:
self._add_to_history(new_name)
self._refresh_connections_list()
self.status_var.set(f"Connection '{new_name}' updated successfully")
self.status_var.set(f"✏️ Connection '{new_name}' updated successfully")
def _delete_selected(self):
"""Delete selected connection"""
@@ -707,7 +855,7 @@ Multi-Monitor Support:
for label in self.details_labels.values():
label.config(text="")
self.status_var.set(f"Connection '{name}' deleted")
self.status_var.set(f"🗑️ Connection '{name}' deleted")
def _connect_selected(self, event=None):
"""Connect to selected connection"""
@@ -751,7 +899,7 @@ Multi-Monitor Support:
username = conn['username']
self.logger.info(f"Attempting RDP connection to {server} as {username}")
self.status_var.set(f"Connecting to {server}...")
self.status_var.set(f"🔗 Connecting to {server}...")
# Test connectivity first
if not self._test_server_connectivity(server):
@@ -1050,7 +1198,7 @@ Multi-Monitor Support:
self._save_credentials()
self._refresh_connections_list()
self.status_var.set(f"Successfully imported {imported_count} connections")
self.status_var.set(f"📥 Successfully imported {imported_count} connections")
messagebox.showinfo("Import Complete", f"Successfully imported {imported_count} connections.")
except FileNotFoundError:
@@ -1097,7 +1245,7 @@ Multi-Monitor Support:
with open(file_path, 'w') as f:
json.dump(export_data, f, indent=2)
self.status_var.set(f"Connections exported to {os.path.basename(file_path)}")
self.status_var.set(f"📤 Connections exported to {os.path.basename(file_path)}")
messagebox.showinfo("Export Complete", f"Successfully exported {len(self.connections)} connections to:\n{file_path}")
except Exception as e:
@@ -1108,7 +1256,7 @@ Multi-Monitor Support:
if messagebox.askyesno("Confirm", "Clear all saved passwords?"):
self.credentials.clear()
self._save_credentials()
self.status_var.set("All credentials cleared")
self.status_var.set("🔐 All credentials cleared")
self.logger.info("All credentials cleared by user")
def _test_selected_connection(self):