v1.8.12: fix Ctrl+Z undo — manual implementation for tk.Entry

tk.Entry has no built-in undo (unlike tk.Text), so _entry.config(undo=True)
crashed. Replaced with custom entry_undo.py that tracks history manually
and binds Ctrl+Z/Ctrl+Y (+ Russian layout support).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-02-24 05:28:56 -05:00
parent 0554d8782f
commit afffc4177e
6 changed files with 70 additions and 23 deletions

View File

@@ -5,6 +5,7 @@ Server add/edit dialog — modal window with all server fields.
import customtkinter as ctk
from core.server_store import SERVER_TYPES, DEFAULT_PORTS
from core.i18n import t
from gui.widgets.entry_undo import enable_undo
def _get_network_interfaces() -> list[tuple[str, str]]:
@@ -47,15 +48,13 @@ class ServerDialog(ctk.CTkToplevel):
ctk.CTkLabel(self, text=t("alias"), anchor="w").pack(fill="x", **pad)
self.alias_entry = ctk.CTkEntry(self, placeholder_text=t("placeholder_alias"))
self.alias_entry.pack(fill="x", **entry_pad)
# Enable undo functionality
self.alias_entry._entry.config(undo=True)
enable_undo(self.alias_entry)
# IP
ctk.CTkLabel(self, text=t("ip"), anchor="w").pack(fill="x", **pad)
self.ip_entry = ctk.CTkEntry(self, placeholder_text=t("placeholder_ip"))
self.ip_entry.pack(fill="x", **entry_pad)
# Enable undo functionality
self.ip_entry._entry.config(undo=True)
enable_undo(self.ip_entry)
# Type + Port row
row = ctk.CTkFrame(self, fg_color="transparent")
@@ -76,8 +75,7 @@ class ServerDialog(ctk.CTkToplevel):
ctk.CTkLabel(port_frame, text=t("port"), anchor="w").pack(fill="x")
self.port_entry = ctk.CTkEntry(port_frame, placeholder_text=t("placeholder_port"))
self.port_entry.pack(fill="x")
# Enable undo functionality
self.port_entry._entry.config(undo=True)
enable_undo(self.port_entry)
# Network interface
ctk.CTkLabel(self, text=t("network_interface"), anchor="w").pack(fill="x", **pad)
@@ -97,8 +95,7 @@ class ServerDialog(ctk.CTkToplevel):
ctk.CTkLabel(self, text=t("username"), anchor="w").pack(fill="x", **pad)
self.user_entry = ctk.CTkEntry(self, placeholder_text=t("placeholder_user"))
self.user_entry.pack(fill="x", **entry_pad)
# Enable undo functionality
self.user_entry._entry.config(undo=True)
enable_undo(self.user_entry)
# Password
ctk.CTkLabel(self, text=t("password"), anchor="w").pack(fill="x", **pad)
@@ -106,8 +103,7 @@ class ServerDialog(ctk.CTkToplevel):
pass_frame.pack(fill="x", padx=20, pady=(2, 5))
self.password_entry = ctk.CTkEntry(pass_frame, show="*", placeholder_text=t("placeholder_password"))
self.password_entry.pack(side="left", fill="x", expand=True, padx=(0, 5))
# Enable undo functionality
self.password_entry._entry.config(undo=True)
enable_undo(self.password_entry)
self.show_pass = ctk.CTkButton(pass_frame, text=t("show"), width=60, command=self._toggle_password)
self.show_pass.pack(side="right")
self._pass_visible = False
@@ -117,8 +113,7 @@ class ServerDialog(ctk.CTkToplevel):
self.totp_entry = ctk.CTkEntry(self, placeholder_text=t("placeholder_totp_secret"),
font=ctk.CTkFont(family="Consolas", size=12))
self.totp_entry.pack(fill="x", **entry_pad)
# Enable undo functionality
self.totp_entry._entry.config(undo=True)
enable_undo(self.totp_entry)
# Skip status checks
self.skip_check_var = ctk.BooleanVar(value=False)
@@ -131,8 +126,7 @@ class ServerDialog(ctk.CTkToplevel):
ctk.CTkLabel(self, text=t("notes"), anchor="w").pack(fill="x", **pad)
self.notes_entry = ctk.CTkEntry(self, placeholder_text=t("placeholder_notes"))
self.notes_entry.pack(fill="x", **entry_pad)
# Enable undo functionality
self.notes_entry._entry.config(undo=True)
enable_undo(self.notes_entry)
# Buttons
btn_frame = ctk.CTkFrame(self, fg_color="transparent")