Create stylesheet overrides for various Qt widgets

Including QPushButton, QComboBox, QSpinBox, QLineEdit, QListWidget, QTabWidget, QTreeWidget, QToolTip, QTableView, QScrollBar and sub-widgets.
This commit is contained in:
Matthias Metelka 2022-09-04 11:34:03 +02:00
parent cb287c6905
commit 86b78256f7
8 changed files with 395 additions and 214 deletions

View file

@ -34,8 +34,9 @@ copy_mdi_icons(
"tag-outline.svg",
"tag-off-outline.svg",
# QComboBox arrow
"chevron-down.svg",
# QComboBox and QSpinBox arrows
"menu-up.svg",
"menu-down.svg",
],
)

326
qt/aqt/stylesheets.py Normal file
View file

@ -0,0 +1,326 @@
from aqt import colors
from aqt.theme import ThemeManager
def general_styles(tm: ThemeManager, buf: str) -> str:
buf += f"""
QFrame {{
background: none;
}}
QPushButton,
QComboBox,
QSpinBox,
QLineEdit,
QListWidget,
QTreeWidget,
QListView {{
border: 1px solid {tm.color(colors.BUTTON_BORDER)};
border-radius: 5px;
}}
QComboBox,
QLineEdit {{
padding: 2px;
}}
QComboBox:focus,
QComboBox:on,
QLineEdit:focus {{
border-color: {tm.color(colors.FOCUS_BORDER)};
}}
QPushButton {{
margin-top: 1px;
}}
QPushButton,
QComboBox,
QSpinBox {{
padding: 2px 6px;
}}
QToolTip {{
background: {tm.color(colors.TOOLTIP_BG)};
}}
"""
return buf
def button_styles(tm: ThemeManager, buf: str) -> str:
buf += f"""
QPushButton:pressed,
QHeaderView::section:pressed,
QSpinBox::up-button:pressed,
QSpinBox::down-button:pressed {{
border: 1px solid {tm.color(colors.BUTTON_PRESSED_BORDER)};
background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_PRESSED_SHADOW)},
stop:0.1 {tm.color(colors.BUTTON_GRADIENT_START)},
stop:0.9 {tm.color(colors.BUTTON_GRADIENT_END)}
stop:1 {tm.color(colors.BUTTON_PRESSED_SHADOW)},
);
}}
QPushButton,
QHeaderView::section,
QSpinBox::up-button,
QSpinBox::down-button,
QComboBox:!editable,
QComboBox::drop-down:editable {{
background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_GRADIENT_END)}
);
}}
QPushButton:hover,
QHeaderView::section:hover,
QSpinBox::up-button:hover,
QSpinBox::down-button:hover,
QComboBox:!editable:hover,
QComboBox::drop-down:editable:hover {{
background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25,
stop:0 {tm.color(colors.BUTTON_HOVER_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_HOVER_GRADIENT_END)}
);
}}
"""
return buf
def combobox_styles(tm: ThemeManager, buf: str) -> str:
buf += f"""
QComboBox:on {{
border-bottom: none;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}}
QComboBox::drop-down {{
border: 0px;
subcontrol-origin: padding;
padding: 4px;
subcontrol-position: top right;
width: 18px;
}}
QComboBox::drop-down:editable {{
margin: 1px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
border-left: 1px solid {tm.color(colors.BUTTON_BORDER)};
}}
QComboBox::down-arrow {{
image: url(icons:menu-down.svg);
}}
"""
return buf
def tabwidget_styles(tm: ThemeManager, buf: str) -> str:
buf += f"""
QTabWidget {{
border-radius: 5px;
border: none;
background: none;
}}
QTabWidget::pane {{
border: 1px solid {tm.color(colors.FRAME_BG)};
border-radius: 5px;
background: {tm.color(colors.FRAME_BG)};
}}
QTabWidget::tab-bar {{
alignment: center;
}}
QTabBar::tab {{
background: none;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
padding: 5px 10px;
margin-bottom: 0px;
}}
QTabBar::tab:!selected:hover,
QTabBar::tab:selected {{
background: {tm.color(colors.FRAME_BG)};
}}
QTabBar::tab:selected {{
margin-bottom: -1px;
}}
QTabBar::tab:!selected {{
margin-top: 5px;
background: {tm.color(colors.WINDOW_BG)};
}}
QTabBar::tab {{
min-width: 8ex;
padding: 5px 10px 5px 10px;
}}
QTabBar::tab:selected {{
border-bottom-color: none;
}}
QTabBar::tab:bottom:selected {{
border-top-color: none;
}}
QTabBar::tab:previous-selected {{
border-top-left-radius: 0;
}}
QTabBar::tab:next-selected {{
border-top-right-radius: 0;
}}
"""
return buf
def table_styles(tm: ThemeManager, buf: str) -> str:
buf += f"""
QTableView {{
margin: -1px -1px 1px -1px;
background: none;
border: 2px solid {tm.color(colors.WINDOW_BG)};
border-radius: 5px;
}}
QHeaderView::section {{
border: 2px solid {tm.color(colors.WINDOW_BG)};
margin: -1px;
}}
QHeaderView::section:first {{
border-top: 2px solid {tm.color(colors.WINDOW_BG)};
border-left: 2px solid {tm.color(colors.WINDOW_BG)};
border-top-left-radius: 5px;
}}
QHeaderView::section:!first {{
border-left: none;
}}
QHeaderView::section:last {{
border-top: 2px solid {tm.color(colors.WINDOW_BG)};
border-right: 2px solid {tm.color(colors.WINDOW_BG)};
border-top-right-radius: 5px;
}}
QHeaderView::section:next-selected {{
border-right: none;
}}
QHeaderView::section:previous-selected {{
border-left: none;
}}
QHeaderView::section:only-one {{
border-left: 2px solid {tm.color(colors.WINDOW_BG)};
border-top: 2px solid {tm.color(colors.WINDOW_BG)};
border-right: 2px solid {tm.color(colors.WINDOW_BG)};
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}}
QHeaderView::up-arrow,
QHeaderView::down-arrow {{
width: 20px;
height: 20px;
}}
QHeaderView::up-arrow {{
image: url(icons:menu-up.svg);
}}
QHeaderView::down-arrow {{
image: url(icons:menu-down.svg);
}}
"""
return buf
def spinbox_styles(tm: ThemeManager, buf: str) -> str:
buf += f"""
QSpinBox::up-button,
QSpinBox::down-button {{
subcontrol-origin: border;
width: 16px;
border: 1px solid {tm.color(colors.BUTTON_BORDER)};
}}
QSpinBox::up-button {{
margin-bottom: -1px;
subcontrol-position: top right;
border-top-right-radius: 5px;
}}
QSpinBox::down-button {{
margin-top: -1px;
subcontrol-position: bottom right;
border-bottom-right-radius: 5px;
}}
QSpinBox::up-arrow {{
image: url(icons:menu-up.svg);
}}
QSpinBox::down-arrow {{
image: url(icons:menu-down.svg);
}}
QSpinBox::up-arrow,
QSpinBox::down-arrow,
QSpinBox::up-arrow:pressed,
QSpinBox::down-arrow:pressed {{
width: 16px;
height: 16px;
}}
QSpinBox::up-arrow:hover,
QSpinBox::down-arrow:hover {{
width: 20px;
height: 20px;
}}
"""
return buf
def scrollbar_styles(tm: ThemeManager, buf: str) -> str:
buf += f"""
QAbstractScrollArea::corner {{
background: none;
border: none;
}}
QScrollBar {{
background-color: {tm.color(colors.WINDOW_BG)};
}}
QScrollBar::handle {{
border-radius: 5px;
background-color: {tm.color(colors.SCROLLBAR_BG)};
}}
QScrollBar::handle:hover {{
background-color: {tm.color(colors.SCROLLBAR_HOVER_BG)};
}}
QScrollBar:horizontal {{
height: 12px;
}}
QScrollBar::handle:horizontal {{
min-width: 50px;
}}
QScrollBar:vertical {{
width: 12px;
}}
QScrollBar::handle:vertical {{
min-height: 50px;
}}
QScrollBar::add-line {{
border: none;
background: none;
}}
QScrollBar::sub-line {{
border: none;
background: none;
}}
"""
return buf
def win10_styles(tm: ThemeManager, buf: str) -> str:
# day mode is missing a bottom border; background must be
# also set for border to apply
buf += f"""
QMenuBar {{
border-bottom: 1px solid {tm.color(colors.BORDER)};
background: {tm.color(colors.WINDOW_BG) if tm.night_mode else "white"};
}}
"""
# qt bug? setting the above changes the browser sidebar
# to white as well, so set it back
buf += f"""
QTreeWidget {{
background: {tm.color(colors.WINDOW_BG)};
}}
"""
if tm.night_mode:
buf += """
QToolTip {
border: 0;
}
"""
return buf

View file

@ -186,180 +186,37 @@ class ThemeManager:
gui_hooks.theme_did_change()
def _apply_style(self, app: QApplication) -> None:
from aqt.stylesheets import (
button_styles,
combobox_styles,
general_styles,
scrollbar_styles,
spinbox_styles,
table_styles,
tabwidget_styles,
win10_styles,
)
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;
}}
"""
buf += "".join(
[
general_styles(self, buf),
button_styles(self, buf),
combobox_styles(self, buf),
tabwidget_styles(self, buf),
table_styles(self, buf),
spinbox_styles(self, buf),
scrollbar_styles(self, buf),
]
)
if is_win and platform.release() == "10":
# day mode is missing a bottom border; background must be
# also set for border to apply
buf += f"""
QMenuBar {{
border-bottom: 1px solid {self.color(colors.BORDER)};
background: {self.color(colors.WINDOW_BG) if self.night_mode else "white"};
}}
"""
# qt bug? setting the above changes the browser sidebar
# to white as well, so set it back
buf += f"""
QTreeWidget {{
background: {self.color(colors.WINDOW_BG)};
}}
"""
if self.night_mode:
buf += """
QToolTip {
border: 0;
}
"""
buf += win10_styles(self, buf)
if not self.macos_dark_mode():
buf += """
QScrollBar {{ background-color: {}; }}
QScrollBar::handle {{ background-color: {}; border-radius: 5px; }}
QScrollBar:horizontal {{ height: 12px; }}
QScrollBar::handle:horizontal {{ min-width: 50px; }}
QScrollBar:vertical {{ width: 12px; }}
QScrollBar::handle:vertical {{ min-height: 50px; }}
QScrollBar::add-line {{
border: none;
background: none;
}}
QScrollBar::sub-line {{
border: none;
background: none;
}}
QTabWidget {{ background-color: {}; }}
""".format(
self.color(colors.WINDOW_BG),
# fushion-button-hover-bg
"#656565",
self.color(colors.WINDOW_BG),
)
buf += scrollbar_styles(self, buf)
# allow addons to modify the styling
buf = gui_hooks.style_did_init(buf)

View file

@ -1,6 +1,7 @@
/* Copyright: Ankitects Pty Ltd and contributors
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
@use "fusion-vars";
@use "sass:color";
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@ -26,12 +27,7 @@ $btn-base-color-day: white;
border-color: var(--medium-border) !important;
}
@mixin btn-day(
$with-hover: true,
$with-active: true,
$with-disabled: true,
$with-margin: true
) {
@mixin btn-day($with-hover: true, $with-active: true, $with-disabled: true) {
.btn-day {
@include btn-day-base;
@content ($btn-base-color-day);
@ -39,7 +35,7 @@ $btn-base-color-day: white;
@if ($with-hover) {
&:hover,
&.hover {
background-color: darken($btn-base-color-day, 8%);
background-color: color.scale($btn-base-color-day, $lightness: -20%);
}
}
@ -60,10 +56,6 @@ $btn-base-color-day: white;
box-shadow: none !important;
}
}
@if ($with-margin) {
margin-left: -1px;
}
}
}
@ -72,23 +64,17 @@ $btn-base-color-night: fusion-vars.$button-border;
@mixin btn-night-base {
color: var(--text-fg);
background: linear-gradient(
0deg,
180deg,
fusion-vars.$button-gradient-start 0%,
fusion-vars.$button-gradient-end 100%
);
}
@mixin btn-night(
$with-hover: true,
$with-active: true,
$with-disabled: true,
$with-margin: true
) {
@mixin btn-night($with-hover: true, $with-active: true, $with-disabled: true) {
.btn-night {
@include btn-night-base;
@content ($btn-base-color-night);
box-shadow: 0 0 3px fusion-vars.$button-outline;
border: 1px solid fusion-vars.$button-border;
-webkit-appearance: none;
@ -96,11 +82,11 @@ $btn-base-color-night: fusion-vars.$button-border;
&:hover,
&.hover {
background: linear-gradient(
0deg,
lighten(fusion-vars.$button-gradient-start, 8%) 0%,
lighten(fusion-vars.$button-gradient-end, 8%) 100%
180deg,
color.scale(fusion-vars.$button-gradient-start, $lightness: 20%) 0%,
color.scale(fusion-vars.$button-gradient-end, $lightness: 20%) 100%
);
border-color: lighten(fusion-vars.$button-border, 8%);
border-color: color.scale(fusion-vars.$button-border, $lightness: 20%);
}
}
@ -108,7 +94,7 @@ $btn-base-color-night: fusion-vars.$button-border;
&:active,
&.active {
@include impressed-shadow(0.35);
border-color: darken($btn-base-color-night, 8%);
border-color: color.scale($btn-base-color-night, $lightness: -20%);
}
&:active.active {
@ -124,10 +110,6 @@ $btn-base-color-night: fusion-vars.$button-border;
border-color: $btn-base-color-night !important;
}
}
@if ($with-margin) {
margin-left: 1px;
}
}
}

View file

@ -1,7 +1,7 @@
/* night-mode-specific colours */
$button-gradient-start: #555555;
$button-gradient-end: #656565;
$button-outline: #222222;
$button-hover-bg: #656565;
$button-border: #646464;
$button-base-bg: #454545;
$button-gradient-start: #3f3f3f;
$button-gradient-end: #363636;
$button-outline: #212121;
$button-hover-bg: #404040;
$button-border: #212121;
$button-base-bg: #343434;

View file

@ -39,13 +39,22 @@
--focus-border: #0969da;
--focus-shadow: rgba(9 105 218 / 0.3);
--code-bg: white;
--button-gradient-start: white;
--button-gradient-end: #f6f6f6;
--button-hover-gradient-start: #f4f4f4;
--button-hover-gradient-end: #efefef;
--button-pressed-shadow: #555;
--button-border: #aaa;
--button-pressed-border: #8f8f8f;
--scrollbar-bg: #d8d8d8;
--scrollbar-hover-bg: #d0d0d0;
}
:root[class*="night-mode"] {
--text-fg: white;
--window-bg: #2f2f31;
--frame-bg: #3a3a3a;
--border: #777;
--border: #4a4a4a;
--medium-border: #444;
--faint-border: #29292b;
--link: #77ccff;
@ -79,5 +88,14 @@
--focus-border: #316dca;
--focus-shadow: #194380;
--code-bg: #272822;
--button-gradient-start: #3f3f3f;
--button-gradient-end: #363636;
--button-hover-gradient-start: #434343;
--button-hover-gradient-end: #404040;
--button-pressed-shadow: #232323;
--button-border: #2f2f31;
--button-pressed-border: #0a0a0a;
--scrollbar-bg: #434343;
--scrollbar-hover-bg: #4e4e4e;
color-scheme: dark;
}

View file

@ -42,7 +42,6 @@
fusion-vars.$button-gradient-start 0%,
fusion-vars.$button-gradient-end 100%
);
box-shadow: 0 0 3px fusion-vars.$button-outline;
border: 1px solid fusion-vars.$button-border;
border-radius: 5px;

View file

@ -1,6 +1,7 @@
/* Copyright: Ankitects Pty Ltd and contributors
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
@use "fusion-vars";
@use "sass:color";
@use "sass/button-mixins" as button;
$btn-base-color-day: white;
@ -17,10 +18,8 @@ $padding: 2px;
background-color: $btn-base-color-day;
border: 1px solid var(--medium-border);
@include button.btn-border-radius;
margin-left: -1px;
&:hover {
background-color: darken($btn-base-color-day, 8%);
background-color: color.scale($btn-base-color-day, $lightness: -20%);
}
&:active,
@ -29,7 +28,6 @@ $padding: 2px;
}
.nightMode & {
box-shadow: 0 0 3px fusion-vars.$button-outline;
border: 1px solid fusion-vars.$button-border;
-webkit-appearance: none;
background: linear-gradient(
@ -43,15 +41,15 @@ $padding: 2px;
&:hover {
background: linear-gradient(
0deg,
lighten(fusion-vars.$button-gradient-start, 8%) 0%,
lighten(fusion-vars.$button-gradient-end, 8%) 100%
color.scale(fusion-vars.$button-gradient-start, $lightness: 20%) 0%,
color.scale(fusion-vars.$button-gradient-end, $lightness: 20%) 100%
);
border-color: lighten(fusion-vars.$button-border, 8%);
border-color: color.scale(fusion-vars.$button-border, $lightness: 20%);
}
&:active {
@include button.impressed-shadow(0.35);
border-color: darken($btn-base-color-night, 8%);
border-color: color.scale($btn-base-color-night, $lightness: -20%);
}
}
}