some cute emotes

This commit is contained in:
2025-12-01 16:03:48 +01:00
parent 6bdf31cb26
commit 5456b6c5fd
2 changed files with 171 additions and 15 deletions

View File

@@ -38,12 +38,19 @@ class IRCPanel(wx.Panel):
self.input_ctrl.SetHint("Type message here …")
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_btn.Bind(wx.EVT_BUTTON, self.on_pick_kaomoji)
send_btn = wx.Button(self, label="Send")
send_btn.SetToolTip("Send message (Enter)")
send_btn.Bind(wx.EVT_BUTTON, self.on_send)
# Order: input field, kaomoji, send
input_sizer.Add(self.input_ctrl, 1, wx.EXPAND | wx.ALL, 2)
input_sizer.Add(self.kaomoji_btn, 0, wx.ALL, 2)
input_sizer.Add(send_btn, 0, wx.ALL, 2)
sizer.Add(input_sizer, 0, wx.EXPAND | wx.ALL, 0)
@@ -365,6 +372,7 @@ class IRCPanel(wx.Panel):
logger.error(f"Error in tab completion: {e}")
def on_send(self, event):
"""Send the current input to the active IRC target."""
try:
message = self.input_ctrl.GetValue().strip()
if message and self.target:
@@ -374,3 +382,134 @@ class IRCPanel(wx.Panel):
self.input_ctrl.Clear()
except Exception as e:
logger.error(f"Error sending message: {e}")
def insert_text_at_caret(self, text):
"""Insert given text at the current caret position in the input box."""
try:
current = self.input_ctrl.GetValue()
pos = self.input_ctrl.GetInsertionPoint()
new_value = current[:pos] + text + current[pos:]
self.input_ctrl.SetValue(new_value)
self.input_ctrl.SetInsertionPoint(pos + len(text))
except Exception as e:
logger.error(f"Error inserting text at caret: {e}")
def on_pick_kaomoji(self, event):
"""Show a kaomoji popup next to the button and insert the chosen one.
All entries are ASCII-only so they are safe for any IRC server.
"""
try:
choices = [
":-)", ":)", ":-D", ":D", "^_^", "^o^", "(*^_^*)", "( ^_^)", "(:3)", "=)", "=]", "^.^",
":-(", ":'(", "T_T", ";_;", ">_<", "(-_-)", "(_ _)",
">:(", ">:-(", ">:-O", ">.<", "(-_-)#",
"<3", "(*^3^)", "(^^)v", "(X_X)", "(^_^)", "*^_^*",
":-O", ":O", ":-0", "O_O", "o_O", "O_o",
"-_-", "(-.-) zzz", "(~_~)", "zzz",
r"¯\_(._.)_/¯", "(¬_¬)", "(*_*)", "(>_>)", "(<_<)",
"OwO", "UwU", ">w<", "^w^", "^u^", "rawr x3", ":3", ":3c", "x3", "nya~", "n_n", "(>ω<)", ":33", "^3^",
"^///^", "(//▽//)", "(*^///^*)", ">///<", "^_^;", "^///^;",
"(*^▽^*)", "(*´▽`*)", "UwU~", "OwO~",
":33", "x3", ":3~", ":3c", "owo", "uwu", "rawr", ":33p",
"xD", ";-)", ";)", ":-P", ":P", ":-|", ":|", "(o_O)", "(O_o)", "('_')",
]
ascii_choices = [c for c in choices if all(ord(ch) < 128 for ch in c)]
if not ascii_choices:
ascii_choices = [":)", ":D", ";)", ":P"]
popup = wx.PopupTransientWindow(self, wx.BORDER_SIMPLE)
panel = wx.Panel(popup)
sizer = wx.BoxSizer(wx.VERTICAL)
listbox = wx.ListBox(panel, choices=ascii_choices, style=wx.LB_SINGLE)
sizer.Add(listbox, 1, wx.EXPAND | wx.ALL, 4)
panel.SetSizerAndFit(sizer)
popup.SetClientSize(panel.GetBestSize())
# Keep a reference so the popup isn't GC'd
self._kaomoji_popup = popup
def on_select(evt):
"""Handle selection from the kaomoji list (keyboard or programmatic)."""
# Ignore synthetic selection changes triggered only for hover visualization
if getattr(self, "_suppress_kaomoji_select", False):
return
try:
idx = evt.GetSelection()
except AttributeError:
# Fallback for synthetic events where we used SetInt()
idx = evt.GetInt() if hasattr(evt, "GetInt") else -1
try:
if 0 <= idx < len(ascii_choices):
choice = ascii_choices[idx]
if choice:
# Insert at current caret position, but DO NOT auto-send.
current = self.input_ctrl.GetValue()
pos = self.input_ctrl.GetInsertionPoint()
needs_space = pos > 0 and not current[pos - 1].isspace()
insert_text = (" " + choice) if needs_space else choice
new_value = current[:pos] + insert_text + current[pos:]
self.input_ctrl.SetValue(new_value)
self.input_ctrl.SetInsertionPoint(pos + len(insert_text))
finally:
popup.Dismiss()
def on_left_click(evt):
"""Single left-click handler for the kaomoji menu."""
try:
pos = evt.GetPosition()
idx = listbox.HitTest(pos)
if idx != wx.NOT_FOUND:
# Ensure the item is selected, then reuse on_select logic
listbox.SetSelection(idx)
cmd_evt = wx.CommandEvent(wx.wxEVT_LISTBOX, listbox.GetId())
cmd_evt.SetEventObject(listbox)
cmd_evt.SetInt(idx)
on_select(cmd_evt)
else:
evt.Skip()
except Exception as e:
logger.error(f"Error in kaomoji left-click handler: {e}")
def on_motion(evt):
"""Visual hover selector so the current row is highlighted."""
try:
pos = evt.GetPosition()
idx = listbox.HitTest(pos)
current_sel = listbox.GetSelection()
if idx != wx.NOT_FOUND and idx != current_sel:
# Temporarily suppress on_select so hover highlight doesn't send
self._suppress_kaomoji_select = True
try:
listbox.SetSelection(idx)
finally:
self._suppress_kaomoji_select = False
elif idx == wx.NOT_FOUND:
# Optionally clear selection when hovering outside items
self._suppress_kaomoji_select = True
try:
listbox.DeselectAll()
finally:
self._suppress_kaomoji_select = False
except Exception as e:
logger.error(f"Error in kaomoji hover handler: {e}")
finally:
evt.Skip()
# Single left-click selects and sends; keyboard selection still works
listbox.Bind(wx.EVT_LISTBOX, on_select)
listbox.Bind(wx.EVT_LEFT_DOWN, on_left_click)
listbox.Bind(wx.EVT_MOTION, on_motion)
# Position popup under the kaomoji button
btn = self.kaomoji_btn
btn_pos = btn.ClientToScreen((0, btn.GetSize().height))
popup.Position(btn_pos, (0, 0))
popup.Popup()
except Exception as e:
logger.error(f"Error in kaomoji picker: {e}")

View File

@@ -229,24 +229,41 @@ class ScanWizardResultsPage(adv.WizardPageSimple):
start_callback(params)
def on_scan_progress(self, scanned, total):
total = max(total, 1)
self.gauge.SetRange(total)
self.gauge.SetValue(min(scanned, total))
self.summary.SetLabel(f"Scanning… {scanned}/{total} hosts checked")
try:
total = max(total, 1)
self.gauge.SetRange(total)
self.gauge.SetValue(min(scanned, total))
self.summary.SetLabel(f"Scanning… {scanned}/{total} hosts checked")
except RuntimeError:
# C++ SHIT
logger.debug("Scan progress update after controls destroyed; ignoring")
def on_scan_result(self, server_info):
idx = self.results_list.InsertItem(self.results_list.GetItemCount(), server_info["address"])
self.results_list.SetItem(idx, 1, str(server_info["port"]))
self.results_list.SetItem(idx, 2, server_info.get("banner", "IRC server detected"))
self.discovered.append(server_info)
self.summary.SetLabel(f"Found {len(self.discovered)} {"server" if self.discovered == 1 else "servers"}")
"""Handle a single discovered server row."""
try:
idx = self.results_list.InsertItem(self.results_list.GetItemCount(), server_info["address"])
self.results_list.SetItem(idx, 1, str(server_info["port"]))
self.results_list.SetItem(idx, 2, server_info.get("banner", "IRC server detected"))
self.discovered.append(server_info)
self.summary.SetLabel(
f"Found {len(self.discovered)} {'server' if len(self.discovered) == 1 else 'servers'}"
)
except RuntimeError:
logger.debug("Scan result update after controls destroyed; ignoring")
def on_scan_complete(self, results):
if results:
self.summary.SetLabel(f"Scan complete : {len(results)} {"server" if len(results) == 1 else "servers"} ready.")
else:
self.summary.SetLabel("Scan complete : no IRC servers discovered.")
self._toggle_buttons()
"""Final scan completion callback."""
try:
if results:
self.summary.SetLabel(
f"Scan complete : {len(results)} "
f"{'server' if len(results) == 1 else 'servers'} ready."
)
else:
self.summary.SetLabel("Scan complete : no IRC servers discovered.")
self._toggle_buttons()
except RuntimeError:
logger.debug("Scan completion update after controls destroyed; ignoring")
def on_quick_connect(self, event):
row = self.results_list.GetFirstSelected()