diff --git a/app.py b/app.py index 593a239..d913790 100644 --- a/app.py +++ b/app.py @@ -20,7 +20,7 @@ from . import APP_NAME, DISPLAY_NAME, __version__ from .config import PROVIDER_LABELS, AppConfig from .i18n import LANGUAGE_SHORT, LANGUAGES, get_language, on_language_changed, set_language, tr from .state import AppContext -from .ui.widgets import widen_popup +from .ui.widgets import tidy_popup from .theme import current_palette, set_active_theme, stylesheet from .core.task_scheduler import TaskScheduler from .ui.cowork_tab import CoworkTab @@ -261,7 +261,7 @@ class MainWindow(QMainWindow): self.nav_project.setObjectName("navProjectPick") self.nav_project.setToolTip(tr("app.nav.project_pick")) self.nav_project.currentIndexChanged.connect(self._on_rail_project_pick) - widen_popup(self.nav_project) + tidy_popup(self.nav_project) self.nav_new_chat = QPushButton(tr("cowork.new_chat")) self.nav_new_chat.setObjectName("navNewChatBtn") self.nav_new_chat.setIcon(_icon("plus")) @@ -675,7 +675,7 @@ class MainWindow(QMainWindow): if idx >= 0: self.nav_project.setCurrentIndex(idx) has = bool(choices) - widen_popup(self.nav_project) + tidy_popup(self.nav_project) self.nav_project.setEnabled(has) self.nav_project_btn.setEnabled(has) self.nav_project_btn.setToolTip( @@ -991,7 +991,7 @@ class MainWindow(QMainWindow): idx = self.language_combo.findData(get_language()) if idx >= 0: self.language_combo.setCurrentIndex(idx) - widen_popup(self.language_combo) + tidy_popup(self.language_combo) self.language_combo.currentIndexChanged.connect(self._on_language_changed) who.addWidget(self.language_combo) self.theme_btn = self._build_theme_button() @@ -1005,7 +1005,7 @@ class MainWindow(QMainWindow): self.provider_combo.setToolTip(tr("app.provider")) for key, label in PROVIDER_LABELS.items(): self.provider_combo.addItem(label, key) - widen_popup(self.provider_combo) + tidy_popup(self.provider_combo) idx = self.provider_combo.findData(self.ctx.config.active_provider) if idx >= 0: self.provider_combo.setCurrentIndex(idx) diff --git a/tools/check_combo_popup.py b/tools/check_combo_popup.py index 5a61cd3..abd423a 100644 --- a/tools/check_combo_popup.py +++ b/tools/check_combo_popup.py @@ -50,6 +50,7 @@ def main() -> int: app.processEvents() fails = [] + from PySide6.QtWidgets import QStyledItemDelegate for name in ("language_combo", "nav_project", "provider_combo"): combo = getattr(win, name, None) if combo is None or not combo.count(): @@ -66,6 +67,20 @@ def main() -> int: if have < need: fails.append(f"{name}: popup {have}px, khong du {need}px cho chu + dau tick") + # No tick: the row is already tinted, and the menu-style delegate that + # draws one on macOS covered the two letters it was marking. + deleg = combo.itemDelegate() + plain = type(deleg) is QStyledItemDelegate + print(f"{'':15} delegate={type(deleg).__name__} (khong ve dau tick={plain})") + if not plain: + fails.append(f"{name}: dung delegate kieu menu — macOS se ve dau tick") + + # ...and the current row must still be obvious without one. + view = combo.view() + sheet = app.styleSheet() + if "selection-background-color" not in sheet: + fails.append("popup khong to mau muc dang chon") + print() for f in fails: print("FAIL " + f) diff --git a/ui/widgets.py b/ui/widgets.py index 21e3234..cf85c3d 100644 --- a/ui/widgets.py +++ b/ui/widgets.py @@ -162,17 +162,25 @@ def guard_wheel(root: QWidget) -> None: w.installEventFilter(_wheel_guard) -def widen_popup(combo) -> None: - """Give a drop-list room for its text AND the tick beside the current item. +def tidy_popup(combo) -> None: + """Make a drop-list show its options and nothing else. - macOS draws a checkmark against the selected row; Windows does not. A combo - only as wide as "VN" therefore looked fine here and had its two letters - covered there. The popup inherits the combo's width unless told otherwise, - so measure what has to fit and say so. + Two platform habits to undo. macOS marks the current row with a checkmark, + drawn by the menu-style delegate a combo gets by default; the row is already + tinted by selection-background-color, so the tick says nothing twice and, in + a combo only as wide as "VN", covered the letters it was marking. Handing + the view a plain QStyledItemDelegate switches it to item-view painting, + where no such glyph exists. + + And the popup inherits the combo's width unless told otherwise, which had + the project and provider names cut off here regardless of platform. So + measure the longest item — plus an indicator's worth of room, in case a + style still draws one — and set that as the view's minimum. """ - from PySide6.QtWidgets import QStyle + from PySide6.QtWidgets import QStyle, QStyledItemDelegate view = combo.view() + combo.setItemDelegate(QStyledItemDelegate(combo)) fm = view.fontMetrics() longest = max((fm.horizontalAdvance(combo.itemText(i)) for i in range(combo.count())), default=0)