windows fixes

This commit is contained in:
2025-11-24 07:12:47 +01:00
parent 4fdceb46ff
commit 3cd75d97f6
2 changed files with 103 additions and 75 deletions

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

178
main.py
View File

@@ -518,13 +518,15 @@ class IRCPanel(wx.Panel):
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
# Use a better font for chat # Use a better font for chat with white theme
self.text_ctrl = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2 | wx.TE_AUTO_URL) self.text_ctrl = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2 | wx.TE_AUTO_URL)
self.text_ctrl.SetBackgroundColour(wx.Colour(30, 30, 30))
self.text_ctrl.SetForegroundColour(wx.Colour(220, 220, 220))
# Load Fira Code font # White theme colors
self.font = self.load_fira_code_font() self.text_ctrl.SetBackgroundColour(wx.Colour(255, 255, 255)) # White background
self.text_ctrl.SetForegroundColour(wx.Colour(0, 0, 0)) # Black text
# Load appropriate font
self.font = self.load_system_font()
self.text_ctrl.SetFont(self.font) self.text_ctrl.SetFont(self.font)
sizer.Add(self.text_ctrl, 1, wx.EXPAND | wx.ALL, 0) sizer.Add(self.text_ctrl, 1, wx.EXPAND | wx.ALL, 0)
@@ -560,39 +562,46 @@ class IRCPanel(wx.Panel):
self.SetAcceleratorTable(accel_tbl) self.SetAcceleratorTable(accel_tbl)
self.Bind(wx.EVT_MENU, self.on_search, id=wx.ID_FIND) self.Bind(wx.EVT_MENU, self.on_search, id=wx.ID_FIND)
def load_fira_code_font(self): def load_system_font(self):
"""Load Fira Code font from resources""" """Load appropriate system font with high DPI support"""
try: try:
# Try to use Fira Code if available # Get system DPI scale factor
font_path = get_resource_path("FiraCode-Regular.ttf") dc = wx.ClientDC(self)
dpi_scale = dc.GetPPI().GetWidth() / 96.0 # 96 is standard DPI
if os.path.exists(font_path): # Calculate base font size based on DPI
# On wxPython 4.1+, we can try to add the font to the font manager base_size = 10
try: if dpi_scale > 1.5:
font_collection = wx.private.FontCollection() font_size = int(base_size * 1.5) # 150% scaling
if font_collection.AddFont(font_path): elif dpi_scale > 1.25:
font = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, font_size = int(base_size * 1.25) # 125% scaling
False, "Fira Code")
if font.IsOk():
logger.info("Successfully loaded Fira Code font")
return font
except Exception:
pass
# Fallback: try to create font by name
font = wx.Font(wx.FontInfo(10).Family(wx.FONTFAMILY_TELETYPE).FaceName("Fira Code"))
if font.IsOk():
logger.info("Using Fira Code font via FaceName")
return font
else: else:
logger.warning("FiraCode-Regular.ttf not found in resources") font_size = base_size
# Try system fonts in order of preference
font_families = [
(wx.FONTFAMILY_TELETYPE, "Consolas"),
(wx.FONTFAMILY_TELETYPE, "Courier New"),
(wx.FONTFAMILY_TELETYPE, "Monaco"),
(wx.FONTFAMILY_TELETYPE, "DejaVu Sans Mono"),
(wx.FONTFAMILY_TELETYPE, "Liberation Mono"),
]
for family, face_name in font_families:
font = wx.Font(font_size, family, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, face_name)
if font.IsOk():
logger.info(f"Using font: {face_name} at {font_size}pt")
return font
# Fallback to default monospace
font = wx.Font(font_size, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
logger.info("Using system monospace font as fallback")
return font
except Exception as e: except Exception as e:
logger.error(f"Error loading Fira Code font: {e}") logger.error(f"Error loading system font: {e}")
# Ultimate fallback
# Fall back to system monospace font return wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
font = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
logger.info("Using system monospace font as fallback")
return font
def set_target(self, target): def set_target(self, target):
self.target = target self.target = target
@@ -635,7 +644,7 @@ class IRCPanel(wx.Panel):
if message_color: if message_color:
attr.SetTextColour(message_color) attr.SetTextColour(message_color)
else: else:
attr.SetTextColour(wx.Colour(220, 220, 220)) attr.SetTextColour(wx.Colour(0, 0, 0)) # Black text for white theme
attr.SetFont(self.font) attr.SetFont(self.font)
self.text_ctrl.SetDefaultStyle(attr) self.text_ctrl.SetDefaultStyle(attr)
@@ -658,10 +667,10 @@ class IRCPanel(wx.Panel):
try: try:
if is_action: if is_action:
message = f"{timestamp}* {username} {content}" message = f"{timestamp}* {username} {content}"
self.add_message(message, f"* {username}", username_color, wx.Colour(255, 150, 255), italic=True) self.add_message(message, f"* {username}", username_color, wx.Colour(128, 0, 128), italic=True) # Dark purple for actions
else: else:
message = f"{timestamp}<{username}> {content}" message = f"{timestamp}<{username}> {content}"
self.add_message(message, f"<{username}>", username_color, wx.Colour(220, 220, 220)) self.add_message(message, f"<{username}>", username_color, wx.Colour(0, 0, 0)) # Black text
except Exception as e: except Exception as e:
logger.error(f"Error adding formatted message: {e}") logger.error(f"Error adding formatted message: {e}")
@@ -669,7 +678,7 @@ class IRCPanel(wx.Panel):
"""Add system message without username coloring""" """Add system message without username coloring"""
try: try:
if color is None: if color is None:
color = wx.Colour(180, 180, 255) color = wx.Colour(0, 0, 128) # Dark blue for system messages
self.add_message(message, None, None, color, bold, False, False) self.add_message(message, None, None, color, bold, False, False)
except Exception as e: except Exception as e:
logger.error(f"Error adding system message: {e}") logger.error(f"Error adding system message: {e}")
@@ -868,6 +877,9 @@ class IRCFrame(wx.Frame):
def __init__(self): def __init__(self):
super().__init__(None, title="wxIRC", size=(1200, 700)) super().__init__(None, title="wxIRC", size=(1200, 700))
# Apply white theme
self.apply_white_theme()
# Show privacy notice first # Show privacy notice first
self.show_privacy_notice() self.show_privacy_notice()
@@ -891,21 +903,21 @@ class IRCFrame(wx.Frame):
self.away = False self.away = False
self.timestamps = True self.timestamps = True
# User color mapping # User color mapping - darker colors for white theme
self.user_colors = {} self.user_colors = {}
self.available_colors = [ self.available_colors = [
wx.Colour(255, 150, 150), # Light red wx.Colour(178, 34, 34), # Firebrick red
wx.Colour(150, 255, 150), # Light green wx.Colour(0, 100, 0), # Dark green
wx.Colour(150, 200, 255), # Light blue wx.Colour(0, 0, 139), # Dark blue
wx.Colour(255, 255, 150), # Light yellow wx.Colour(139, 69, 19), # Saddle brown
wx.Colour(255, 150, 255), # Light magenta wx.Colour(139, 0, 139), # Dark magenta
wx.Colour(150, 255, 255), # Light cyan wx.Colour(0, 139, 139), # Dark cyan
wx.Colour(255, 200, 150), # Light orange wx.Colour(210, 105, 30), # Chocolate
wx.Colour(200, 150, 255), # Light purple wx.Colour(75, 0, 130), # Indigo
wx.Colour(255, 200, 200), # Pink wx.Colour(178, 34, 34), # Firebrick
wx.Colour(200, 255, 200), # Mint wx.Colour(0, 128, 128), # Teal
wx.Colour(200, 200, 255), # Lavender wx.Colour(72, 61, 139), # Dark slate blue
wx.Colour(255, 255, 200), # Cream wx.Colour(139, 0, 0), # Dark red
] ]
self.color_index = 0 self.color_index = 0
@@ -939,6 +951,19 @@ class IRCFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.on_find_previous, id=1002) self.Bind(wx.EVT_MENU, self.on_find_previous, id=1002)
self.Bind(wx.EVT_MENU, self.on_quick_escape, id=1003) self.Bind(wx.EVT_MENU, self.on_quick_escape, id=1003)
def apply_white_theme(self):
"""Apply white theme to the application"""
try:
# Set system colors for white theme
self.SetBackgroundColour(wx.Colour(255, 255, 255))
self.SetForegroundColour(wx.Colour(0, 0, 0))
# Set system settings for light theme
sys_settings = wx.SystemSettings()
except Exception as e:
logger.error(f"Error applying white theme: {e}")
def show_privacy_notice(self): def show_privacy_notice(self):
"""Show privacy notice dialog at startup""" """Show privacy notice dialog at startup"""
dlg = PrivacyNoticeDialog(self) dlg = PrivacyNoticeDialog(self)
@@ -1002,13 +1027,14 @@ class IRCFrame(wx.Frame):
return None return None
def setup_ui(self): def setup_ui(self):
"""Setup UI components""" """Setup UI components with white theme"""
panel = wx.Panel(self) panel = wx.Panel(self)
panel.SetBackgroundColour(wx.Colour(255, 255, 255)) # White background
main_sizer = wx.BoxSizer(wx.HORIZONTAL) main_sizer = wx.BoxSizer(wx.HORIZONTAL)
# Left sidebar # Left sidebar - light gray for contrast
left_panel = wx.Panel(panel) left_panel = wx.Panel(panel)
left_panel.SetBackgroundColour(wx.Colour(45, 45, 45)) left_panel.SetBackgroundColour(wx.Colour(240, 240, 240)) # Light gray
left_sizer = wx.BoxSizer(wx.VERTICAL) left_sizer = wx.BoxSizer(wx.VERTICAL)
conn_box = wx.StaticBox(left_panel, label="Connection") conn_box = wx.StaticBox(left_panel, label="Connection")
@@ -1068,6 +1094,7 @@ class IRCFrame(wx.Frame):
# Center - Notebook # Center - Notebook
self.notebook = wx.Notebook(panel) self.notebook = wx.Notebook(panel)
self.notebook.SetBackgroundColour(wx.Colour(255, 255, 255))
# Server panel # Server panel
server_panel = IRCPanel(self.notebook, self) server_panel = IRCPanel(self.notebook, self)
@@ -1075,9 +1102,9 @@ class IRCFrame(wx.Frame):
self.notebook.AddPage(server_panel, "Server") self.notebook.AddPage(server_panel, "Server")
self.channels["SERVER"] = server_panel self.channels["SERVER"] = server_panel
# Right sidebar - Users # Right sidebar - Users - light gray for contrast
right_panel = wx.Panel(panel) right_panel = wx.Panel(panel)
right_panel.SetBackgroundColour(wx.Colour(45, 45, 45)) right_panel.SetBackgroundColour(wx.Colour(240, 240, 240)) # Light gray
right_sizer = wx.BoxSizer(wx.VERTICAL) right_sizer = wx.BoxSizer(wx.VERTICAL)
users_box = wx.StaticBox(right_panel, label="Users") users_box = wx.StaticBox(right_panel, label="Users")
@@ -1232,7 +1259,7 @@ class IRCFrame(wx.Frame):
if hasattr(event, 'arguments') and event.arguments: if hasattr(event, 'arguments') and event.arguments:
event_info += f" - {' '.join(event.arguments)}" event_info += f" - {' '.join(event.arguments)}"
self.log_server(event_info, wx.Colour(180, 180, 255), italic=True) self.log_server(event_info, wx.Colour(0, 0, 128), italic=True) # Dark blue for raw events
except Exception as e: except Exception as e:
logger.error(f"Error in all_events handler: {e}") logger.error(f"Error in all_events handler: {e}")
@@ -1259,19 +1286,19 @@ class IRCFrame(wx.Frame):
try: try:
self.port = int(self.port_ctrl.GetValue()) self.port = int(self.port_ctrl.GetValue())
except ValueError: except ValueError:
self.safe_ui_update(self.log_server, "Invalid port number", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, "Invalid port number", wx.Colour(255, 0, 0))
self.is_connecting = False self.is_connecting = False
return return
self.nick = self.nick_ctrl.GetValue() self.nick = self.nick_ctrl.GetValue()
if not self.server or not self.nick: if not self.server or not self.nick:
self.safe_ui_update(self.log_server, "Server and nick are required", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, "Server and nick are required", wx.Colour(255, 0, 0))
self.is_connecting = False self.is_connecting = False
return return
self.safe_ui_update(self.connect_btn.Enable, False) self.safe_ui_update(self.connect_btn.Enable, False)
self.safe_ui_update(self.log_server, f"Connecting to {self.server}:{self.port} as {self.nick}...", wx.Colour(150, 150, 255)) self.safe_ui_update(self.log_server, f"Connecting to {self.server}:{self.port} as {self.nick}...", wx.Colour(0, 0, 128))
def connect_thread(): def connect_thread():
try: try:
@@ -1320,7 +1347,7 @@ class IRCFrame(wx.Frame):
self.reactor.process_forever() self.reactor.process_forever()
except Exception as e: except Exception as e:
logger.error(f"Reactor loop error: {e}") logger.error(f"Reactor loop error: {e}")
self.safe_ui_update(self.log_server, f"Connection error: {e}", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, f"Connection error: {e}", wx.Colour(255, 0, 0))
self.safe_ui_update(self.on_disconnect_cleanup) self.safe_ui_update(self.on_disconnect_cleanup)
def on_connect_success(self): def on_connect_success(self):
@@ -1334,7 +1361,7 @@ class IRCFrame(wx.Frame):
def on_connect_failed(self, error_msg): def on_connect_failed(self, error_msg):
"""Handle connection failure""" """Handle connection failure"""
self.is_connecting = False self.is_connecting = False
self.log_server(error_msg, wx.Colour(255, 100, 100)) self.log_server(error_msg, wx.Colour(255, 0, 0))
self.connect_btn.Enable(True) self.connect_btn.Enable(True)
self.SetStatusText("Connection failed") self.SetStatusText("Connection failed")
logger.error(f"Connection failed: {error_msg}") logger.error(f"Connection failed: {error_msg}")
@@ -1376,7 +1403,7 @@ class IRCFrame(wx.Frame):
self.safe_ui_update(self.connect_btn.SetLabel, "Connect") self.safe_ui_update(self.connect_btn.SetLabel, "Connect")
self.safe_ui_update(self.connect_btn.Enable, True) self.safe_ui_update(self.connect_btn.Enable, True)
self.safe_ui_update(self.SetStatusText, "Disconnected") self.safe_ui_update(self.SetStatusText, "Disconnected")
self.safe_ui_update(self.log_server, "Disconnected from server", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, "Disconnected from server", wx.Colour(255, 0, 0))
def on_join_channel(self, event): def on_join_channel(self, event):
try: try:
@@ -1388,7 +1415,7 @@ class IRCFrame(wx.Frame):
self.channel_input.Clear() self.channel_input.Clear()
except Exception as e: except Exception as e:
logger.error(f"Error joining channel: {e}") logger.error(f"Error joining channel: {e}")
self.safe_ui_update(self.log_server, f"Error joining channel: {e}", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, f"Error joining channel: {e}", wx.Colour(255, 0, 0))
def on_channel_select(self, event): def on_channel_select(self, event):
try: try:
@@ -1505,7 +1532,7 @@ class IRCFrame(wx.Frame):
self.channels[target].add_formatted_message(timestamp, self.nick, message, user_color) self.channels[target].add_formatted_message(timestamp, self.nick, message, user_color)
except Exception as e: except Exception as e:
logger.error(f"Error sending message: {e}") logger.error(f"Error sending message: {e}")
self.safe_ui_update(self.log_server, f"Error sending message: {e}", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, f"Error sending message: {e}", wx.Colour(255, 0, 0))
def handle_command(self, target, message): def handle_command(self, target, message):
try: try:
@@ -1528,7 +1555,7 @@ Available commands:
/quit [message] - Disconnect from server /quit [message] - Disconnect from server
/help - Show this help /help - Show this help
""" """
self.log_server(help_text, wx.Colour(200, 255, 200)) self.log_server(help_text, wx.Colour(0, 100, 0)) # Dark green for help
elif cmd == "me": elif cmd == "me":
if self.is_connected(): if self.is_connected():
self.connection.action(target, args) self.connection.action(target, args)
@@ -1568,10 +1595,10 @@ Available commands:
self.away = bool(args) self.away = bool(args)
self.safe_ui_update(self.away_item.Check, self.away) self.safe_ui_update(self.away_item.Check, self.away)
else: else:
self.safe_ui_update(self.log_server, f"Unknown command: {cmd}. Use /help for available commands.", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, f"Unknown command: {cmd}. Use /help for available commands.", wx.Colour(255, 0, 0))
except Exception as e: except Exception as e:
logger.error(f"Error handling command: {e}") logger.error(f"Error handling command: {e}")
self.safe_ui_update(self.log_server, f"Error executing command: {e}", wx.Colour(255, 100, 100)) self.safe_ui_update(self.log_server, f"Error executing command: {e}", wx.Colour(255, 0, 0))
def part_channel(self, channel): def part_channel(self, channel):
try: try:
@@ -1767,13 +1794,14 @@ COMMANDS (type /help in chat for full list):
/nick newname - Change nickname /nick newname - Change nickname
/away [message] - Set away status /away [message] - Set away status
""" """
self.log_server(help_text, wx.Colour(200, 255, 200), bold=True) self.log_server(help_text, wx.Colour(0, 100, 0), bold=True) # Dark green for help
# IRC Event Handlers - All use thread-safe UI updates # IRC Event Handlers - All use thread-safe UI updates
def on_welcome(self, connection, event): def on_welcome(self, connection, event):
try: try:
self.log_server("Connected to server!", wx.Colour(100, 255, 100), bold=True) self.log_server("Connected to server!", wx.Colour(0, 128, 0), bold=True) # Dark green
self.log_server(f"Welcome message: {' '.join(event.arguments)}", wx.Colour(150, 255, 150)) self.log_server(f"Welcome message: {' '.join(event.arguments)}", wx.Colour(0, 100, 0))
# Auto-join channels # Auto-join channels
for channel in self.auto_join_channels: for channel in self.auto_join_channels:
@@ -1792,7 +1820,7 @@ COMMANDS (type /help in chat for full list):
if nick == self.nick: if nick == self.nick:
self.safe_ui_update(self.add_channel, channel) self.safe_ui_update(self.add_channel, channel)
self.log_server(f"Joined channel {channel}", wx.Colour(100, 255, 100)) self.log_server(f"Joined channel {channel}", wx.Colour(0, 128, 0)) # Dark green
self.log_channel_message(channel, nick, f"{nick} joined", is_system=True) self.log_channel_message(channel, nick, f"{nick} joined", is_system=True)
@@ -1900,7 +1928,7 @@ COMMANDS (type /help in chat for full list):
if old_nick == self.nick: if old_nick == self.nick:
self.nick = new_nick self.nick = new_nick
self.log_server(f"You are now known as {new_nick}", wx.Colour(150, 200, 255), bold=True) self.log_server(f"You are now known as {new_nick}", wx.Colour(0, 0, 128), bold=True) # Dark blue
for channel in self.channel_users: for channel in self.channel_users:
if old_nick in self.channel_users[channel]: if old_nick in self.channel_users[channel]:
@@ -1928,13 +1956,13 @@ COMMANDS (type /help in chat for full list):
nick = event.source.nick if hasattr(event.source, 'nick') else str(event.source) nick = event.source.nick if hasattr(event.source, 'nick') else str(event.source)
message = event.arguments[0] message = event.arguments[0]
self.log_server(f"-{nick}- {message}", wx.Colour(255, 150, 255), italic=True) self.log_server(f"-{nick}- {message}", wx.Colour(128, 0, 128), italic=True) # Dark purple for notices
except Exception as e: except Exception as e:
logger.error(f"Error in notice handler: {e}") logger.error(f"Error in notice handler: {e}")
def on_disconnect(self, connection, event): def on_disconnect(self, connection, event):
try: try:
self.log_server("Disconnected from server", wx.Colour(255, 100, 100), bold=True) self.log_server("Disconnected from server", wx.Colour(255, 0, 0), bold=True) # Red for disconnect
self.safe_ui_update(self.on_disconnect_cleanup) self.safe_ui_update(self.on_disconnect_cleanup)
except Exception as e: except Exception as e:
logger.error(f"Error in disconnect handler: {e}") logger.error(f"Error in disconnect handler: {e}")