From 61a2458f833741c0b999f3e6ed4ba1c23f63a33b Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Wed, 3 Dec 2025 13:56:30 +0100 Subject: [PATCH] update to be better ; still have to fix the scrolling on windows --- src/IRCPanel.py | 153 +++++++++++++++++++----------------------------- 1 file changed, 60 insertions(+), 93 deletions(-) diff --git a/src/IRCPanel.py b/src/IRCPanel.py index 11dc1a0..3c7d53f 100644 --- a/src/IRCPanel.py +++ b/src/IRCPanel.py @@ -1,4 +1,6 @@ -import wx , wx.adv +import wx +import wx.adv +import random import threading import logging from SearchDialog import SearchDialog @@ -19,8 +21,7 @@ class IRCPanel(wx.Panel): sizer = wx.BoxSizer(wx.VERTICAL) - # 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_READONLY | wx.TE_MULTILINE | wx.TE_AUTO_URL) if self.theme: self.text_ctrl.SetBackgroundColour(self.theme["content_bg"]) @@ -39,9 +40,44 @@ class IRCPanel(wx.Panel): self.input_ctrl.Bind(wx.EVT_TEXT_ENTER, self.on_send) self.input_ctrl.Bind(wx.EVT_KEY_DOWN, self.on_key_down) - # Kaomoji picker button - inserts plain ASCII kaomojis into the input box - self.kaomoji_btn = wx.Button(self, label="Emotes") - self.kaomoji_btn.SetToolTip("Emotes :3") + self.kaomoji_groups = { + "Happy": [ + ":-)", ":)", ":-D", ":D", "^_^", "^o^", "(*^_^*)", "( ^_^)/", "(:3)", "=)", "=]", "^.^", + "UwU", "OwO", "^w^", "^u^", "x3", ":3", ":3c", "nya~", "n_n", "(>ω<)", ":33", "^3^" + ], + "Sad": [ + ":-(", ":'(", "T_T", ";_;", ">_<", "(-_-)", "(_ _)", + ], + "Angry": [ + ">:(", ">:-(", ">:-O", ">.<", "(-_-)#" + ], + "Love": [ + "<3", "(*^3^)", "(^^)v", "(^_^)", "*^_^*" + ], + "Surprised / Misc": [ + ":-O", ":O", ":-0", "O_O", "o_O", "O_o" + ], + "Sleepy | Bored": [ + "-_-", "(-.-) zzz", "(~_~)", "zzz" + ], + "Gay": [ + r"¯\_(._.)_/¯", "(¬_¬)", "(*_*)", "(>_>)", "(<_<)", "(o_O)", "(O_o)", "('_')", + "(//▽//)", "(*^///^*)", ">///<", "^_^;", "^///^;", "owo", "uwu", "rawr", ":33p" + ], + "Blush": [ + "^///^", "(//▽//)", "(*^///^*)", ">///<", "^_^;", "^///^;", + "(*^▽^*)", "(*´▽`*)" + ], + "Others": [ + "UwU~", "OwO~", ":33", "x3", ":3~", ":3c", "rawr x3", "xD", ";-)", ";)", ":-P", ":P", ":-|", ":|" + ] + } + + emote_random = random.choice(list(self.kaomoji_groups.values())) # Get a random value ( returns a list and looks like a value of the dict in the code ; ) + emote_random = str(emote_random).strip('[]').split(', ')[random.randint(0, len(emote_random)-1)].strip("'") # Do some formatting for the strings, since they are stored in lists + + self.kaomoji_btn = wx.Button(self, label=f"{emote_random}") + self.kaomoji_btn.SetToolTip(f"Kaomojis {emote_random} ") self.kaomoji_btn.Bind(wx.EVT_BUTTON, self.on_pick_kaomoji) send_btn = wx.Button(self, label="Send") @@ -116,7 +152,7 @@ class IRCPanel(wx.Panel): self.target = target def add_message(self, message, username=None, username_color=None, message_color=None, bold=False, italic=False, underline=False): - """Thread-safe message addition with username coloring""" + """Thread-safe message addition - plain text only for pixel-perfect scrolling""" try: # Use CallAfter for thread safety if wx.IsMainThread(): @@ -127,44 +163,13 @@ class IRCPanel(wx.Panel): logger.error(f"Error in add_message: {e}") def _add_message_safe(self, message, username=None, username_color=None, message_color=None, bold=False, italic=False, underline=False): - """Actually add message - must be called from main thread""" + """Actually add message - must be called from main thread + Note: Without TE_RICH2, color/formatting is not supported, but scrolling is pixel-perfect""" try: self.messages.append(message) - # Save current position for formatting - start_pos = self.text_ctrl.GetLastPosition() - - if username and username_color: - # Add username with its color - attr = wx.TextAttr() - attr.SetTextColour(username_color) - if bold: - attr.SetFontWeight(wx.FONTWEIGHT_BOLD) - if italic: - attr.SetFontStyle(wx.FONTSTYLE_ITALIC) - if underline: - attr.SetFontUnderlined(True) - attr.SetFont(self.font) - self.text_ctrl.SetDefaultStyle(attr) - self.text_ctrl.AppendText(username) - - # Add the rest of the message with message color - attr = wx.TextAttr() - if message_color: - attr.SetTextColour(message_color) - else: - attr.SetTextColour(self.default_text_colour) - - attr.SetFont(self.font) - self.text_ctrl.SetDefaultStyle(attr) - - # Append the message (without username if we already added it) - if username and username_color: - # Find the message part after username - message_text = message[message.find(username) + len(username):] - self.text_ctrl.AppendText(message_text + "\n") - else: - self.text_ctrl.AppendText(message + "\n") + # Simple append without formatting (pixel-perfect scrolling) + self.text_ctrl.AppendText(message + "\n") # Auto-scroll to bottom self.text_ctrl.ShowPosition(self.text_ctrl.GetLastPosition()) @@ -172,23 +177,20 @@ class IRCPanel(wx.Panel): logger.error(f"Error adding message safely: {e}") def add_formatted_message(self, timestamp, username, content, username_color=None, is_action=False): - """Add a formatted message with colored username""" + """Add a formatted message (plain text only for pixel-perfect scrolling)""" try: if is_action: message = f"{timestamp}* {username} {content}" - self.add_message(message, f"* {username}", username_color, wx.Colour(128, 0, 128), italic=True) # Dark purple for actions else: message = f"{timestamp}<{username}> {content}" - self.add_message(message, f"<{username}>", username_color, self.default_text_colour) + self.add_message(message) except Exception as e: logger.error(f"Error adding formatted message: {e}") def add_system_message(self, message, color=None, bold=False): - """Add system message without username coloring""" + """Add system message (plain text only for pixel-perfect scrolling)""" try: - if color is None: - 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) except Exception as e: logger.error(f"Error adding system message: {e}") @@ -222,20 +224,16 @@ class IRCPanel(wx.Panel): return # Prepare search parameters - search_flags = 0 if not case_sensitive: - # For manual search, we'll handle case sensitivity ourselves search_text_lower = search_text.lower() full_text_lower = full_text.lower() - # Manual search implementation since wx.TextCtrl doesn't have FindText + # Manual search implementation pos = 0 while pos < len(full_text): if case_sensitive: - # Case sensitive search found_pos = full_text.find(search_text, pos) else: - # Case insensitive search found_pos = full_text_lower.find(search_text_lower, pos) if found_pos == -1: @@ -243,14 +241,13 @@ class IRCPanel(wx.Panel): # For whole word search, verify boundaries if whole_word: - # Check if it's a whole word is_word_start = (found_pos == 0 or not full_text[found_pos-1].isalnum()) is_word_end = (found_pos + len(search_text) >= len(full_text) or not full_text[found_pos + len(search_text)].isalnum()) if is_word_start and is_word_end: self.search_positions.append(found_pos) - pos = found_pos + 1 # Move forward to avoid infinite loop + pos = found_pos + 1 else: self.search_positions.append(found_pos) pos = found_pos + len(search_text) @@ -400,38 +397,7 @@ class IRCPanel(wx.Panel): Show a grouped kaomoji popup next to the button and insert the chosen one. """ try: - kaomoji_groups = { - "Happy": [ - ":-)", ":)", ":-D", ":D", "^_^", "^o^", "(*^_^*)", "( ^_^)/", "(:3)", "=)", "=]", "^.^", - "UwU", "OwO", "^w^", "^u^", "x3", ":3", ":3c", "nya~", "n_n", "(>ω<)", ":33", "^3^" - ], - "Sad": [ - ":-(", ":'(", "T_T", ";_;", ">_<", "(-_-)", "(_ _)", - ], - "Angry": [ - ">:(", ">:-(", ">:-O", ">.<", "(-_-)#" - ], - "Love": [ - "<3", "(*^3^)", "(^^)v", "(^_^)", "*^_^*" - ], - "Surprised / Misc": [ - ":-O", ":O", ":-0", "O_O", "o_O", "O_o" - ], - "Sleepy | Bored": [ - "-_-", "(-.-) zzz", "(~_~)", "zzz" - ], - "Gay": [ - r"¯\_(._.)_/¯", "(¬_¬)", "(*_*)", "(>_>)", "(<_<)", "(o_O)", "(O_o)", "('_')", - "(//▽//)", "(*^///^*)", ">///<", "^_^;", "^///^;", "owo", "uwu", "rawr", ":33p" - ], - "Blush": [ - "^///^", "(//▽//)", "(*^///^*)", ">///<", "^_^;", "^///^;", - "(*^▽^*)", "(*´▽`*)" - ], - "Others": [ - "UwU~", "OwO~", ":33", "x3", ":3~", ":3c", "rawr x3", "xD", ";-)", ";)", ":-P", ":P", ":-|", ":|" - ] - } + display_items = [] item_lookup = [] # tuple: (group, index in group) or None for separators/labels @@ -440,7 +406,7 @@ class IRCPanel(wx.Panel): def is_ascii(s): return all(ord(ch) < 128 for ch in s) - for group, choices in kaomoji_groups.items(): + for group, choices in self.kaomoji_groups.items(): group_ascii_choices = [c for c in choices if is_ascii(c)] if not group_ascii_choices: continue @@ -451,11 +417,12 @@ class IRCPanel(wx.Panel): display_items.append(f" {choice}") item_lookup.append((group, idx)) - popup = wx.PopupTransientWindow(self, wx.BORDER_SIMPLE) + popup = wx.PopupTransientWindow(self, wx.BORDER_SUNKEN) + panel = wx.Panel(popup) sizer = wx.BoxSizer(wx.VERTICAL) listbox = wx.ListBox( - panel, choices=display_items, style=wx.LB_SINGLE + panel, choices=display_items, style=wx.LB_SINGLE | wx.BORDER_SUNKEN ) sizer.Add(listbox, 1, wx.EXPAND | wx.ALL, 4) panel.SetSizerAndFit(sizer) @@ -471,7 +438,7 @@ class IRCPanel(wx.Panel): return None group, group_idx = lookup if group: - choices = [c for c in kaomoji_groups[group] if is_ascii(c)] + choices = [c for c in self.kaomoji_groups[group] if is_ascii(c)] return choices[group_idx] else: # Fallback: old style flat @@ -505,7 +472,7 @@ class IRCPanel(wx.Panel): self.input_ctrl.SetValue(new_value) self.input_ctrl.SetInsertionPoint(pos + len(insert_text)) finally: - popup.Dismiss() + popup.Destroy() # Linux did not like dismiss, so we just destroy it. it works better def on_left_click(evt): """Single left-click handler for the kaomoji menu."""