diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index a6cdd9b20..2d62a0f17 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -281,6 +281,7 @@ class AnkiApp(QApplication): def __init__(self, argv: list[str]) -> None: QApplication.__init__(self, argv) + self.installEventFilter(self) self._argv = argv def secondInstance(self) -> bool: @@ -339,6 +340,25 @@ class AnkiApp(QApplication): return True return QApplication.event(self, evt) + # Global cursor: pointer for Qt buttons + ################################################## + + def eventFilter(self, src, evt): + if evt.type() == QEvent.Type.HoverEnter: + if type(src) == QPushButton: + # TODO: apply drop-shadow with setGraphicsEffect(QGraphicsDropShadowEffect) + # issue: can't access attributes of QClassProxy (Qt5-compat) + self.setOverrideCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + else: + self.restoreOverrideCursor() + return False + + elif evt.type() == QEvent.Type.HoverLeave or evt.type() == QCloseEvent: + self.restoreOverrideCursor() + return False + + return False + def parseArgs(argv: list[str]) -> tuple[argparse.Namespace, list[str]]: "Returns (opts, args)." diff --git a/qt/aqt/browser/sidebar/searchbar.py b/qt/aqt/browser/sidebar/searchbar.py index d8f11f6ee..b73d90f12 100644 --- a/qt/aqt/browser/sidebar/searchbar.py +++ b/qt/aqt/browser/sidebar/searchbar.py @@ -6,9 +6,7 @@ from __future__ import annotations import aqt import aqt.browser import aqt.gui_hooks -from aqt import colors from aqt.qt import * -from aqt.theme import theme_manager class SidebarSearchBar(QLineEdit): @@ -20,29 +18,10 @@ class SidebarSearchBar(QLineEdit): self.timer.setInterval(600) self.timer.setSingleShot(True) self.setFrame(False) - self.setup_style() qconnect(self.timer.timeout, self.onSearch) qconnect(self.textChanged, self.onTextChanged) - aqt.gui_hooks.theme_did_change.append(self.setup_style) - - def setup_style(self) -> None: - styles = [ - "padding: 2px", - f"border: 1px solid {theme_manager.color(colors.BORDER)}", - "border-radius: 5px", - ] - - self.setStyleSheet( - "QLineEdit { %s }" % ";".join(styles) - + f""" -QLineEdit:focus {{ - border: 1px solid {theme_manager.color(colors.FOCUS_BORDER)}; -}} - """ - ) - def onTextChanged(self, text: str) -> None: if not self.timer.isActive(): self.timer.start() @@ -57,6 +36,3 @@ QLineEdit:focus {{ self.onSearch() else: QLineEdit.keyPressEvent(self, evt) - - def cleanup(self) -> None: - aqt.gui_hooks.theme_did_change.remove(self.setup_style) diff --git a/qt/aqt/browser/sidebar/tree.py b/qt/aqt/browser/sidebar/tree.py index d173d65e0..cbdaca784 100644 --- a/qt/aqt/browser/sidebar/tree.py +++ b/qt/aqt/browser/sidebar/tree.py @@ -116,7 +116,6 @@ class SidebarTreeView(QTreeView): def cleanup(self) -> None: self.toolbar.cleanup() - self.searchBar.cleanup() gui_hooks.flag_label_did_change.remove(self.refresh) gui_hooks.theme_did_change.remove(self._setup_style) diff --git a/qt/aqt/data/qt/icons/BUILD.bazel b/qt/aqt/data/qt/icons/BUILD.bazel index bf5c44ba4..b3f131a17 100644 --- a/qt/aqt/data/qt/icons/BUILD.bazel +++ b/qt/aqt/data/qt/icons/BUILD.bazel @@ -33,6 +33,9 @@ copy_mdi_icons( # tags "tag-outline.svg", "tag-off-outline.svg", + + # QComboBox arrow + "chevron-down.svg", ], ) diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 6a943e042..23d6a403d 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -187,6 +187,126 @@ class ThemeManager: def _apply_style(self, app: QApplication) -> None: buf = "" + if not is_mac: + buf += f""" +QComboBox, +QLineEdit {{ + border: 1px solid {self.color(colors.BORDER)}; + border-radius: 5px; + padding: 2px; +}} +QComboBox:focus, +QLineEdit:focus {{ + border: 1px solid {self.color(colors.FOCUS_BORDER)}; +}} +QComboBox:on {{ + border-bottom: none; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +}} +QComboBox::drop-down {{ + border: 0px; /* This resets the arrow styles */ + subcontrol-origin: padding; + padding: 4px; + subcontrol-position: top right; + width: 18px; +}} +QComboBox::down-arrow {{ + image: url(icons:chevron-down.svg); +}} +QPushButton {{ + padding: 2px; + border-radius: 5px; + border: 1px solid #cfcbcb; + background: #fff; +}} +QPushButton:hover {{ + background: #f9f8f8; + border-color: #afabac; +}} +QToolTip {{ + border-radius: 5px; + border: 1px solid {self.color(colors.BORDER)}; +}} +QFrame {{ + border: none; + background: none; +}} +QLabel {{ + background: transparent; + border-color: transparent; +}} +QToolTip {{ + background: {self.color(colors.TOOLTIP_BG)}; +}} +QTabWidget {{ + border-radius: 5px; + background: none; + border: none; +}} + +QTabWidget::pane {{ + border: 1px solid {self.color(colors.BORDER)}; + border-top-left-radius: 0px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; + background: {self.color(colors.FRAME_BG)}; +}} + +QTabBar::tab {{ + background: none; + border: 1px solid {self.color(colors.BORDER)}; + border-radius: 0px; + padding: 5px 10px; + margin-bottom: 0px; +}} +QTabBar::tab:selected {{ + background: {self.color(colors.FRAME_BG)}; + margin-bottom: -1px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +}} + + +QTabWidget::tab-bar {{ + top: 1px; +}} + + +QTabBar::tab:!selected:hover {{ + background: {self.color(colors.FRAME_BG)}; +}} + +QTabBar::tab:!selected {{ + margin-top: 5px; + background: {self.color(colors.WINDOW_BG)}; +}} + + +QTabBar::tab {{ + min-width: 8ex; + margin-right: -1px; + padding: 5px 10px 5px 10px; +}} + +QTabBar::tab:selected {{ + border-bottom-color: none; +}} + +QTabBar::tab:bottom:selected {{ + border-top-color: none; +}} + +QTabBar::tab:first, +QTabBar::tab:only-one {{ + border-top-left-radius: 5px; +}} +QTabBar::tab:last, +QTabBar::tab:only-one {{ + border-top-right-radius: 5px; +}} + """ if is_win and platform.release() == "10": # day mode is missing a bottom border; background must be