update to be better ; still have to fix the scrolling on windows

This commit is contained in:
2025-12-03 13:56:30 +01:00
parent d5a4628281
commit 61a2458f83

View File

@@ -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."""