From 1cbdaca70af1b4d9c683b500efffb32e03f5433b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=E1=BB=B3nh=20Thi=E1=BB=87n=20L=E1=BB=99c?= <63589389+loccun@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:09:06 +0700 Subject: [PATCH 1/5] Merge pull request #1 from loccun/palette-keymap-update-button-10102198958473316767 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎨 Palette: Update Add button state in Keymap Editor --- settings-gui/ui/pages/keymap_editor.py | 35 +++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/settings-gui/ui/pages/keymap_editor.py b/settings-gui/ui/pages/keymap_editor.py index d111ce9..0142980 100644 --- a/settings-gui/ui/pages/keymap_editor.py +++ b/settings-gui/ui/pages/keymap_editor.py @@ -298,13 +298,15 @@ def _setup_ui(self): for action_code, action_name in BAMBOO_ACTIONS: self.combo_action.addItem(action_name, action_code) - btn_add = QPushButton(QIcon.fromTheme("list-add"), _("Add")) - btn_add.setToolTip(_("Add / Update Keymap")) - btn_add.clicked.connect(self.on_add) + self.btn_add = QPushButton(QIcon.fromTheme("list-add"), _("Add")) + self.btn_add.setToolTip(_("Add Keymap")) + self.btn_add.clicked.connect(self.on_add) + self.input_key.textChanged.connect(self._update_add_button_icon) + self.combo_action.currentIndexChanged.connect(self._update_add_button_icon) input_layout.addWidget(self.input_key) input_layout.addWidget(self.combo_action) - input_layout.addWidget(btn_add) + input_layout.addWidget(self.btn_add) editor_layout.addLayout(input_layout) # Table @@ -435,8 +437,31 @@ def on_add(self): return self._add_row(key, self.combo_action.currentData()) + self.input_key.clear() + self._update_add_button_icon() + self.input_key.setFocus() self._on_item_changed() + def _update_add_button_icon(self, *_args): + """Changes the Add button icon to Update if key exists.""" + key = self.input_key.text().strip() + + # Disable button if key is empty + self.btn_add.setEnabled(bool(key)) + + found = any( + self.table.item(r, 0) and self.table.item(r, 0).text() == key + for r in range(self.table.rowCount()) + ) + if found: + self.btn_add.setIcon(QIcon.fromTheme("document-save")) + self.btn_add.setText(_("Update")) + self.btn_add.setToolTip(_("Update Keymap")) + else: + self.btn_add.setIcon(QIcon.fromTheme("list-add")) + self.btn_add.setText(_("Add")) + self.btn_add.setToolTip(_("Add Keymap")) + def on_load_preset(self): """Loads a predefined set of keymaps.""" preset_name = self.combo_preset.currentText() @@ -482,6 +507,8 @@ def on_row_selected(self, row, column): if cell_combo: self.combo_action.setCurrentIndex(cell_combo.currentIndex()) + self._update_add_button_icon() + def do_import(self): """Imports keymap from a TSV file.""" path, _filter = QFileDialog.getOpenFileName( From d5cfebf5491a818b5f458edaba76d1a173be7abc Mon Sep 17 00:00:00 2001 From: hthienloc Date: Mon, 30 Mar 2026 15:25:25 +0700 Subject: [PATCH 2/5] refactor: consolidate row lookup logic and remove redundant icon update calls in editors --- settings-gui/ui/pages/dict_editor.py | 1 - settings-gui/ui/pages/keymap_editor.py | 30 +++++++++++++------------- settings-gui/ui/pages/macro_editor.py | 30 +++++++++++++++----------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/settings-gui/ui/pages/dict_editor.py b/settings-gui/ui/pages/dict_editor.py index 274e580..c0aeae6 100644 --- a/settings-gui/ui/pages/dict_editor.py +++ b/settings-gui/ui/pages/dict_editor.py @@ -294,7 +294,6 @@ def on_add(self): self.upsert_row(word) self.input_word.clear() - self._update_add_button_icon() self.input_word.setFocus() def _update_add_button_icon(self): diff --git a/settings-gui/ui/pages/keymap_editor.py b/settings-gui/ui/pages/keymap_editor.py index 0142980..21e0944 100644 --- a/settings-gui/ui/pages/keymap_editor.py +++ b/settings-gui/ui/pages/keymap_editor.py @@ -302,7 +302,6 @@ def _setup_ui(self): self.btn_add.setToolTip(_("Add Keymap")) self.btn_add.clicked.connect(self.on_add) self.input_key.textChanged.connect(self._update_add_button_icon) - self.combo_action.currentIndexChanged.connect(self._update_add_button_icon) input_layout.addWidget(self.input_key) input_layout.addWidget(self.combo_action) @@ -428,20 +427,26 @@ def on_add(self): return # Check for update - for row in range(self.table.rowCount()): - item = self.table.item(row, 0) - if item and item.text() == key: - combo = self.table.cellWidget(row, 1) - if combo: - combo.setCurrentIndex(self.combo_action.currentIndex()) - return + row = self._find_row_by_key(key) + if row is not None: + combo = self.table.cellWidget(row, 1) + if combo: + combo.setCurrentIndex(self.combo_action.currentIndex()) + return self._add_row(key, self.combo_action.currentData()) self.input_key.clear() - self._update_add_button_icon() self.input_key.setFocus() self._on_item_changed() + def _find_row_by_key(self, key: str) -> int | None: + """Finds row index for a given key. Returns None if not found.""" + for r in range(self.table.rowCount()): + item = self.table.item(r, 0) + if item and item.text() == key: + return r + return None + def _update_add_button_icon(self, *_args): """Changes the Add button icon to Update if key exists.""" key = self.input_key.text().strip() @@ -449,10 +454,7 @@ def _update_add_button_icon(self, *_args): # Disable button if key is empty self.btn_add.setEnabled(bool(key)) - found = any( - self.table.item(r, 0) and self.table.item(r, 0).text() == key - for r in range(self.table.rowCount()) - ) + found = self._find_row_by_key(key) is not None if found: self.btn_add.setIcon(QIcon.fromTheme("document-save")) self.btn_add.setText(_("Update")) @@ -507,8 +509,6 @@ def on_row_selected(self, row, column): if cell_combo: self.combo_action.setCurrentIndex(cell_combo.currentIndex()) - self._update_add_button_icon() - def do_import(self): """Imports keymap from a TSV file.""" path, _filter = QFileDialog.getOpenFileName( diff --git a/settings-gui/ui/pages/macro_editor.py b/settings-gui/ui/pages/macro_editor.py index a70f13e..e2bdc88 100644 --- a/settings-gui/ui/pages/macro_editor.py +++ b/settings-gui/ui/pages/macro_editor.py @@ -323,16 +323,24 @@ def save_data(self): self.dbus.set_sub_config_list("lotus-macro", "Macro", data) self.initial_state = self._get_current_state() + def _find_row_by_key(self, key: str) -> int | None: + """Finds row index for a given key. Returns None if not found.""" + for r in range(self.table.rowCount()): + item = self.table.item(r, 0) + if item and item.text() == key: + return r + return None + def upsert_row(self, key: str, value: str, sort: bool = True): # Update existing - for row in range(self.table.rowCount()): - if self.table.item(row, 0) and self.table.item(row, 0).text() == key: - self.table.item(row, 1).setText(value) - self._apply_row_highlight(row, key) - if sort: - self.on_search_changed() # Re-apply filter - self.update_button_states() - return + row = self._find_row_by_key(key) + if row is not None: + self.table.item(row, 1).setText(value) + self._apply_row_highlight(row, key) + if sort: + self.on_search_changed() # Re-apply filter + self.update_button_states() + return # Insert new row = self.table.rowCount() @@ -420,7 +428,6 @@ def on_add(self): self.upsert_row(key, val) self.input_key.clear() self.input_val.clear() - self._update_add_button_icon() self.input_key.setFocus() def _update_add_button_icon(self): @@ -440,10 +447,7 @@ def _update_add_button_icon(self): # Disable button if key is invalid, empty, or value is empty self.btn_add.setEnabled(not is_invalid and bool(key) and bool(val)) - found = any( - self.table.item(r, 0) and self.table.item(r, 0).text() == key - for r in range(self.table.rowCount()) - ) + found = self._find_row_by_key(key) is not None if found: self.btn_add.setIcon(QIcon.fromTheme("document-save")) self.btn_add.setText(_("Update")) From e473c2631e715df320d479029825a7959308e252 Mon Sep 17 00:00:00 2001 From: hthienloc Date: Mon, 30 Mar 2026 15:40:41 +0700 Subject: [PATCH 3/5] refactor: implement upsert logic for keymap and macro table entries to ensure consistent state updates --- settings-gui/ui/pages/keymap_editor.py | 26 ++++++++++++++++++-------- settings-gui/ui/pages/macro_editor.py | 2 ++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/settings-gui/ui/pages/keymap_editor.py b/settings-gui/ui/pages/keymap_editor.py index 21e0944..512fda2 100644 --- a/settings-gui/ui/pages/keymap_editor.py +++ b/settings-gui/ui/pages/keymap_editor.py @@ -421,22 +421,32 @@ def on_search_changed(self): self.table.setRowHidden(row, search_text not in key and search_text not in action) def on_add(self): - """Adds a new keymap entry.""" + """Adds or updates a keymap entry.""" key = self.input_key.text().strip() if not key: return - # Check for update + self.upsert_row(key, self.combo_action.currentData()) + self.input_key.clear() + self.input_key.setFocus() + + def upsert_row(self, key: str, action_code: str): + """Adds or updates a row in the keymap table.""" row = self._find_row_by_key(key) if row is not None: - combo = self.table.cellWidget(row, 1) - if combo: - combo.setCurrentIndex(self.combo_action.currentIndex()) + # Update existing + cell_combo = self.table.cellWidget(row, 1) + if cell_combo: + idx = cell_combo.findData(action_code) + if idx >= 0: + cell_combo.setCurrentIndex(idx) + self._on_item_changed() return - self._add_row(key, self.combo_action.currentData()) - self.input_key.clear() - self.input_key.setFocus() + # Insert new + self._add_row(key, action_code) + self.on_search_changed() + self.update_button_states() self._on_item_changed() def _find_row_by_key(self, key: str) -> int | None: diff --git a/settings-gui/ui/pages/macro_editor.py b/settings-gui/ui/pages/macro_editor.py index e2bdc88..dedceb4 100644 --- a/settings-gui/ui/pages/macro_editor.py +++ b/settings-gui/ui/pages/macro_editor.py @@ -340,6 +340,7 @@ def upsert_row(self, key: str, value: str, sort: bool = True): if sort: self.on_search_changed() # Re-apply filter self.update_button_states() + self._on_item_changed() return # Insert new @@ -348,6 +349,7 @@ def upsert_row(self, key: str, value: str, sort: bool = True): self.table.setItem(row, 0, QTableWidgetItem(key)) self.table.setItem(row, 1, QTableWidgetItem(value)) self._apply_row_highlight(row, key) + self.on_search_changed() if sort: self.on_search_changed() # Re-apply filter self.update_button_states() From 194e3670fa38b97070af3b08f9be0a89fd46649e Mon Sep 17 00:00:00 2001 From: hthienloc Date: Mon, 30 Mar 2026 17:41:11 +0700 Subject: [PATCH 4/5] refactor: switch backup file format from .lotusbak to .json --- settings-gui/ui/pages/backup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/settings-gui/ui/pages/backup.py b/settings-gui/ui/pages/backup.py index 6c213fa..2fcaff6 100644 --- a/settings-gui/ui/pages/backup.py +++ b/settings-gui/ui/pages/backup.py @@ -58,7 +58,7 @@ def _setup_ui(self): self.import_desc = QLabel( _( - "Save your configurations to a JSON file, or restore them from a .lotusbak file. Select what you want to include:" + "Save and restore your configurations via JSON files. Select the components you wish to include:" ) ) self.import_desc.setWordWrap(True) @@ -134,13 +134,13 @@ def do_export(self): return default_filename = ( - f"lotus-backup-{datetime.now().strftime('%Y%m%d-%H%M%S')}.lotusbak" + f"lotus-backup-{datetime.now().strftime('%Y%m%d-%H%M%S')}.json" ) path, _filter = QFileDialog.getSaveFileName( self, _("Export Backup"), os.path.join(os.path.expanduser("~"), default_filename), - _("Lotus Backup (*.lotusbak);;All Files (*)"), + _("JSON Backup (*.json);;All Files (*)"), ) if not path: return @@ -194,7 +194,7 @@ def on_select_import_file(self): self, _("Select Backup File"), os.path.expanduser("~"), - _("Lotus Backup (*.lotusbak);;All Files (*)"), + _("JSON Backup (*.json);;All Files (*)"), ) if not path: return From 67cfb4377eda182903afc36ff997880203bed439 Mon Sep 17 00:00:00 2001 From: hthienloc Date: Mon, 30 Mar 2026 17:45:20 +0700 Subject: [PATCH 5/5] fix: update backup description text for clarity --- settings-gui/ui/pages/backup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings-gui/ui/pages/backup.py b/settings-gui/ui/pages/backup.py index 2fcaff6..dd26915 100644 --- a/settings-gui/ui/pages/backup.py +++ b/settings-gui/ui/pages/backup.py @@ -58,7 +58,7 @@ def _setup_ui(self): self.import_desc = QLabel( _( - "Save and restore your configurations via JSON files. Select the components you wish to include:" + "Save or restore your configurations via JSON files. Select the components you wish to include:" ) ) self.import_desc.setWordWrap(True)