Add stylesheet for QMenu (#2122)

* Give QMenu cursor: pointer

* Darken border colors in dark theme

* Refactor cursor: pointer event filter

* Add QMenu stylesheet

* Remove min-width for QMenu item

* Add QMenuBar styles

with increased height for touchscreen users and more visible highlight color.

* Fix type

* Revert "Add QMenuBar styles"

This reverts commit 6ae405a073.

* Remove strong border from QMenu checkbox style

* Keep highlight color consistent

* Adjust highlight-bg

* Increase horizontal padding and adjust checkbox margin

* Introduce border-faint var and make default border brighter in dark mode

* Fix 1px move on hover and make highlight color more subtle

* Remove win10 styles

because the properties are set in the other stylesheets anyway.

* Fix bottom border of QMenuBar not showing underneath entries

* Remove unused import

* Make border-faint one shade darker in light theme
This commit is contained in:
Matthias Metelka 2022-10-12 06:29:06 +02:00 committed by GitHub
parent 3d47c9547a
commit dc67ed9952
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 69 deletions

View file

@ -345,26 +345,19 @@ class AnkiApp(QApplication):
################################################## ##################################################
def eventFilter(self, src: Any, evt: QEvent) -> bool: def eventFilter(self, src: Any, evt: QEvent) -> bool:
if evt.type() == QEvent.Type.HoverEnter: pointer_classes = (
if ( QPushButton,
( QCheckBox,
isinstance( QRadioButton,
src, QMenu,
( # classes with PyQt5 compatibility proxy
QPushButton, without_qt5_compat_wrapper(QToolButton),
QCheckBox, without_qt5_compat_wrapper(QTabBar),
QRadioButton, )
# classes with PyQt5 compatibility proxy if evt.type() in [QEvent.Type.Enter, QEvent.Type.HoverEnter]:
without_qt5_compat_wrapper(QToolButton), if (isinstance(src, pointer_classes) and src.isEnabled()) or (
without_qt5_compat_wrapper(QTabBar), isinstance(src, without_qt5_compat_wrapper(QComboBox))
), and not src.isEditable()
)
)
and src.isEnabled()
or (
isinstance(src, without_qt5_compat_wrapper(QComboBox))
and not src.isEditable()
)
): ):
self.setOverrideCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.setOverrideCursor(QCursor(Qt.CursorShape.PointingHandCursor))
else: else:

View file

@ -16,7 +16,7 @@ a.deck:hover {
} }
tr.deck td { tr.deck td {
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--border-faint);
} }
tr.top-level-drag-row td { tr.top-level-drag-row td {

View file

@ -28,7 +28,8 @@ qlineargradient(
def general_styles(tm: ThemeManager) -> str: def general_styles(tm: ThemeManager) -> str:
return f""" return f"""
QFrame {{ QFrame,
QWidget {{
background: none; background: none;
}} }}
QPushButton, QPushButton,
@ -38,7 +39,7 @@ QLineEdit,
QListWidget, QListWidget,
QTreeWidget, QTreeWidget,
QListView {{ QListView {{
border: 1px solid {tm.var(colors.BORDER)}; border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-radius: {tm.var(props.BORDER_RADIUS)}; border-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QLineEdit {{ QLineEdit {{
@ -58,6 +59,47 @@ QSpinBox {{
""" """
def menu_styles(tm: ThemeManager) -> str:
return f"""
QMenuBar {{
border-bottom: 1px solid {tm.var(colors.BORDER_FAINT)};
}}
QMenuBar::item {{
background-color: transparent;
padding: 2px 4px;
border-radius: {tm.var(props.BORDER_RADIUS)};
}}
QMenuBar::item:selected {{
background-color: {tm.var(colors.CANVAS_ELEVATED)};
}}
QMenu {{
background-color: {tm.var(colors.CANVAS_OVERLAY)};
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
padding: 4px;
}}
QMenu::item {{
background-color: transparent;
padding: 3px 14px;
margin-bottom: 4px;
}}
QMenu::item:selected {{
background-color: {tm.var(colors.CANVAS_INSET)};
color: {tm.var(colors.HIGHLIGHT_FG)};
border-radius: {tm.var(props.BORDER_RADIUS)};
}}
QMenu::separator {{
height: 1px;
background: {tm.var(colors.BORDER_SUBTLE)};
margin: 0 8px 4px 8px;
}}
QMenu::indicator {{
border: 1px solid {tm.var(colors.BORDER)};
margin-left: 6px;
margin-right: -6px;
}}
"""
def button_styles(tm: ThemeManager) -> str: def button_styles(tm: ThemeManager) -> str:
return f""" return f"""
QPushButton {{ QPushButton {{
@ -184,7 +226,7 @@ QTabWidget::pane {{
top: -15px; top: -15px;
padding-top: 1em; padding-top: 1em;
background: {tm.var(colors.CANVAS_ELEVATED)}; background: {tm.var(colors.CANVAS_ELEVATED)};
border: 1px solid {tm.var(colors.BORDER)}; border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-radius: {tm.var(props.BORDER_RADIUS)}; border-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QTabWidget::tab-bar {{ QTabWidget::tab-bar {{
@ -196,7 +238,7 @@ QTabBar::tab {{
min-width: 8ex; min-width: 8ex;
}} }}
QTabBar::tab {{ QTabBar::tab {{
border: 1px solid {tm.var(colors.BORDER)}; border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
}} }}
QTabBar::tab:first {{ QTabBar::tab:first {{
border-top-{tm.left()}-radius: {tm.var(props.BORDER_RADIUS)}; border-top-{tm.left()}-radius: {tm.var(props.BORDER_RADIUS)};
@ -225,7 +267,7 @@ def table_styles(tm: ThemeManager) -> str:
return f""" return f"""
QTableView {{ QTableView {{
border-radius: {tm.var(props.BORDER_RADIUS)}; border-radius: {tm.var(props.BORDER_RADIUS)};
gridline-color: {tm.var(colors.BORDER)}; gridline-color: {tm.var(colors.BORDER_SUBTLE)};
selection-background-color: {tm.var(colors.SELECTION_BG)}; selection-background-color: {tm.var(colors.SELECTION_BG)};
selection-color: {tm.var(colors.SELECTION_FG)}; selection-color: {tm.var(colors.SELECTION_FG)};
}} }}
@ -233,7 +275,7 @@ QHeaderView {{
background: {tm.var(colors.CANVAS)}; background: {tm.var(colors.CANVAS)};
}} }}
QHeaderView::section {{ QHeaderView::section {{
border: 1px solid {tm.var(colors.BORDER)}; border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
background: { background: {
button_gradient( button_gradient(
tm.var(colors.BUTTON_GRADIENT_START), tm.var(colors.BUTTON_GRADIENT_START),
@ -261,19 +303,19 @@ QHeaderView::section:hover {{
}; };
}} }}
QHeaderView::section:first {{ QHeaderView::section:first {{
border-left: 1px solid {tm.var(colors.BORDER)}; border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-top-left-radius: {tm.var(props.BORDER_RADIUS)}; border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QHeaderView::section:!first {{ QHeaderView::section:!first {{
border-left: none; border-left: none;
}} }}
QHeaderView::section:last {{ QHeaderView::section:last {{
border-right: 1px solid {tm.var(colors.BORDER)}; border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QHeaderView::section:only-one {{ QHeaderView::section:only-one {{
border-left: 1px solid {tm.var(colors.BORDER)}; border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-right: 1px solid {tm.var(colors.BORDER)}; border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-top-left-radius: {tm.var(props.BORDER_RADIUS)}; border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
@ -374,16 +416,16 @@ QRadioButton {{
margin: 2px 0; margin: 2px 0;
}} }}
QCheckBox::indicator, QCheckBox::indicator,
QRadioButton::indicator {{ QRadioButton::indicator,
QMenu::indicator {{
border: 1px solid {tm.var(colors.BUTTON_BORDER)}; border: 1px solid {tm.var(colors.BUTTON_BORDER)};
border-radius: {tm.var(props.BORDER_RADIUS)};
background: {tm.var(colors.CANVAS_INSET)}; background: {tm.var(colors.CANVAS_INSET)};
width: 16px; width: 16px;
height: 16px; height: 16px;
}} }}
QCheckBox::indicator {{ QRadioButton::indicator,
border-radius: {tm.var(props.BORDER_RADIUS)}; QMenu::indicator:exclusive {{
}}
QRadioButton::indicator {{
border-radius: 8px; border-radius: 8px;
}} }}
QCheckBox::indicator:hover, QCheckBox::indicator:hover,
@ -395,7 +437,8 @@ QRadioButton::indicator:checked:hover {{
height: 14px; height: 14px;
}} }}
QCheckBox::indicator:checked, QCheckBox::indicator:checked,
QRadioButton::indicator:checked {{ QRadioButton::indicator:checked,
QMenu::indicator:checked {{
image: url({tm.themed_icon("mdi:check")}); image: url({tm.themed_icon("mdi:check")});
}} }}
QCheckBox::indicator:indeterminate {{ QCheckBox::indicator:indeterminate {{
@ -445,20 +488,3 @@ QScrollBar::sub-line {{
background: none; background: none;
}} }}
""" """
def win10_styles(tm: ThemeManager) -> str:
return f"""
/* day mode is missing a bottom border; background must be
also set for border to apply */
QMenuBar {{
border-bottom: 1px solid {tm.var(colors.BORDER)};
background: {tm.var(colors.CANVAS) if tm.night_mode else "white"};
}}
/* qt bug? setting the above changes the browser sidebar
to white as well, so set it back */
QTreeWidget {{
background: {tm.var(colors.CANVAS)};
}}
"""

View file

@ -5,7 +5,6 @@ from __future__ import annotations
import enum import enum
import os import os
import platform
import re import re
import subprocess import subprocess
from dataclasses import dataclass from dataclasses import dataclass
@ -229,29 +228,27 @@ class ThemeManager:
checkbox_styles, checkbox_styles,
combobox_styles, combobox_styles,
general_styles, general_styles,
menu_styles,
scrollbar_styles, scrollbar_styles,
spinbox_styles, spinbox_styles,
table_styles, table_styles,
tabwidget_styles, tabwidget_styles,
win10_styles,
) )
buf += "".join( buf += "".join(
[ [
general_styles(self), general_styles(self),
button_styles(self), button_styles(self),
checkbox_styles(self),
menu_styles(self),
combobox_styles(self), combobox_styles(self),
tabwidget_styles(self), tabwidget_styles(self),
table_styles(self), table_styles(self),
spinbox_styles(self), spinbox_styles(self),
checkbox_styles(self),
scrollbar_styles(self), scrollbar_styles(self),
] ]
) )
if is_win and platform.release() == "10":
buf += win10_styles(self)
# allow addons to modify the styling # allow addons to modify the styling
buf = gui_hooks.style_did_init(buf) buf = gui_hooks.style_did_init(buf)

View file

@ -56,8 +56,8 @@ $vars: (
dark: palette(darkgray, 6), dark: palette(darkgray, 6),
), ),
overlay: ( overlay: (
light: white, light: palette(lightgray, 0),
dark: black, dark: palette(darkgray, 5),
), ),
code: ( code: (
light: white, light: white,
@ -67,16 +67,20 @@ $vars: (
border: ( border: (
default: ( default: (
light: palette(lightgray, 6), light: palette(lightgray, 6),
dark: palette(darkgray, 7), dark: palette(darkgray, 4),
),
subtle: (
light: palette(lightgray, 5),
dark: palette(darkgray, 6),
), ),
strong: ( strong: (
light: palette(lightgray, 9), light: palette(lightgray, 9),
dark: palette(darkgray, 1), dark: palette(darkgray, 1),
), ),
subtle: (
light: palette(lightgray, 5),
dark: palette(darkgray, 7),
),
faint: (
light: palette(lightgray, 4),
dark: palette(darkgray, 6),
),
focus: ( focus: (
light: palette(blue, 5), light: palette(blue, 5),
dark: palette(blue, 5), dark: palette(blue, 5),
@ -269,8 +273,8 @@ $vars: (
), ),
highlight: ( highlight: (
bg: ( bg: (
light: palette(blue, 3), light: color.scale(palette(blue, 3), $alpha: -33%),
dark: palette(blue, 4), dark: color.scale(palette(blue, 4), $alpha: -33%),
), ),
fg: ( fg: (
light: black, light: black,