diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4bce1a2b..402ef275 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ CHANGELOG for FlatCAM Evo beta
- fixed preprocessors issue where the start GCode was not added due of trying to access an object that did not exist (because its name was not changed to reflect the changes in other parts on the app)
- updated the requirements.txt file
+- added qdarktheme package into the code
27.09.2023
diff --git a/appMain.py b/appMain.py
index 09a66e85..86a742ce 100644
--- a/appMain.py
+++ b/appMain.py
@@ -47,9 +47,9 @@ import socket
import tkinter as tk
-import qdarktheme
-import qdarktheme.themes.dark.stylesheet as qdarksheet
-import qdarktheme.themes.light.stylesheet as qlightsheet
+import libs.qdarktheme
+import libs.qdarktheme.themes.dark.stylesheet as qdarksheet
+import libs.qdarktheme.themes.light.stylesheet as qlightsheet
from typing import Union
@@ -628,11 +628,11 @@ class App(QtCore.QObject):
elif self.options["global_theme"] == 'light':
self.resource_location = 'assets/resources'
qlightsheet.STYLE_SHEET = light_style_sheet.L_STYLE_SHEET
- self.qapp.setStyleSheet(qdarktheme.load_stylesheet('light'))
+ self.qapp.setStyleSheet(libs.qdarktheme.load_stylesheet('light'))
else:
self.resource_location = 'assets/resources/dark_resources'
qdarksheet.STYLE_SHEET = dark_style_sheet.D_STYLE_SHEET
- self.qapp.setStyleSheet(qdarktheme.load_stylesheet())
+ self.qapp.setStyleSheet(libs.qdarktheme.load_stylesheet())
# ############################################################################################################
# ################################### Set LOG verbosity ######################################################
@@ -801,7 +801,6 @@ class App(QtCore.QObject):
self.ui = MainGUI(self)
# ########################
-
# decide if to show or hide the Notebook side of the screen at startup
if self.options["global_project_at_startup"] is True:
self.ui.splitter.setSizes([1, 1])
@@ -956,7 +955,7 @@ class App(QtCore.QObject):
self.hover_shapes = ShapeCollectionLegacy(obj=self, app=self, name='hover')
# Storage for Selection shapes
- self.sel_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name="selection")
+ self.sel_shapes = ShapeCollectionLegacy(obj=self, app=self, name="selection")
# #############################################################################################################
end_plot_time = time.time()
@@ -4142,9 +4141,9 @@ class App(QtCore.QObject):
"""
Called for converting a Geometry object from single-geo to multi-geo.
Single-geo Geometry objects store their geometry data into self.solid_geometry.
- Multi-geo Geometry objects store their geometry data into the self.tools dictionary, each key (a tool actually)
- having as a value another dictionary. This value dictionary has one of its keys 'solid_geometry' which holds
- the solid-geometry of that tool.
+ Multi-geo Geometry objects store their geometry data into the `self.tools` dictionary, each key
+ (a tool actually) having as a value another dictionary. This value dictionary has
+ one of its keys 'solid_geometry' which holds the solid-geometry of that tool.
:return: None
"""
@@ -4833,7 +4832,7 @@ class App(QtCore.QObject):
except Exception:
pass
- if type(dia_box_location) == tuple:
+ if isinstance(dia_box_location, tuple):
dia_box_location = str(dia_box_location)
else:
dia_box_location = None
@@ -5296,7 +5295,7 @@ class App(QtCore.QObject):
else:
default_data[opt_key] = self.options[opt_key]
- if type(self.options["tools_mill_tooldia"]) == float:
+ if isinstance(self.options["tools_mill_tooldia"], float):
tools_diameters = [self.options["tools_mill_tooldia"]]
else:
try:
@@ -7240,7 +7239,7 @@ class App(QtCore.QObject):
outline = self.options['global_sel_line'][:-2] + str(hex(int(1.0 * 255)))[2:]
self.sel_objects_list.append(
- self.sel_shapes.add(b_sel_rect,color=outline, face_color=face, update=True, layer=0, tolerance=None)
+ self.sel_shapes.add(b_sel_rect, color=outline, face_color=face, update=True, layer=0, tolerance=None)
)
if self.use_3d_engine is False:
self.sel_shapes.redraw()
@@ -7350,17 +7349,17 @@ class App(QtCore.QObject):
return
obj = self.collection.get_active()
- if type(obj) == GeometryObject:
+ if isinstance(obj, GeometryObject):
self.f_handlers.on_file_exportdxf()
- elif type(obj) == ExcellonObject:
+ elif isinstance(obj, ExcellonObject):
self.f_handlers.on_file_saveexcellon()
- elif type(obj) == CNCJobObject:
+ elif isinstance(obj, CNCJobObject):
obj.on_exportgcode_button_click()
- elif type(obj) == GerberObject:
+ elif isinstance(obj, GerberObject):
self.f_handlers.on_file_savegerber()
- elif type(obj) == ScriptObject:
+ elif isinstance(obj, ScriptObject):
self.f_handlers.on_file_savescript()
- elif type(obj) == DocumentObject:
+ elif isinstance(obj, DocumentObject):
self.f_handlers.on_file_savedocument()
def obj_move(self):
diff --git a/flatcam.py b/flatcam.py
index cc2a8fd2..5729da67 100644
--- a/flatcam.py
+++ b/flatcam.py
@@ -12,8 +12,6 @@ from appGUI import VisPyPatches
from appGUI.GUIElements import FCMessageBox
from multiprocessing import freeze_support
-# import copyreg
-# import types
MIN_VERSION_MAJOR = 3
MIN_VERSION_MINOR = 6
diff --git a/libs/qdarktheme/__init__.py b/libs/qdarktheme/__init__.py
new file mode 100644
index 00000000..e7bf97a1
--- /dev/null
+++ b/libs/qdarktheme/__init__.py
@@ -0,0 +1,6 @@
+"""PyQtDarkTheme - A flat dark theme for PySide and PyQt.
+
+- Repository: https://github.com/5yutan5/PyQtDarkTheme
+- Documentation: https://pyqtdarktheme.readthedocs.io
+"""
+from libs.qdarktheme.main import __version__, clear_cache, get_themes, load_palette, load_stylesheet
diff --git a/libs/qdarktheme/main.py b/libs/qdarktheme/main.py
new file mode 100644
index 00000000..7c8b2f6c
--- /dev/null
+++ b/libs/qdarktheme/main.py
@@ -0,0 +1,251 @@
+"""Main file of qdarktheme."""
+from __future__ import annotations
+
+import json
+import platform
+import re
+import shutil
+from pathlib import Path
+
+from libs.qdarktheme.qtpy import __version__ as qt_version
+from libs.qdarktheme.qtpy.qt_compat import QT_API
+from libs.qdarktheme.util import OPERATORS, compare_v, get_logger, multi_replace
+
+# Version of PyQtDarkTheme
+__version__ = "1.1.1"
+
+_logger = get_logger(__name__)
+
+if qt_version is None:
+ _logger.warning("Failed to detect Qt version. Load Qt version as the latest version.")
+ _qt_version = "10.0.0" # Fairly future version for always setting latest version.
+else:
+ _qt_version = qt_version
+
+if QT_API is None:
+ _qt_api = "PySide6"
+ _logger.warning(f"Failed to detect Qt binding. Load Qt API as '{_qt_api}'.")
+else:
+ _qt_api = QT_API
+
+if None in [qt_version, QT_API]:
+ _logger.warning(
+ "Maybe you need to install qt-binding. Available Qt-binding packages: PySide6, PyQt6, PyQt5, PySide2."
+ )
+
+_RESOURCE_HOME_DIR = Path.home() / ".qdarktheme"
+_RESOURCES_BASE_DIR = _RESOURCE_HOME_DIR / f"v{__version__}"
+
+# Pattern
+_PATTERN_RADIUS = re.compile(r"\$radius\{[\s\S]*?\}")
+_PATTERN_ENV_PATCH = re.compile(r"\$env_patch\{[\s\S]*?\}")
+
+
+def _build_svg_files(theme: str, theme_resources_dir: Path) -> None:
+ svg_resources_dir = theme_resources_dir / "svg"
+ if not svg_resources_dir.exists():
+ svg_resources_dir.mkdir()
+ else:
+ return
+
+ if theme == "dark":
+ from libs.qdarktheme.themes.dark.svg import SVG_RESOURCES
+ else:
+ from libs.qdarktheme.themes.light.svg import SVG_RESOURCES
+
+ for file_name, code in json.loads(SVG_RESOURCES).items():
+ (svg_resources_dir / f"{file_name}.svg").write_text(code)
+
+
+def get_themes() -> tuple[str, ...]:
+ """Return available theme list.
+
+ Returns:
+ Available themes.
+ """
+ from libs.qdarktheme.themes import THEMES
+
+ return THEMES
+
+
+def _replace_rounded(match: re.Match) -> str:
+ return match.group().replace("$radius{", "").replace("}", "")
+
+
+def _replace_sharp(match: re.Match) -> str:
+ return _PATTERN_RADIUS.sub("0", match.group())
+
+
+def _parse_radius(stylesheet: str, border: str = "rounded") -> dict[str, str]:
+ """Parse `$radius{...}` placeholder in template stylesheet."""
+ matches = _PATTERN_RADIUS.finditer(stylesheet)
+ replace = _replace_rounded if border == "rounded" else _replace_sharp
+ return {match.group(): replace(match) for match in matches}
+
+
+def _parse_env_patch(stylesheet: str) -> dict[str, str]:
+ """Parse `$env_patch{...}` placeholder in template stylesheet.
+
+ Template stylesheet has `$env_patch{...}` symbol.
+ This symbol has json string and resolve the differences of the style between qt versions.
+ The json keys:
+ * version - the qt version and qualifier. Available qualifiers: [==, !=, >=, <=, >, <].
+ * qt - the name of qt binding.
+ * value - the qt stylesheet string
+
+ Args:
+ stylesheet: The qt stylesheet string.
+
+ Raises:
+ SyntaxError: If the version operator in version key of `$env_patch{...}` is wrong.
+
+ Returns:
+ The dictionary. Key is the text of $env_patch{...} symbol.
+ Value is the value of the `value` key in $env_patch.
+ """
+ replacements: dict[str, str] = {}
+ for match in re.finditer(_PATTERN_ENV_PATCH, stylesheet):
+ match_text = match.group()
+ json_text = match_text.replace("$env_patch", "")
+ env_property: dict[str, str] = json.loads(json_text)
+
+ patch_version = env_property.get("version")
+ patch_qt = env_property.get("qt")
+ patch_os = env_property.get("os")
+ patch_value = env_property["value"]
+
+ results: list[bool] = []
+ # Parse version
+ if patch_version is not None:
+ for operator in OPERATORS:
+ if operator not in patch_version:
+ continue
+ version = patch_version.replace(operator, "")
+ results.append(compare_v(_qt_version, operator, version))
+ break
+ else:
+ raise SyntaxError(
+ f"invalid character in qualifier. Available qualifiers {list(OPERATORS.keys())}"
+ ) from None
+ # Parse qt binding
+ if patch_qt is not None:
+ if QT_API is None:
+ results.append(False)
+ results.append(patch_qt.lower() == _qt_api.lower())
+ # Parse os
+ if patch_os is not None:
+ results.append(platform.system().lower() in patch_os.lower())
+
+ replacements[match_text] = patch_value if all(results) else ""
+ return replacements
+
+
+def load_stylesheet(theme: str = "dark", border: str = "rounded") -> str:
+ """Load the style sheet which looks like flat design. There are two themes, dark theme and light theme.
+
+ Args:
+ theme: The name of the theme. Available themes are "dark" and "light".
+ border: The border style. Available styles are "rounded" and "sharp".
+
+ Raises:
+ TypeError: If the arg of theme name is wrong.
+
+ Returns:
+ The stylesheet string for the given theme.
+
+ Examples:
+ Set stylesheet to your Qt application.
+
+ 1. Dark Theme::
+
+ app = QApplication([])
+ app.setStyleSheet(qdarktheme.load_stylesheet())
+ # or
+ app.setStyleSheet(qdarktheme.load_stylesheet("dark"))
+
+ 2. Light Theme::
+
+ app = QApplication([])
+ app.setStyleSheet(qdarktheme.load_stylesheet("light"))
+
+ Change sharp frame.
+
+ Sharp Frame::
+
+ app = QApplication([])
+ app.setStyleSheet(qdarktheme.load_stylesheet(border="sharp"))
+ """
+ if theme not in get_themes():
+ raise TypeError("The argument [theme] can only be specified as 'dark' or 'light'.") from None
+
+ if border not in ("rounded", "sharp"):
+ raise TypeError("The argument [border] can only be specified as 'rounded' or 'sharp'.")
+
+ theme_resources_dir = _RESOURCES_BASE_DIR / theme
+ theme_resources_dir.mkdir(parents=True, exist_ok=True)
+ _build_svg_files(theme, theme_resources_dir)
+
+ if theme == "dark":
+ from libs.qdarktheme.themes.dark.stylesheet import STYLE_SHEET
+ else:
+ from libs.qdarktheme.themes.light.stylesheet import STYLE_SHEET
+
+ # Build stylesheet
+ # Radius
+ replacements_radius = _parse_radius(STYLE_SHEET, border)
+ stylesheet = multi_replace(STYLE_SHEET, replacements_radius)
+ # Env
+ replacements_env = _parse_env_patch(stylesheet)
+ # Path
+ replacements_env["${path}"] = _RESOURCES_BASE_DIR.as_posix()
+ return multi_replace(stylesheet, replacements_env)
+
+
+def clear_cache():
+ """Clear the caches in system home path.
+
+ PyQtDarkTheme build the caches of resources in the system home path.You can clear the caches by running this
+ method.
+ """
+ try:
+ shutil.rmtree(_RESOURCE_HOME_DIR)
+ _logger.info(f"The caches({_RESOURCE_HOME_DIR}) has been deleted")
+ except FileNotFoundError:
+ _logger.info("There is no caches")
+
+
+def load_palette(theme: str = "dark"):
+ """Load the QPalette for the dark or light theme.
+
+ Args:
+ theme: The name of the theme. Available theme are "dark" and "light".
+
+ Raises:
+ TypeError: If the arg name of theme is wrong.
+
+ Returns:
+ QPalette: The QPalette for the given theme.
+
+ Examples:
+ Set QPalette to your Qt application.
+
+ 1. Dark Theme::
+
+ app = QApplication([])
+ app.setPalette(qdarktheme.load_palette())
+ # or
+ app.setPalette(qdarktheme.load_palette("dark"))
+
+ 2. Light Theme::
+
+ app = QApplication([])
+ app.setPalette(qdarktheme.load_palette("light"))
+ """
+ if theme not in get_themes():
+ raise TypeError("The argument [theme] can only be specified as 'dark' or 'light'.") from None
+
+ if theme == "dark":
+ from libs.qdarktheme.themes.dark.palette import PALETTE
+ else:
+ from libs.qdarktheme.themes.light.palette import PALETTE
+ return PALETTE
diff --git a/libs/qdarktheme/qtpy/QtCore/__init__.py b/libs/qdarktheme/qtpy/QtCore/__init__.py
new file mode 100644
index 00000000..410f2546
--- /dev/null
+++ b/libs/qdarktheme/qtpy/QtCore/__init__.py
@@ -0,0 +1,19 @@
+"""Module for QtCore."""
+from libs.qdarktheme.qtpy.qt_compat import QT_API, qt_import_error
+
+if QT_API is None:
+ raise qt_import_error
+if QT_API == "PySide6":
+ from PySide6.QtCore import * # type: ignore # noqa: F403
+elif QT_API == "PyQt6":
+ from PyQt6.QtCore import * # type: ignore # noqa: F403
+
+ Slot = pyqtSlot # noqa: F405
+ Signal = pyqtSignal # noqa: F405
+elif QT_API == "PyQt5":
+ from PyQt5.QtCore import * # type: ignore # noqa: F403
+
+ Slot = pyqtSlot # noqa: F405
+ Signal = pyqtSignal # noqa: F405
+elif QT_API == "PySide2":
+ from PySide2.QtCore import * # type: ignore # noqa: F403
diff --git a/libs/qdarktheme/qtpy/QtGui/__init__.py b/libs/qdarktheme/qtpy/QtGui/__init__.py
new file mode 100644
index 00000000..b14cb747
--- /dev/null
+++ b/libs/qdarktheme/qtpy/QtGui/__init__.py
@@ -0,0 +1,20 @@
+"""Module for QtGui."""
+from libs.qdarktheme.qtpy.qt_compat import QT_API, qt_import_error
+
+if QT_API is None:
+ raise qt_import_error
+if QT_API == "PySide6":
+ from PySide6.QtGui import * # type: ignore # noqa: F403
+elif QT_API == "PyQt6":
+ from PyQt6.QtGui import * # type: ignore # noqa: F403
+elif QT_API == "PyQt5":
+ from PyQt5.QtGui import * # type: ignore # noqa: F403
+ from PyQt5.QtWidgets import QAction, QActionGroup, QShortcut # type: ignore
+elif QT_API == "PySide2":
+ from PySide2.QtGui import * # type: ignore # noqa: F403
+ from PySide2.QtWidgets import QAction, QActionGroup, QShortcut # type: ignore
+
+if QT_API in ["PyQt5", "PySide2"]:
+ QAction = QAction # type: ignore # noqa: SIM909
+ QActionGroup = QActionGroup # type: ignore # noqa: SIM909
+ QShortcut = QShortcut # type: ignore # noqa: SIM909
diff --git a/libs/qdarktheme/qtpy/QtSvg/__init__.py b/libs/qdarktheme/qtpy/QtSvg/__init__.py
new file mode 100644
index 00000000..edabd64d
--- /dev/null
+++ b/libs/qdarktheme/qtpy/QtSvg/__init__.py
@@ -0,0 +1,13 @@
+"""Module for QtSvg."""
+from libs.qdarktheme.qtpy.qt_compat import QT_API, qt_import_error
+
+if QT_API is None:
+ raise qt_import_error
+if QT_API == "PySide6":
+ from PySide6.QtSvg import * # type: ignore # noqa: F403
+elif QT_API == "PyQt6":
+ from PyQt6.QtSvg import * # type: ignore # noqa: F403
+elif QT_API == "PyQt5":
+ from PyQt5.QtSvg import * # type: ignore # noqa: F403
+elif QT_API == "PySide2":
+ from PySide2.QtSvg import * # type: ignore # noqa: F403
diff --git a/libs/qdarktheme/qtpy/QtWidgets/__init__.py b/libs/qdarktheme/qtpy/QtWidgets/__init__.py
new file mode 100644
index 00000000..1dfdf6a0
--- /dev/null
+++ b/libs/qdarktheme/qtpy/QtWidgets/__init__.py
@@ -0,0 +1,50 @@
+"""Module for QtWidgets."""
+from __future__ import annotations
+
+from collections.abc import Sequence
+
+from libs.qdarktheme.qtpy.qt_compat import QT_API
+from libs.qdarktheme.qtpy.QtCore import Qt
+from libs.qdarktheme.qtpy.QtGui import QPalette
+
+if QT_API == "PySide6":
+ from PySide6.QtWidgets import * # type: ignore # noqa: F403
+elif QT_API == "PyQt6":
+ from PyQt6.QtWidgets import * # type: ignore # noqa: F403
+elif QT_API == "PyQt5":
+ from PyQt5.QtWidgets import * # type: ignore # noqa: F403
+elif QT_API == "PySide2":
+ from PySide2.QtWidgets import * # type: ignore # noqa: F403
+
+
+class Application(QApplication): # type: ignore # noqa: F405
+ """Override QApplication."""
+
+ def __init__(self, args: Sequence[str] | None = None) -> None:
+ """Override QApplication method."""
+ super().__init__(args)
+
+ def exec(self) -> int:
+ """Override QApplication method."""
+ if hasattr(super(), "exec"):
+ return super().exec()
+ return super().exec_()
+
+ def exit(self, returnCode: int = 0) -> None: # noqa: N803
+ """Override QApplication method."""
+ return super().exit(returnCode)
+
+ def setStyleSheet(self, sheet: str) -> None: # noqa: N802
+ """Override QApplication method."""
+ return super().setStyleSheet(sheet)
+
+ def setAttribute(self, attribute: Qt.ApplicationAttribute, on: bool = True) -> None: # noqa: N802
+ """Override QApplication method."""
+ super().setAttribute(attribute, on)
+
+ def setPalette(self, palette: QPalette, className: str | None = None) -> None: # noqa: N802, N803
+ """Override QApplication method."""
+ super().setPalette(palette, className)
+
+
+QApplication = Application
diff --git a/libs/qdarktheme/qtpy/__init__.py b/libs/qdarktheme/qtpy/__init__.py
new file mode 100644
index 00000000..7085216b
--- /dev/null
+++ b/libs/qdarktheme/qtpy/__init__.py
@@ -0,0 +1,11 @@
+"""Package applying Qt compat of PyQt6, PySide6, PyQt5 and PySide2."""
+from libs.qdarktheme.qtpy.qt_compat import QtImportError
+from libs.qdarktheme.qtpy.qt_version import __version__
+
+try:
+ from libs.qdarktheme.qtpy import QtCore, QtGui, QtSvg, QtWidgets
+except ImportError:
+ from libs.qdarktheme.util import get_logger as __get_logger
+
+ __logger = __get_logger(__name__)
+ __logger.warning("Failed to import QtCore, QtGui, QtSvg and QtWidgets.")
diff --git a/libs/qdarktheme/qtpy/qt_compat.py b/libs/qdarktheme/qtpy/qt_compat.py
new file mode 100644
index 00000000..58ae5e25
--- /dev/null
+++ b/libs/qdarktheme/qtpy/qt_compat.py
@@ -0,0 +1,82 @@
+"""Module for Qt compat."""
+from __future__ import annotations
+
+import os
+import sys
+
+
+class QtImportError(ImportError):
+ """Error raise if no bindings could be selected."""
+
+ pass
+
+
+qt_import_error = QtImportError(
+ "Failed to import qt-binding. Check packages(pip list)."
+ "\n\tAvailable Qt-binding packages: PySide6, PyQt6, PyQt5, PySide2."
+)
+
+
+# Qt6
+_QT_API_PYSIDE6 = "PySide6"
+_QT_API_PYQT6 = "PyQt6"
+# Qt5
+_QT_API_PYQT5 = "PyQt5"
+_QT_API_PYSIDE2 = "PySide2"
+
+
+_API_LIST = [_QT_API_PYSIDE6, _QT_API_PYQT6, _QT_API_PYQT5, _QT_API_PYSIDE2]
+
+
+def _get_loaded_api() -> str | None:
+ """Return which API is loaded.
+
+ If this returns anything besides None,
+ importing any other Qt-binding is unsafe.
+ """
+ for api in _API_LIST:
+ if sys.modules.get(f"{api}.QtCore"):
+ return api
+ return None
+
+
+def _get_environ_api() -> str | None:
+ """Return which API is specified in environ."""
+ _qt_api_env = os.environ.get("QT_API")
+ if _qt_api_env is not None:
+ _qt_api_env = _qt_api_env.lower()
+
+ _env_to_module = {
+ "pyside6": _QT_API_PYSIDE6,
+ "pyqt6": _QT_API_PYQT6,
+ "pyqt5": _QT_API_PYQT5,
+ "pyside2": _QT_API_PYSIDE2,
+ None: None,
+ }
+ try:
+ return _env_to_module[_qt_api_env]
+ except KeyError:
+ raise KeyError(
+ "The environment variable QT_API has the unrecognized value "
+ f"{_qt_api_env!r}. "
+ f"Valid values are {[k for k in _env_to_module if k is not None]}"
+ ) from None
+
+
+def _get_installed_api() -> str | None:
+ """Return which API is installed."""
+ # Fix [AttributeError: module 'importlib' has no attribute 'util']
+ # See https://stackoverflow.com/a/39661116/13452582
+ from importlib import util
+
+ for api in _API_LIST:
+ if util.find_spec(api) is not None:
+ return api
+ return None
+
+
+QT_API = _get_loaded_api()
+if QT_API is None:
+ QT_API = _get_environ_api()
+if QT_API is None:
+ QT_API = _get_installed_api()
diff --git a/libs/qdarktheme/qtpy/qt_version.py b/libs/qdarktheme/qtpy/qt_version.py
new file mode 100644
index 00000000..ed9ac257
--- /dev/null
+++ b/libs/qdarktheme/qtpy/qt_version.py
@@ -0,0 +1,18 @@
+"""Module for detecting Qt version."""
+from __future__ import annotations
+
+from libs.qdarktheme.qtpy.qt_compat import QT_API
+
+__version__: str | None = None
+if QT_API == "PySide6":
+ from PySide6 import __version__ # type: ignore
+elif QT_API == "PyQt6":
+ from PyQt6.QtCore import PYQT_VERSION_STR # type: ignore
+
+ __version__ = PYQT_VERSION_STR
+elif QT_API == "PyQt5":
+ from PyQt5.QtCore import PYQT_VERSION_STR # type: ignore
+
+ __version__ = PYQT_VERSION_STR
+elif QT_API == "PySide2":
+ from PySide2 import __version__ # type: ignore # noqa: F401
diff --git a/libs/qdarktheme/themes/__init__.py b/libs/qdarktheme/themes/__init__.py
new file mode 100644
index 00000000..eb8d45d3
--- /dev/null
+++ b/libs/qdarktheme/themes/__init__.py
@@ -0,0 +1,45 @@
+"""Package including resources.
+
+**Warning**
+
+This package created programmatically. All changes made in this file will be lost!
+Created by the `qdarktheme/tools/build_resources`.
+
+
+License Information
+===================
+
+Material design icons
+---------------------
+
+All svg files in PyQtDarkTheme is from Material design icons(which uses an Apache 2.0 license).
+
+- Author: Google
+- Site: https://fonts.google.com/icons
+- Source: https://github.com/google/material-design-icons
+- License: Apache License Version 2.0 | https://www.apache.org/licenses/LICENSE-2.0.txt
+
+Modifications made to each files to change the icon color and angle and remove svg namespace.
+
+The current Material design icons license summary can be viewed at:
+https://github.com/google/material-design-icons/blob/master/LICENSE
+
+
+QDarkStyleSheet(Source code)
+----------------------------
+
+Qt stylesheets are originally fork of QDarkStyleSheet(MIT License).
+
+- Author: Colin Duquesnoy
+- Site: https://github.com/ColinDuquesnoy/QDarkStyleSheet
+- Source: https://github.com/ColinDuquesnoy/QDarkStyleSheet
+- License: MIT License | https://opensource.org/licenses/MIT
+
+Modifications made to a file to change the style.
+
+The current QDarkStyleSheet license summary can be viewed at:
+https://github.com/ColinDuquesnoy/QDarkStyleSheet/blob/master/LICENSE.rst
+
+"""
+
+THEMES = ("dark", "light")
diff --git a/libs/qdarktheme/themes/dark/__init__.py b/libs/qdarktheme/themes/dark/__init__.py
new file mode 100644
index 00000000..ef5fe371
--- /dev/null
+++ b/libs/qdarktheme/themes/dark/__init__.py
@@ -0,0 +1 @@
+"""Package containing the resources for dark theme."""
diff --git a/libs/qdarktheme/themes/dark/palette.py b/libs/qdarktheme/themes/dark/palette.py
new file mode 100644
index 00000000..578d8a7a
--- /dev/null
+++ b/libs/qdarktheme/themes/dark/palette.py
@@ -0,0 +1,45 @@
+"""Module loading QPalette."""
+from libs.qdarktheme.qtpy.QtGui import QColor, QPalette
+
+_palette = QPalette()
+
+# base
+_palette.setColor(QPalette.ColorRole.WindowText, QColor("#e4e7eb"))
+_palette.setColor(QPalette.ColorRole.Button, QColor("#202124"))
+_palette.setColor(QPalette.ColorRole.Text, QColor("#eff1f1"))
+_palette.setColor(QPalette.ColorRole.ButtonText, QColor("#8ab4f7"))
+_palette.setColor(QPalette.ColorRole.Base, QColor("#202124"))
+_palette.setColor(QPalette.ColorRole.Window, QColor("#202124"))
+_palette.setColor(QPalette.ColorRole.Highlight, QColor("#8ab4f7"))
+_palette.setColor(QPalette.ColorRole.HighlightedText, QColor("#202124"))
+_palette.setColor(QPalette.ColorRole.Link, QColor("#202124"))
+_palette.setColor(QPalette.ColorRole.AlternateBase, QColor("#292b2e"))
+_palette.setColor(QPalette.ColorRole.ToolTipBase, QColor("#292a2d"))
+_palette.setColor(QPalette.ColorRole.ToolTipText, QColor("#e4e7eb"))
+_palette.setColor(QPalette.ColorRole.LinkVisited, QColor("#c58af8"))
+_palette.setColor(QPalette.ColorRole.ToolTipText, QColor("#292a2d"))
+_palette.setColor(QPalette.ColorRole.ToolTipBase, QColor("#e4e7eb"))
+if hasattr(QPalette.ColorRole, "Foreground"):
+ _palette.setColor(QPalette.ColorRole.Foreground, QColor("#e4e7eb")) # type: ignore
+if hasattr(QPalette.ColorRole, "PlaceholderText"):
+ _palette.setColor(QPalette.ColorRole.PlaceholderText, QColor("#8a8b8d"))
+
+_palette.setColor(QPalette.ColorRole.Light, QColor("#3f4042"))
+_palette.setColor(QPalette.ColorRole.Midlight, QColor("#3f4042"))
+_palette.setColor(QPalette.ColorRole.Dark, QColor("#e4e7eb"))
+_palette.setColor(QPalette.ColorRole.Mid, QColor("#3f4042"))
+_palette.setColor(QPalette.ColorRole.Shadow, QColor("#3f4042"))
+
+# disabled
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.WindowText, QColor("#697177"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, QColor("#697177"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, QColor("#3f4042"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Highlight, QColor("#53575b"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.HighlightedText, QColor("#697177"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Link, QColor("#697177"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.LinkVisited, QColor("#697177"))
+
+# inactive
+_palette.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Highlight, QColor("#393d41"))
+
+PALETTE = _palette
diff --git a/libs/qdarktheme/themes/dark/stylesheet.py b/libs/qdarktheme/themes/dark/stylesheet.py
new file mode 100644
index 00000000..acfa4dfa
--- /dev/null
+++ b/libs/qdarktheme/themes/dark/stylesheet.py
@@ -0,0 +1,1097 @@
+"""Contents that define stylesheet for dark theme."""
+
+STYLE_SHEET = """
+* {
+ padding: 0;
+ margin: 0;
+ border: none;
+ border-style: none;
+ border-image: unset;
+ outline: none;
+}
+QToolBar * {
+ margin: 0;
+ padding: 0;
+}
+QWidget {
+ background: #202124;
+ color: #e4e7eb;
+ selection-background-color: #8ab4f7;
+ selection-color: #202124;
+}
+QWidget:disabled {
+ color: #697177;
+ selection-background-color: #53575b;
+ selection-color: #697177;
+}
+QWidget {
+ backward-icon: url(${path}/dark/svg/arrow_upward__icon-foreground__rotate-270.svg);
+ forward-icon: url(${path}/dark/svg/arrow_upward__icon-foreground__rotate-90.svg);
+ leftarrow-icon: url(${path}/dark/svg/arrow_upward__icon-foreground__rotate-270.svg);
+ rightarrow-icon: url(${path}/dark/svg/arrow_upward__icon-foreground__rotate-90.svg);
+ dialog-ok-icon: url(${path}/dark/svg/check__icon-foreground.svg);
+ dialog-cancel-icon: url(${path}/dark/svg/close__icon-foreground.svg);
+ dialog-yes-icon: url(${path}/dark/svg/check_circle__icon-foreground.svg);
+ dialog-no-icon: url(${path}/dark/svg/cancel__icon-foreground.svg);
+ dialog-apply-icon: url(${path}/dark/svg/check__icon-foreground.svg);
+ dialog-reset-icon: url(${path}/dark/svg/restart_alt__icon-foreground.svg);
+ dialog-save-icon: url(${path}/dark/svg/save__icon-foreground.svg);
+ dialog-discard-icon: url(${path}/dark/svg/delete__icon-foreground.svg);
+ dialog-close-icon: url(${path}/dark/svg/close__icon-foreground.svg);
+ dialog-open-icon: url(${path}/dark/svg/folder_open__icon-foreground.svg);
+ dialog-help-icon: url(${path}/dark/svg/help__icon-foreground.svg);
+ filedialog-parent-directory-icon: url(${path}/dark/svg/arrow_upward__icon-foreground.svg);
+ filedialog-new-directory-icon: url(${path}/dark/svg/create_new_folder__icon-foreground.svg);
+ titlebar-close-icon: url(${path}/dark/svg/close__icon-foreground.svg);
+ titlebar-normal-icon: url(${path}/dark/svg/flip_to_front__icon-foreground.svg);
+}
+QCommandLinkButton {
+ qproperty-icon: url(${path}/dark/svg/east__highlight.svg);
+}
+QMainWindow::separator {
+ width: 4px;
+ height: 4px;
+ background: #3f4042;
+}
+QMainWindow::separator:hover,
+QMainWindow::separator:pressed {
+ background: #8ab4f7;
+}
+QToolTip {
+ background: #292a2d;
+ color: #e4e7eb;
+ border: 1px solid #3f4042;
+}
+QSizeGrip {
+ width: 0;
+ height: 0;
+ image: none;
+}
+QStatusBar {
+ background: #2a2b2e;
+}
+QStatusBar::item {
+ border: none;
+}
+QStatusBar QWidget {
+ background: transparent;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QStatusBar > .QSizeGrip {
+ padding: 0;
+}
+QStatusBar QWidget:hover {
+ background: #44464a;
+}
+QStatusBar QWidget:pressed,
+QStatusBar QWidget:checked {
+ background: #4f5054;
+}
+QStatusBar QWidget:disabled {
+ background: #202124;
+}
+QCheckBox,
+QRadioButton {
+ border-top: 2px solid transparent;
+ border-bottom: 2px solid transparent;
+}
+QCheckBox:!window,
+QRadioButton:!window {
+ background: transparent;
+}
+QCheckBox:hover,
+QRadioButton:hover {
+ border-bottom: 2px solid #8ab4f7;
+}
+QGroupBox {
+ font-weight: bold;
+ border: 1px solid #3f4042;
+ margin-top: 8px;
+ padding: 2px 1px 1px 1px;
+ border-radius: $radius{4px};
+}
+QGroupBox::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ left: 7px;
+ margin: 0 2px 0 3px;
+}
+QGroupBox:flat {
+ border-color: transparent;
+}
+QMenuBar {
+ background: #202124;
+ padding: 2px;
+ border-bottom: 1px solid #3f4042;
+}
+QMenuBar::item {
+ background: transparent;
+ padding: 4px;
+}
+QMenuBar::item:selected {
+ padding: 4px;
+ background: #44464d;
+ border-radius: $radius{4px};
+}
+QMenuBar::item:pressed {
+ padding: 4px;
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+QToolBar {
+ background: #333333;
+ padding: 1px;
+ font-weight: bold;
+ spacing: 2px;
+ margin: 1px;
+}
+QToolBar::handle:horizontal {
+ width: 20px;
+ image: url(${path}/dark/svg/drag_indicator_horizontal__icon-foreground.svg);
+}
+QToolBar::handle:vertical {
+ height: 20px;
+ image: url(${path}/dark/svg/drag_indicator_horizontal__icon-foreground__rotate-90.svg);
+}
+QToolBar::separator {
+ background: #3f4042;
+}
+QToolBar::separator:horizontal {
+ width: 2px;
+ margin: 0 6px;
+}
+QToolBar::separator:vertical {
+ height: 2px;
+ margin: 6px 0;
+}
+QToolBar > QToolButton {
+ background: transparent;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QToolBar > QToolButton:hover,
+QToolBar > QToolButton::menu-button:hover {
+ background: #44464a;
+}
+QToolBar > QToolButton:pressed,
+QToolBar > QToolButton::menu-button:pressed,
+QToolBar > QToolButton:checked {
+ background: #4f5054;
+}
+QToolBar > QToolButton#qt_toolbar_ext_button {
+ image: url(${path}/dark/svg/double_arrow__icon-foreground.svg);
+ $env_patch{"os": "Windows", "value": "padding: 0; qproperty-icon: unset"};
+}
+QToolBar > QToolButton#qt_toolbar_ext_button:disabled {
+ image: url(${path}/dark/svg/double_arrow__icon-foreground-disabled.svg);
+}
+QToolBar > QWidget {
+ background: transparent;
+}
+QMenu {
+ background: #292a2d;
+ padding: 8px 0;
+ border: 1px solid #3f4042;
+}
+QMenu::separator {
+ margin: 4px 0;
+ height: 1px;
+ background: #3f4042;
+}
+QMenu::item {
+ padding: 4px 28px;
+}
+QMenu::item:selected {
+ background: #3f4042;
+}
+QMenu::icon {
+ padding-left: 10px;
+ width: 14px;
+ height: 14px;
+}
+QMenu::right-arrow {
+ margin: 2px;
+ padding-left: 12px;
+ height: 20px;
+ width: 20px;
+ image: url(${path}/dark/svg/chevron_right__icon-foreground.svg);
+}
+QMenu::right-arrow:disabled {
+ image: url(${path}/dark/svg/chevron_right__icon-foreground-disabled.svg);
+}
+QScrollBar {
+ background: #292b2e;
+ $env_patch{"os": "Darwin", "value": "background: transparent"};
+ border-radius: $radius{4px};
+}
+QScrollBar:horizontal {
+ height: 14px;
+ $env_patch{"os": "Darwin", "value": "height: 7px;"};
+}
+QScrollBar:vertical {
+ width: 14px;
+ $env_patch{"os": "Darwin", "value": "width: 7px;"};
+}
+QScrollBar::handle {
+ background: rgba(84.000, 86.000, 86.000, 0.737);
+ border-radius: $radius{3px};
+}
+QScrollBar::handle:hover {
+ background: rgba(114.000, 115.000, 115.000, 0.827);
+}
+QScrollBar::handle:pressed {
+ background: rgba(143.000, 145.000, 145.000, 0.933);
+}
+QScrollBar::handle:disabled {
+ background-color: #3b3e43;
+}
+QScrollBar::handle:horizontal {
+ min-width: 8px;
+ margin: 4px 14px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:horizontal:hover {
+ margin: 2px 14px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:vertical {
+ min-height: 8px;
+ margin: 14px 4px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:vertical:hover {
+ margin: 14px 2px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::sub-page, QScrollBar::add-page {
+ background: transparent;
+}
+QScrollBar::sub-line,
+QScrollBar::add-line {
+ background: transparent;
+ width: 14px;
+ height: 14px;
+ margin: 2px;
+ subcontrol-origin: margin;
+ $env_patch{"os": "Darwin", "value": "width: 0; height: 0; margin: 0"};
+}
+QScrollBar::sub-line:vertical {
+ subcontrol-position: top;
+}
+QScrollBar::add-line:vertical {
+ subcontrol-position: bottom;
+}
+QScrollBar::sub-line:horizontal {
+ subcontrol-position: left;
+}
+QScrollBar::add-line:horizontal {
+ subcontrol-position: right;
+}
+QScrollBar::up-arrow {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle.svg);
+}
+QScrollBar::right-arrow {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle__rotate-90.svg);
+}
+QScrollBar::down-arrow {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle__rotate-180.svg);
+}
+QScrollBar::left-arrow {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle__rotate-270.svg);
+}
+QScrollBar::up-arrow:hover {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle-pressed.svg);
+}
+QScrollBar::right-arrow:hover {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-90.svg);
+}
+QScrollBar::down-arrow:hover {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-180.svg);
+}
+QScrollBar::left-arrow:hover {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-270.svg);
+}
+QScrollBar::up-arrow:disabled {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-disabled.svg);
+}
+QScrollBar::right-arrow:disabled {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-disabled__rotate-90.svg);
+}
+QScrollBar::down-arrow:disabled {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-disabled__rotate-180.svg);
+}
+QScrollBar::left-arrow:disabled {
+ image: url(${path}/dark/svg/arrow_drop_up__scrollbar-disabled__rotate-270.svg);
+}
+QProgressBar {
+ border: 1px solid #3f4042;
+ text-align: center;
+ color: #e4e7eb;
+ border-radius: $radius{4px};
+}
+QProgressBar::chunk {
+ background: #8ab4f7;
+ border-radius: $radius{3px};
+}
+QProgressBar::chunk:disabled {
+ background: #53575b;
+}
+QPushButton {
+ color: #8ab4f7;
+ border: 1px solid #3f4042;
+ padding: 4px 8px;
+ border-radius: $radius{4px};
+}
+QPushButton:!window {
+ background: transparent;
+}
+QPushButton:flat,
+QPushButton:default {
+ border: none;
+ padding: 5px 9px;
+}
+QPushButton:default {
+ color: #202124;
+ background: #8ab4f7;
+}
+QPushButton:hover,
+QPushButton:flat:hover {
+ background: rgba(46.000, 70.000, 94.000, 0.333);
+}
+QPushButton:pressed,
+QPushButton:flat:pressed,
+QPushButton:checked:pressed,
+QPushButton:flat:checked:pressed {
+ background: rgba(46.000, 70.000, 94.000, 0.933);
+}
+QPushButton:checked,
+QPushButton:flat:checked {
+ background: rgba(46.000, 70.000, 94.000, 0.733);
+}
+QPushButton:default:hover {
+ background: #7fa7e5;
+}
+QPushButton:default:pressed {
+ background: #6d8bbe;
+}
+QPushButton:default:disabled {
+ background: #53575b;
+}
+QDialogButtonBox QPushButton {
+ min-width: 65px;
+}
+QToolButton {
+ background: transparent;
+ padding: 5px;
+ spacing: 2px;
+ border-radius: $radius{2px};
+}
+QToolButton:hover,
+QToolButton::menu-button:hover {
+ background: rgba(46.000, 70.000, 94.000, 0.333);
+}
+QToolButton:pressed,
+QToolButton:checked:pressed,
+QToolButton::menu-button:pressed {
+ background: rgba(46.000, 70.000, 94.000, 0.933);
+}
+QToolButton:selected,
+QToolButton:checked {
+ background: rgba(46.000, 70.000, 94.000, 0.733);
+}
+QToolButton::checked:disabled {
+ background: #3f4042;
+}
+QToolButton::menu-indicator {
+ height: 18px;
+ width: 18px;
+ top: 6px;
+ left: 3px;
+ image: url(${path}/dark/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QToolButton::menu-indicator:disabled {
+ image: url(${path}/dark/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QToolButton::menu-arrow {
+ image: unset;
+}
+QToolButton::menu-button {
+ subcontrol-origin: margin;
+ border: none;
+ width: 17px;
+ border-top-right-radius: $radius{4px};
+ border-bottom-right-radius: $radius{4px};
+ image: url(${path}/dark/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QToolButton::menu-button:disabled {
+ image: url(${path}/dark/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QToolButton[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "popupMode=MenuButtonPopup"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "popupMode=\\\"1\\\""}
+$env_patch{"version": ">=6.0.0", "value": "popupMode=MenuButtonPopup"}
+] {
+ padding-right: 1px;
+ margin-right: 18px;
+ border-top-right-radius: $radius{0};
+ border-bottom-right-radius: $radius{0};
+}
+QComboBox {
+ border: 1px solid #3f4042;
+ min-height: 1.5em;
+ padding: 0 4px;
+ background: #3f4042;
+ border-radius: $radius{4px};
+}
+QComboBox:focus,
+QComboBox:open {
+ border: 1px solid #8ab4f7;
+}
+QComboBox::drop-down {
+ border: none;
+ padding-right: 4px;
+}
+QComboBox::down-arrow {
+ image: url(${path}/dark/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QComboBox::down-arrow:disabled {
+ image: url(${path}/dark/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QComboBox::item:selected {
+ border: none;
+ background: #004875;
+ color: #e4e7eb;
+}
+QComboBox QAbstractItemView {
+ background: #292a2d;
+ margin: 0;
+ border: 1px solid #3f4042;
+ selection-background-color: #004875;
+ selection-color: #e4e7eb;
+ padding: 2px;
+}
+QComboBox QAbstractItemView[
+$env_patch{"version": "<6.0.0", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border-color: #3f4042;
+}
+QSlider {
+ padding: 2px 0;
+}
+QSlider::groove {
+ border-radius: $radius{2px};
+}
+QSlider::groove:horizontal {
+ height: 4px;
+}
+QSlider::groove:vertical {
+ width: 4px;
+}
+QSlider::sub-page, QSlider::handle {
+ background: #8ab4f7;
+}
+QSlider::sub-page:disabled,
+QSlider::add-page:disabled,
+QSlider::handle:disabled {
+ background: #53575b;
+}
+QSlider::add-page {
+ background: #5b7193;
+}
+QSlider::handle:hover {
+ background: #7fa7e5;
+}
+QSlider::handle:pressed {
+ background: #6d8bbe;
+}
+QSlider::handle:horizontal {
+ width: 16px;
+ height: 8px;
+ margin: -6px 0;
+ border-radius: 8px;
+}
+QSlider::handle:vertical {
+ width: 8px;
+ height: 16px;
+ margin: 0 -6px;
+ border-radius: 8px;
+}
+QTabWidget::pane {
+ border: 1px solid #3f4042;
+ border-radius: $radius{4px};
+}
+QTabBar {
+ qproperty-drawBase: 0;
+}
+QTabBar::close-button:selected {
+ image: url(${path}/dark/svg/close__icon-foreground.svg);
+}
+QTabBar::close-button:!selected {
+ image: url(${path}/dark/svg/close__tabbar-button-unselected.svg)
+}
+QTabBar::close-button:disabled {
+ image: url(${path}/dark/svg/close__icon-foreground-disabled.svg);
+}
+QTabBar::close-button:hover {
+ background: #5580ad;
+ border-radius: $radius{4px};
+}
+QTabBar::close-button:hover:!selected {
+ background: #324763;
+}
+QTabBar::tab {
+ padding: 3px;
+}
+QTabBar::tab:hover {
+ background: rgba(46.000, 70.000, 94.000, 0.333);
+}
+QTabBar::tab:selected {
+ color: #8ab4f7;
+ background: rgba(46.000, 70.000, 94.000, 0.933);
+}
+QTabBar::tab:selected:disabled {
+ background: #53575b;
+ color: #697177;
+}
+QTabBar::tab:top {
+ border-bottom: 2px solid #3f4042;
+ margin-left: 4px;
+ border-top-left-radius: $radius{2px};
+ border-top-right-radius: $radius{2px};
+}
+QTabBar::tab:top:selected {
+ border-bottom: 2px solid #8ab4f7;
+}
+QTabBar::tab:top:hover {
+ border-color: #8ab4f7;
+}
+QTabBar::tab:top:selected:disabled {
+ border-color: #53575b;
+}
+QTabBar::tab:bottom {
+ border-top: 2px solid #3f4042;
+ margin-left: 4px;
+ border-bottom-left-radius: $radius{2px};
+ border-bottom-right-radius: $radius{2px};
+}
+QTabBar::tab:bottom:selected {
+ border-top: 2px solid #8ab4f7;
+}
+QTabBar::tab:bottom:hover {
+ border-color: #8ab4f7;
+}
+QTabBar::tab:bottom:selected:disabled {
+ border-color: #53575b;
+}
+QTabBar::tab:left {
+ border-right: 2px solid #3f4042;
+ margin-top: 4px;
+ border-top-left-radius: $radius{2px};
+ border-bottom-left-radius: $radius{2px};
+}
+QTabBar::tab:left:selected {
+ border-right: 2px solid #8ab4f7;
+}
+QTabBar::tab:left:hover {
+ border-color: #8ab4f7;
+}
+QTabBar::tab:left:selected:disabled {
+ border-color: #53575b;
+}
+QTabBar::tab:right {
+ border-left: 2px solid #3f4042;
+ margin-top: 4px;
+ border-top-right-radius: $radius{2px};
+ border-bottom-right-radius: $radius{2px};
+}
+QTabBar::tab:right:selected {
+ border-left: 2px solid #8ab4f7;
+}
+QTabBar::tab:right:hover {
+ border-color: #8ab4f7;
+}
+QTabBar::tab:right:selected:disabled {
+ border-color: #53575b;
+}
+QDockWidget {
+ border: 1px solid #3f4042;
+ border-radius: $radius{4px};
+}
+QDockWidget::title {
+ padding: 3px;
+ spacing: 4px;
+ background: #000000;
+}
+QDockWidget::close-button,
+QDockWidget::float-button {
+ border-radius: $radius{2px};
+}
+QDockWidget::close-button:hover,
+QDockWidget::float-button:hover {
+ background: rgba(46.000, 70.000, 94.000, 0.333);
+}
+QDockWidget::close-button:pressed,
+QDockWidget::float-button:pressed {
+ background: rgba(46.000, 70.000, 94.000, 0.933);
+}
+QFrame {
+ border: 1px solid #3f4042;
+ padding: 1px;
+ border-radius: $radius{4px};
+}
+.QFrame {
+ padding: 0;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=NoFrame"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border-color: transparent;
+ padding: 0;
+}
+.QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=NoFrame"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border: none;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=Panel"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"2\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=Panel"}
+] {
+ border-color: #323439;
+ background: #323439;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=HLine"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"4\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=HLine"}
+] {
+ max-height: 2px;
+ border: none;
+ background: #3f4042;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=VLine"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"5\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=VLine"}
+] {
+ max-width: 2px;
+ border: none;
+ background: #3f4042;
+}
+QLCDNumber {
+ color: #e4e7eb;
+ min-width: 2em;
+ margin: 2px;
+}
+QLabel:!window,
+QLCDNumber:!window {
+ background-color: transparent;
+}
+QToolBox:selected {
+ border: 2px solid #8ab4f7;
+}
+QToolBox::tab {
+ background: #000000;
+ border-bottom: 2px solid #3f4042;
+ border-top-left-radius: $radius{4px};
+ border-top-right-radius: $radius{4px};
+}
+QToolBox::tab:selected {
+ border-bottom: 2px solid #8ab4f7;
+}
+QToolBox::tab:selected:disabled {
+ border-bottom: 2px solid #53575b;
+}
+QSplitter::handle {
+ background: #3f4042;
+ margin: 1px 3px;
+}
+QSplitter::handle:hover {
+ background: #8ab4f7;
+}
+QSplitter::handle:horizontal {
+ width: 5px;
+ image: url(${path}/dark/svg/horizontal_rule__icon-foreground__rotate-90.svg);
+}
+QSplitter::handle:horizontal:disabled {
+ image: url(${path}/dark/svg/horizontal_rule__icon-foreground-disabled__rotate-90.svg);
+}
+QSplitter::handle:vertical {
+ height: 5px;
+ image: url(${path}/dark/svg/horizontal_rule__icon-foreground.svg);
+}
+QSplitter::handle:vertical:disabled {
+ image: url(${path}/dark/svg/horizontal_rule__icon-foreground-disabled.svg);
+}
+QSplitterHandle::item:hover {}
+QAbstractScrollArea {
+ selection-background-color: #004875;
+ selection-color: #e4e7eb;
+ margin: 1px;
+}
+QAbstractScrollArea:disabled {
+ selection-background-color: #e4e7eb;
+}
+QAbstractScrollArea::corner {
+ background: transparent;
+}
+QAbstractScrollArea > .QWidget {
+ background: transparent;
+}
+QAbstractScrollArea > .QWidget > .QWidget {
+ background: transparent;
+}
+QTextEdit, QPlainTextEdit {
+ background: #1e1d1e;
+}
+QTextEdit:focus,
+QTextEdit:selected,
+QPlainTextEdit:focus,
+QPlainTextEdit:selected {
+ border: 1px solid #8ab4f7;
+ selection-background-color: #12507b;
+}
+QTextEdit:!focus,
+QPlainTextEdit:!focus {
+ $env_patch{"version": ">=5.15.0", "value": "selection-background-color: #393d41"};
+}
+QTextEdit:!active,
+QPlainTextEdit:!active {
+ $env_patch{"version": "<5.15.0", "value": "selection-background-color: #393d41"};
+}
+QAbstractItemView {
+ alternate-background-color: #292b2e;
+}
+QAbstractItemView::item {
+ $env_patch{"version": ">=6.0.0", "value": "border-color: transparent"};
+}
+QAbstractItemView:selected:!active,
+QAbstractItemView:selected:!focus,
+QAbstractItemView::item:selected:!active,
+QTreeView::branch:selected:!active {
+ background: #393d41;
+}
+QAbstractItemView::item:selected,
+QTreeView::branch:selected {
+ background: #004875;
+ color: #e4e7eb;
+}
+QAbstractItemView::item:!selected:hover,
+QTreeView::branch:!selected:hover {
+ background: #292d2e;
+}
+QAbstractItemView::item:selected:disabled {
+ color: #697177;
+}
+QAbstractItemView QLineEdit,
+QAbstractItemView QAbstractSpinBox,
+QAbstractItemView QComboBox,
+QAbstractItemView QAbstractButton {
+ padding: 0;
+ margin: 1px;
+}
+QTreeView::branch {
+ border-image: url(${path}/dark/svg/vertical_line__guides-stroke-inactive.svg) 0;
+}
+QTreeView::branch:active {
+ border-image: url(${path}/dark/svg/vertical_line__icon-foreground.svg) 0;
+}
+QTreeView::branch:disabled {
+ border-image: url(${path}/dark/svg/vertical_line__icon-foreground-disabled.svg) 0;
+}
+QTreeView::branch:has-siblings:adjoins-item,
+QTreeView::branch:!has-children:!has-siblings:adjoins-item {
+ border-image: unset;
+}
+QTreeView::branch:has-children:!has-siblings:closed,
+QTreeView::branch:closed:has-children:has-siblings {
+ border-image: unset;
+ image: url(${path}/dark/svg/chevron_right__icon-foreground.svg);
+}
+QTreeView::branch:has-children:!has-siblings:closed:disabled,
+QTreeView::branch:closed:has-children:has-siblings:disabled {
+ image: url(${path}/dark/svg/chevron_right__icon-foreground-disabled.svg);
+}
+QTreeView::branch:open:has-children:!has-siblings,
+QTreeView::branch:open:has-children:has-siblings {
+ border-image: unset;
+ image: url(${path}/dark/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QTreeView::branch:open:has-children:!has-siblings:disabled,
+QTreeView::branch:open:has-children:has-siblings:disabled {
+ image: url(${path}/dark/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QTableView {
+ gridline-color: #58595c;
+ background: #000000;
+}
+QTableView QTableCornerButton::section {
+ margin: 0 1px 1px 0;
+ background: #3f4042;
+ border-top-left-radius: $radius{2px};
+}
+QTableView QTableCornerButton::section:pressed {
+ background: #004875;
+}
+QTableView > QHeaderView{
+ background: #000000;
+}
+QHeaderView {
+ padding: 0;
+ margin: 0;
+ border: none;
+ border-radius: $radius{0};
+}
+QHeaderView::section {
+ background: #3f4042;
+ text-align: left;
+ padding: 0 4px;
+ border: none;
+}
+QHeaderView::section:horizontal:on,
+QHeaderView::section:vertical:on {
+ border-color: #8ab4f7;
+}
+QHeaderView::section:horizontal:on:disabled,
+QHeaderView::section:vertical:on:disabled {
+ color: #53575b;
+ border-color: #53575b;
+}
+QHeaderView::section:horizontal {
+ border-top: 2px solid transparent;
+ margin-right: 1px;
+}
+QHeaderView::section:vertical {
+ border-left: 2px solid transparent;
+ margin-bottom: 1px;
+}
+QHeaderView::section:last,
+QHeaderView::section:only-one {
+ margin: 0;
+}
+QHeaderView::down-arrow {
+ margin: -2px -6px -6px -6px;
+ image: url(${path}/dark/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QHeaderView::down-arrow:disabled {
+ image: url(${path}/dark/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QHeaderView::up-arrow {
+ margin: -2px -6px -6px -6px;
+ image: url(${path}/dark/svg/expand_less__icon-foreground.svg);
+}
+QHeaderView::up-arrow:disabled {
+ image: url(${path}/dark/svg/expand_less__icon-foreground-disabled.svg);
+}
+QCalendarWidget {
+ border: none;
+}
+QCalendarWidget > .QWidget {
+ background: #000000;
+ border-bottom: 1px solid #3f4042;
+ border-radius: $radius{4px};
+ border-bottom-left-radius: $radius{0};
+ border-bottom-right-radius: $radius{0};
+}
+QCalendarWidget > .QWidget > QWidget {
+ padding: 1px;
+}
+QCalendarWidget > .QWidget > QSpinBox {
+ margin-left: 1px;
+}
+QCalendarWidget > .QWidget > QSpinBox::up-button,
+QCalendarWidget > .QWidget > QSpinBox::down-button {
+ margin: 1px 3px 1px 1px;
+}
+QCalendarWidget .QWidget > QToolButton {
+ border-radius: $radius{4px};
+}
+QCalendarWidget > .QWidget > QToolButton::menu-indicator {
+ height: 14px;
+ width: 14px;
+ top: 5px;
+ left: 3px;
+}
+QCalendarWidget > QTableView {
+ margin: 0;
+ border: none;
+ border-radius: $radius{4px};
+ border-top-left-radius: $radius{0};
+ border-top-right-radius: $radius{0};
+}
+QCalendarWidget > .QWidget > QToolButton#qt_calendar_prevmonth {
+ qproperty-icon: url(${path}/dark/svg/arrow_upward__icon-foreground__rotate-270.svg);
+}
+QCalendarWidget > .QWidget > QToolButton#qt_calendar_nextmonth {
+ qproperty-icon: url(${path}/dark/svg/arrow_upward__icon-foreground__rotate-90.svg);
+}
+QLineEdit,
+QAbstractSpinBox {
+ border: 1px solid #3f4042;
+ padding: 3px 4px;
+ min-height: 1em;
+ background: #3f4042;
+ border-radius: $radius{4px};
+}
+QLineEdit:focus,
+QAbstractSpinBox:focus {
+ border: 1px solid #8ab4f7;
+}
+QAbstractSpinBox::up-button,
+QAbstractSpinBox::down-button {
+ subcontrol-origin: border;
+ width: 12px;
+ height: 4px;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QAbstractSpinBox::up-button:hover,
+QAbstractSpinBox::down-button:hover {
+ background: #58595c;
+}
+QAbstractSpinBox::up-button {
+ subcontrol-position: top right;
+ margin: 3px 3px 1px 1px;
+}
+QAbstractSpinBox::up-arrow {
+ image: url(${path}/dark/svg/arrow_drop_up__icon-foreground.svg);
+}
+QAbstractSpinBox::up-arrow:disabled {
+ image: url(${path}/dark/svg/arrow_drop_up__icon-foreground-disabled.svg);
+}
+QAbstractSpinBox::down-button {
+ subcontrol-position: bottom right;
+ margin: 1px 3px 3px 1px;
+}
+QAbstractSpinBox::down-arrow {
+ image: url(${path}/dark/svg/arrow_drop_up__icon-foreground__rotate-180.svg);
+}
+QAbstractSpinBox::down-arrow:disabled {
+ image: url(${path}/dark/svg/arrow_drop_up__icon-foreground-disabled__rotate-180.svg);
+}
+QDateTimeEdit::drop-down {
+ padding-right: 4px;
+ width: 16px;
+ image: url(${path}/dark/svg/calendar_today__icon-foreground.svg);
+}
+QDateTimeEdit::drop-down:disabled {
+ image: url(${path}/dark/svg/calendar_today__icon-foreground-disabled.svg);
+}
+QDateTimeEdit::down-arrow[calendarPopup=true] {
+ image: none;
+}
+QDateTimeEdit QCalendarWidget QAbstractItemView {
+ padding: -1px;
+ border: none;
+}
+QFileDialog > QFrame QAbstractItemView {
+ border: none;
+}
+QFileDialog > QFrame > QFrame QFrame QFrame {
+ border: none;
+ padding: 0;
+}
+QFontDialog QListView {
+ min-height: 60px;
+}
+QFontDialog QScrollBar:vertical {
+ margin: 0;
+}
+QComboBox::indicator:checked,
+QMenu::indicator:checked {
+ width: 18px;
+ image: url(${path}/dark/svg/check__icon-foreground.svg);
+}
+QMenu::indicator {
+ width: 18px;
+ background: #48494b;
+ margin-left: 3px;
+ border-radius: $radius{4px};
+}
+QCheckBox,
+QRadioButton {
+ spacing: 8px;
+}
+QGroupBox::title,
+QAbstractItemView::item {
+ spacing: 6px;
+}
+QCheckBox::indicator,
+QGroupBox::indicator,
+QAbstractItemView::indicator,
+QRadioButton::indicator {
+ height: 18px;
+ width: 18px;
+}
+QCheckBox::indicator,
+QGroupBox::indicator,
+QAbstractItemView::indicator {
+ image: url(${path}/dark/svg/check_box_outline_blank__icon-foreground.svg);
+}
+QCheckBox::indicator:unchecked:disabled,
+QGroupBox::indicator:unchecked:disabled,
+QAbstractItemView::indicator:unchecked:disabled {
+ image: url(${path}/dark/svg/check_box_outline_blank__icon-foreground-disabled.svg);
+}
+QCheckBox::indicator:checked,
+QGroupBox::indicator:checked,
+QAbstractItemView::indicator:checked {
+ image: url(${path}/dark/svg/check_box__highlight.svg);
+}
+QCheckBox::indicator:checked:disabled,
+QGroupBox::indicator:checked:disabled,
+QAbstractItemView::indicator:checked:disabled {
+ image: url(${path}/dark/svg/check_box__icon-foreground-disabled.svg);
+}
+QCheckBox::indicator:indeterminate,
+QAbstractItemView::indicator:indeterminate {
+ image: url(${path}/dark/svg/indeterminate_check_box__highlight.svg);
+}
+QCheckBox::indicator:indeterminate:disabled,
+QAbstractItemView::indicator:indeterminate:disabled {
+ image: url(${path}/dark/svg/indeterminate_check_box__icon-foreground-disabled.svg);
+}
+QRadioButton::indicator:unchecked {
+ image: url(${path}/dark/svg/radio_button_unchecked__icon-foreground.svg);
+}
+QRadioButton::indicator:unchecked:disabled {
+ image: url(${path}/dark/svg/radio_button_unchecked__icon-foreground-disabled.svg);
+}
+QRadioButton::indicator:checked {
+ image: url(${path}/dark/svg/radio_button_checked__highlight.svg);
+}
+QRadioButton::indicator:checked:disabled {
+ image: url(${path}/dark/svg/radio_button_checked__icon-foreground-disabled.svg);
+}
+QComboBox QAbstractItemView,
+QStatusBar > QMenu,
+QDateTimeEdit QCalendarWidget QAbstractItemView,
+QDateTimeEdit QCalendarWidget .QWidget {
+ margin: 0;
+ border-radius: $radius{0};
+ $env_patch{"version": "<6.0.0", "os": "Darwin", "value": "border-radius: $radius{4px}"};
+}
+QMenu,
+QStatusBar > QMenu {
+ $env_patch{"version": "<6.0.0", "os": "Darwin", "value": "border-radius: $radius{8px}"};
+}
+PlotWidget {
+ padding: 0;
+}
+ParameterTree > .QWidget > .QWidget > .QWidget > QAbstractSpinBox::up-button,
+ParameterTree > .QWidget > .QWidget > .QWidget > QAbstractSpinBox::down-button {
+ margin: 2px 3px 1px 1px;
+ padding: 2px;
+}
+ParameterTree > .QWidget > .QWidget > .QWidget > QComboBox{
+ min-height: 1.2em;
+}
+
+"""
diff --git a/libs/qdarktheme/themes/dark/svg.py b/libs/qdarktheme/themes/dark/svg.py
new file mode 100644
index 00000000..00e1b3c4
--- /dev/null
+++ b/libs/qdarktheme/themes/dark/svg.py
@@ -0,0 +1,5 @@
+"""Contents that define svg for dark theme."""
+
+SVG_RESOURCES = """
+{"arrow_drop_up__icon-foreground": "", "arrow_drop_up__icon-foreground-disabled": "", "arrow_drop_up__icon-foreground-disabled__rotate-180": "", "arrow_drop_up__icon-foreground__rotate-180": "", "arrow_drop_up__scrollbar-disabled": "", "arrow_drop_up__scrollbar-disabled__rotate-180": "", "arrow_drop_up__scrollbar-disabled__rotate-270": "", "arrow_drop_up__scrollbar-disabled__rotate-90": "", "arrow_drop_up__scrollbar-handle": "", "arrow_drop_up__scrollbar-handle-pressed": "", "arrow_drop_up__scrollbar-handle-pressed__rotate-180": "", "arrow_drop_up__scrollbar-handle-pressed__rotate-270": "", "arrow_drop_up__scrollbar-handle-pressed__rotate-90": "", "arrow_drop_up__scrollbar-handle__rotate-180": "", "arrow_drop_up__scrollbar-handle__rotate-270": "", "arrow_drop_up__scrollbar-handle__rotate-90": "", "arrow_upward__icon-foreground": "", "arrow_upward__icon-foreground__rotate-270": "", "arrow_upward__icon-foreground__rotate-90": "", "calendar_today__icon-foreground": "", "calendar_today__icon-foreground-disabled": "", "cancel__icon-foreground": "", "check__icon-foreground": "", "check_box__highlight": "", "check_box__icon-foreground-disabled": "", "check_box_outline_blank__icon-foreground": "", "check_box_outline_blank__icon-foreground-disabled": "", "check_circle__icon-foreground": "", "chevron_right__icon-foreground": "", "chevron_right__icon-foreground-disabled": "", "close__icon-foreground": "", "close__icon-foreground-disabled": "", "close__tabbar-button-unselected": "", "create_new_folder__icon-foreground": "", "delete__icon-foreground": "", "double_arrow__icon-foreground": "", "double_arrow__icon-foreground-disabled": "", "drag_indicator_horizontal__icon-foreground": "", "drag_indicator_horizontal__icon-foreground__rotate-90": "", "east__highlight": "", "expand_less__icon-foreground": "", "expand_less__icon-foreground-disabled": "", "expand_less__icon-foreground-disabled__rotate-180": "", "expand_less__icon-foreground__rotate-180": "", "flip_to_front__icon-foreground": "", "folder_open__icon-foreground": "", "help__icon-foreground": "", "horizontal_rule__icon-foreground": "", "horizontal_rule__icon-foreground-disabled": "", "horizontal_rule__icon-foreground-disabled__rotate-90": "", "horizontal_rule__icon-foreground__rotate-90": "", "indeterminate_check_box__highlight": "", "indeterminate_check_box__icon-foreground-disabled": "", "radio_button_checked__highlight": "", "radio_button_checked__icon-foreground-disabled": "", "radio_button_unchecked__icon-foreground": "", "radio_button_unchecked__icon-foreground-disabled": "", "restart_alt__icon-foreground": "", "save__icon-foreground": "", "vertical_line__guides-stroke-inactive": "", "vertical_line__icon-foreground": "", "vertical_line__icon-foreground-disabled": ""}
+""" # noqa: E501
diff --git a/libs/qdarktheme/themes/light/__init__.py b/libs/qdarktheme/themes/light/__init__.py
new file mode 100644
index 00000000..0819e30c
--- /dev/null
+++ b/libs/qdarktheme/themes/light/__init__.py
@@ -0,0 +1 @@
+"""Package containing the resources for light theme."""
diff --git a/libs/qdarktheme/themes/light/palette.py b/libs/qdarktheme/themes/light/palette.py
new file mode 100644
index 00000000..8219413e
--- /dev/null
+++ b/libs/qdarktheme/themes/light/palette.py
@@ -0,0 +1,45 @@
+"""Module loading QPalette."""
+from libs.qdarktheme.qtpy.QtGui import QColor, QPalette
+
+_palette = QPalette()
+
+# base
+_palette.setColor(QPalette.ColorRole.WindowText, QColor("#4d5157"))
+_palette.setColor(QPalette.ColorRole.Button, QColor("#f8f9fa"))
+_palette.setColor(QPalette.ColorRole.Text, QColor("#4d5157"))
+_palette.setColor(QPalette.ColorRole.ButtonText, QColor("#0081db"))
+_palette.setColor(QPalette.ColorRole.Base, QColor("#f8f9fa"))
+_palette.setColor(QPalette.ColorRole.Window, QColor("#f8f9fa"))
+_palette.setColor(QPalette.ColorRole.Highlight, QColor("#0081db"))
+_palette.setColor(QPalette.ColorRole.HighlightedText, QColor("#f8f9fa"))
+_palette.setColor(QPalette.ColorRole.Link, QColor("#f8f9fa"))
+_palette.setColor(QPalette.ColorRole.AlternateBase, QColor("#e9ecef"))
+_palette.setColor(QPalette.ColorRole.ToolTipBase, QColor("#ffffff"))
+_palette.setColor(QPalette.ColorRole.ToolTipText, QColor("#4d5157"))
+_palette.setColor(QPalette.ColorRole.LinkVisited, QColor("#660098"))
+_palette.setColor(QPalette.ColorRole.ToolTipText, QColor("#ffffff"))
+_palette.setColor(QPalette.ColorRole.ToolTipBase, QColor("#4d5157"))
+if hasattr(QPalette.ColorRole, "Foreground"):
+ _palette.setColor(QPalette.ColorRole.Foreground, QColor("#4d5157")) # type: ignore
+if hasattr(QPalette.ColorRole, "PlaceholderText"):
+ _palette.setColor(QPalette.ColorRole.PlaceholderText, QColor("#696a6c"))
+
+_palette.setColor(QPalette.ColorRole.Light, QColor("#dadce0"))
+_palette.setColor(QPalette.ColorRole.Midlight, QColor("#dadce0"))
+_palette.setColor(QPalette.ColorRole.Dark, QColor("#4d5157"))
+_palette.setColor(QPalette.ColorRole.Mid, QColor("#dadce0"))
+_palette.setColor(QPalette.ColorRole.Shadow, QColor("#dadce0"))
+
+# disabled
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.WindowText, QColor("#babdc2"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, QColor("#babdc2"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, QColor("#dadce0"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Highlight, QColor("#dadce0"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.HighlightedText, QColor("#babdc2"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Link, QColor("#babdc2"))
+_palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.LinkVisited, QColor("#babdc2"))
+
+# inactive
+_palette.setColor(QPalette.ColorGroup.Inactive, QPalette.ColorRole.Highlight, QColor("#e4e6f2"))
+
+PALETTE = _palette
diff --git a/libs/qdarktheme/themes/light/stylesheet.py b/libs/qdarktheme/themes/light/stylesheet.py
new file mode 100644
index 00000000..3cc343da
--- /dev/null
+++ b/libs/qdarktheme/themes/light/stylesheet.py
@@ -0,0 +1,1097 @@
+"""Contents that define stylesheet for light theme."""
+
+STYLE_SHEET = """
+* {
+ padding: 0;
+ margin: 0;
+ border: none;
+ border-style: none;
+ border-image: unset;
+ outline: none;
+}
+QToolBar * {
+ margin: 0;
+ padding: 0;
+}
+QWidget {
+ background: #f8f9fa;
+ color: #4d5157;
+ selection-background-color: #0081db;
+ selection-color: #f8f9fa;
+}
+QWidget:disabled {
+ color: #babdc2;
+ selection-background-color: #dadce0;
+ selection-color: #babdc2;
+}
+QWidget {
+ backward-icon: url(${path}/light/svg/arrow_upward__icon-foreground__rotate-270.svg);
+ forward-icon: url(${path}/light/svg/arrow_upward__icon-foreground__rotate-90.svg);
+ leftarrow-icon: url(${path}/light/svg/arrow_upward__icon-foreground__rotate-270.svg);
+ rightarrow-icon: url(${path}/light/svg/arrow_upward__icon-foreground__rotate-90.svg);
+ dialog-ok-icon: url(${path}/light/svg/check__icon-foreground.svg);
+ dialog-cancel-icon: url(${path}/light/svg/close__icon-foreground.svg);
+ dialog-yes-icon: url(${path}/light/svg/check_circle__icon-foreground.svg);
+ dialog-no-icon: url(${path}/light/svg/cancel__icon-foreground.svg);
+ dialog-apply-icon: url(${path}/light/svg/check__icon-foreground.svg);
+ dialog-reset-icon: url(${path}/light/svg/restart_alt__icon-foreground.svg);
+ dialog-save-icon: url(${path}/light/svg/save__icon-foreground.svg);
+ dialog-discard-icon: url(${path}/light/svg/delete__icon-foreground.svg);
+ dialog-close-icon: url(${path}/light/svg/close__icon-foreground.svg);
+ dialog-open-icon: url(${path}/light/svg/folder_open__icon-foreground.svg);
+ dialog-help-icon: url(${path}/light/svg/help__icon-foreground.svg);
+ filedialog-parent-directory-icon: url(${path}/light/svg/arrow_upward__icon-foreground.svg);
+ filedialog-new-directory-icon: url(${path}/light/svg/create_new_folder__icon-foreground.svg);
+ titlebar-close-icon: url(${path}/light/svg/close__icon-foreground.svg);
+ titlebar-normal-icon: url(${path}/light/svg/flip_to_front__icon-foreground.svg);
+}
+QCommandLinkButton {
+ qproperty-icon: url(${path}/light/svg/east__highlight.svg);
+}
+QMainWindow::separator {
+ width: 4px;
+ height: 4px;
+ background: #dadce0;
+}
+QMainWindow::separator:hover,
+QMainWindow::separator:pressed {
+ background: #0081db;
+}
+QToolTip {
+ background: #ffffff;
+ color: #4d5157;
+ border: 1px solid #dadce0;
+}
+QSizeGrip {
+ width: 0;
+ height: 0;
+ image: none;
+}
+QStatusBar {
+ background: #dfe1e5;
+}
+QStatusBar::item {
+ border: none;
+}
+QStatusBar QWidget {
+ background: transparent;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QStatusBar > .QSizeGrip {
+ padding: 0;
+}
+QStatusBar QWidget:hover {
+ background: #d1d4da;
+}
+QStatusBar QWidget:pressed,
+QStatusBar QWidget:checked {
+ background: #c3c7ce;
+}
+QStatusBar QWidget:disabled {
+ background: #edeef0;
+}
+QCheckBox,
+QRadioButton {
+ border-top: 2px solid transparent;
+ border-bottom: 2px solid transparent;
+}
+QCheckBox:!window,
+QRadioButton:!window {
+ background: transparent;
+}
+QCheckBox:hover,
+QRadioButton:hover {
+ border-bottom: 2px solid #0081db;
+}
+QGroupBox {
+ font-weight: bold;
+ border: 1px solid #dadce0;
+ margin-top: 8px;
+ padding: 2px 1px 1px 1px;
+ border-radius: $radius{4px};
+}
+QGroupBox::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ left: 7px;
+ margin: 0 2px 0 3px;
+}
+QGroupBox:flat {
+ border-color: transparent;
+}
+QMenuBar {
+ background: #f8f9fa;
+ padding: 2px;
+ border-bottom: 1px solid #dadce0;
+}
+QMenuBar::item {
+ background: transparent;
+ padding: 4px;
+}
+QMenuBar::item:selected {
+ padding: 4px;
+ background: #dadce0;
+ border-radius: $radius{4px};
+}
+QMenuBar::item:pressed {
+ padding: 4px;
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+QToolBar {
+ background: #ebebeb;
+ padding: 1px;
+ font-weight: bold;
+ spacing: 2px;
+ margin: 1px;
+}
+QToolBar::handle:horizontal {
+ width: 20px;
+ image: url(${path}/light/svg/drag_indicator_horizontal__icon-foreground.svg);
+}
+QToolBar::handle:vertical {
+ height: 20px;
+ image: url(${path}/light/svg/drag_indicator_horizontal__icon-foreground__rotate-90.svg);
+}
+QToolBar::separator {
+ background: #dadce0;
+}
+QToolBar::separator:horizontal {
+ width: 2px;
+ margin: 0 6px;
+}
+QToolBar::separator:vertical {
+ height: 2px;
+ margin: 6px 0;
+}
+QToolBar > QToolButton {
+ background: transparent;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QToolBar > QToolButton:hover,
+QToolBar > QToolButton::menu-button:hover {
+ background: #d7d7d7;
+}
+QToolBar > QToolButton:pressed,
+QToolBar > QToolButton::menu-button:pressed,
+QToolBar > QToolButton:checked {
+ background: #c4c4c4;
+}
+QToolBar > QToolButton#qt_toolbar_ext_button {
+ image: url(${path}/light/svg/double_arrow__icon-foreground.svg);
+ $env_patch{"os": "Windows", "value": "padding: 0; qproperty-icon: unset"};
+}
+QToolBar > QToolButton#qt_toolbar_ext_button:disabled {
+ image: url(${path}/light/svg/double_arrow__icon-foreground-disabled.svg);
+}
+QToolBar > QWidget {
+ background: transparent;
+}
+QMenu {
+ background: #ffffff;
+ padding: 8px 0;
+ border: 1px solid #dadce0;
+}
+QMenu::separator {
+ margin: 4px 0;
+ height: 1px;
+ background: #dadce0;
+}
+QMenu::item {
+ padding: 4px 28px;
+}
+QMenu::item:selected {
+ background: #dadce0;
+}
+QMenu::icon {
+ padding-left: 10px;
+ width: 14px;
+ height: 14px;
+}
+QMenu::right-arrow {
+ margin: 2px;
+ padding-left: 12px;
+ height: 20px;
+ width: 20px;
+ image: url(${path}/light/svg/chevron_right__icon-foreground.svg);
+}
+QMenu::right-arrow:disabled {
+ image: url(${path}/light/svg/chevron_right__icon-foreground-disabled.svg);
+}
+QScrollBar {
+ background: #edeff2;
+ $env_patch{"os": "Darwin", "value": "background: transparent"};
+ border-radius: $radius{4px};
+}
+QScrollBar:horizontal {
+ height: 14px;
+ $env_patch{"os": "Darwin", "value": "height: 7px;"};
+}
+QScrollBar:vertical {
+ width: 14px;
+ $env_patch{"os": "Darwin", "value": "width: 7px;"};
+}
+QScrollBar::handle {
+ background: rgba(155.000, 155.000, 157.000, 0.737);
+ border-radius: $radius{3px};
+}
+QScrollBar::handle:hover {
+ background: rgba(117.000, 117.000, 119.000, 0.827);
+}
+QScrollBar::handle:pressed {
+ background: rgba(96.000, 96.000, 98.000, 0.933);
+}
+QScrollBar::handle:disabled {
+ background-color: #d6dbe2;
+}
+QScrollBar::handle:horizontal {
+ min-width: 8px;
+ margin: 4px 14px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:horizontal:hover {
+ margin: 2px 14px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:vertical {
+ min-height: 8px;
+ margin: 14px 4px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:vertical:hover {
+ margin: 14px 2px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::sub-page, QScrollBar::add-page {
+ background: transparent;
+}
+QScrollBar::sub-line,
+QScrollBar::add-line {
+ background: transparent;
+ width: 14px;
+ height: 14px;
+ margin: 2px;
+ subcontrol-origin: margin;
+ $env_patch{"os": "Darwin", "value": "width: 0; height: 0; margin: 0"};
+}
+QScrollBar::sub-line:vertical {
+ subcontrol-position: top;
+}
+QScrollBar::add-line:vertical {
+ subcontrol-position: bottom;
+}
+QScrollBar::sub-line:horizontal {
+ subcontrol-position: left;
+}
+QScrollBar::add-line:horizontal {
+ subcontrol-position: right;
+}
+QScrollBar::up-arrow {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle.svg);
+}
+QScrollBar::right-arrow {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle__rotate-90.svg);
+}
+QScrollBar::down-arrow {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle__rotate-180.svg);
+}
+QScrollBar::left-arrow {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle__rotate-270.svg);
+}
+QScrollBar::up-arrow:hover {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle-pressed.svg);
+}
+QScrollBar::right-arrow:hover {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-90.svg);
+}
+QScrollBar::down-arrow:hover {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-180.svg);
+}
+QScrollBar::left-arrow:hover {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-270.svg);
+}
+QScrollBar::up-arrow:disabled {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-disabled.svg);
+}
+QScrollBar::right-arrow:disabled {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-disabled__rotate-90.svg);
+}
+QScrollBar::down-arrow:disabled {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-disabled__rotate-180.svg);
+}
+QScrollBar::left-arrow:disabled {
+ image: url(${path}/light/svg/arrow_drop_up__scrollbar-disabled__rotate-270.svg);
+}
+QProgressBar {
+ border: 1px solid #dadce0;
+ text-align: center;
+ color: #4d5157;
+ border-radius: $radius{4px};
+}
+QProgressBar::chunk {
+ background: #0081db;
+ border-radius: $radius{3px};
+}
+QProgressBar::chunk:disabled {
+ background: #dadce0;
+}
+QPushButton {
+ color: #0081db;
+ border: 1px solid #dadce0;
+ padding: 4px 8px;
+ border-radius: $radius{4px};
+}
+QPushButton:!window {
+ background: transparent;
+}
+QPushButton:flat,
+QPushButton:default {
+ border: none;
+ padding: 5px 9px;
+}
+QPushButton:default {
+ color: #f8f9fa;
+ background: #0081db;
+}
+QPushButton:hover,
+QPushButton:flat:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QPushButton:pressed,
+QPushButton:flat:pressed,
+QPushButton:checked:pressed,
+QPushButton:flat:checked:pressed {
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QPushButton:checked,
+QPushButton:flat:checked {
+ background: rgba(181.000, 202.000, 244.000, 0.733);
+}
+QPushButton:default:hover {
+ background: #3781ea;
+}
+QPushButton:default:pressed {
+ background: #6ca1f0;
+}
+QPushButton:default:disabled {
+ background: #dadce0;
+}
+QDialogButtonBox QPushButton {
+ min-width: 65px;
+}
+QToolButton {
+ background: transparent;
+ padding: 5px;
+ spacing: 2px;
+ border-radius: $radius{2px};
+}
+QToolButton:hover,
+QToolButton::menu-button:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QToolButton:pressed,
+QToolButton:checked:pressed,
+QToolButton::menu-button:pressed {
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QToolButton:selected,
+QToolButton:checked {
+ background: rgba(181.000, 202.000, 244.000, 0.733);
+}
+QToolButton::checked:disabled {
+ background: #dadce0;
+}
+QToolButton::menu-indicator {
+ height: 18px;
+ width: 18px;
+ top: 6px;
+ left: 3px;
+ image: url(${path}/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QToolButton::menu-indicator:disabled {
+ image: url(${path}/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QToolButton::menu-arrow {
+ image: unset;
+}
+QToolButton::menu-button {
+ subcontrol-origin: margin;
+ border: none;
+ width: 17px;
+ border-top-right-radius: $radius{4px};
+ border-bottom-right-radius: $radius{4px};
+ image: url(${path}/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QToolButton::menu-button:disabled {
+ image: url(${path}/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QToolButton[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "popupMode=MenuButtonPopup"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "popupMode=\\\"1\\\""}
+$env_patch{"version": ">=6.0.0", "value": "popupMode=MenuButtonPopup"}
+] {
+ padding-right: 1px;
+ margin-right: 18px;
+ border-top-right-radius: $radius{0};
+ border-bottom-right-radius: $radius{0};
+}
+QComboBox {
+ border: 1px solid #dadce0;
+ min-height: 1.5em;
+ padding: 0 4px;
+ background: rgba(255.000, 255.000, 255.000, 0.000);
+ border-radius: $radius{4px};
+}
+QComboBox:focus,
+QComboBox:open {
+ border: 1px solid #0081db;
+}
+QComboBox::drop-down {
+ border: none;
+ padding-right: 4px;
+}
+QComboBox::down-arrow {
+ image: url(${path}/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QComboBox::down-arrow:disabled {
+ image: url(${path}/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QComboBox::item:selected {
+ border: none;
+ background: #4ca6e5;
+ color: #4d5157;
+}
+QComboBox QAbstractItemView {
+ background: #ffffff;
+ margin: 0;
+ border: 1px solid #dadce0;
+ selection-background-color: #4ca6e5;
+ selection-color: #4d5157;
+ padding: 2px;
+}
+QComboBox QAbstractItemView[
+$env_patch{"version": "<6.0.0", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border-color: #dadce0;
+}
+QSlider {
+ padding: 2px 0;
+}
+QSlider::groove {
+ border-radius: $radius{2px};
+}
+QSlider::groove:horizontal {
+ height: 4px;
+}
+QSlider::groove:vertical {
+ width: 4px;
+}
+QSlider::sub-page, QSlider::handle {
+ background: #0081db;
+}
+QSlider::sub-page:disabled,
+QSlider::add-page:disabled,
+QSlider::handle:disabled {
+ background: #dadce0;
+}
+QSlider::add-page {
+ background: #abc6f6;
+}
+QSlider::handle:hover {
+ background: #3781ea;
+}
+QSlider::handle:pressed {
+ background: #6ca1f0;
+}
+QSlider::handle:horizontal {
+ width: 16px;
+ height: 8px;
+ margin: -6px 0;
+ border-radius: 8px;
+}
+QSlider::handle:vertical {
+ width: 8px;
+ height: 16px;
+ margin: 0 -6px;
+ border-radius: 8px;
+}
+QTabWidget::pane {
+ border: 1px solid #dadce0;
+ border-radius: $radius{4px};
+}
+QTabBar {
+ qproperty-drawBase: 0;
+}
+QTabBar::close-button:selected {
+ image: url(${path}/light/svg/close__icon-foreground.svg);
+}
+QTabBar::close-button:!selected {
+ image: url(${path}/light/svg/close__tabbar-button-unselected.svg)
+}
+QTabBar::close-button:disabled {
+ image: url(${path}/light/svg/close__icon-foreground-disabled.svg);
+}
+QTabBar::close-button:hover {
+ background: #93b2ef;
+ border-radius: $radius{4px};
+}
+QTabBar::close-button:hover:!selected {
+ background: #aec5f4;
+}
+QTabBar::tab {
+ padding: 3px;
+}
+QTabBar::tab:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QTabBar::tab:selected {
+ color: #0081db;
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QTabBar::tab:selected:disabled {
+ background: #dadce0;
+ color: #babdc2;
+}
+QTabBar::tab:top {
+ border-bottom: 2px solid #dadce0;
+ margin-left: 4px;
+ border-top-left-radius: $radius{2px};
+ border-top-right-radius: $radius{2px};
+}
+QTabBar::tab:top:selected {
+ border-bottom: 2px solid #0081db;
+}
+QTabBar::tab:top:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:top:selected:disabled {
+ border-color: #dadce0;
+}
+QTabBar::tab:bottom {
+ border-top: 2px solid #dadce0;
+ margin-left: 4px;
+ border-bottom-left-radius: $radius{2px};
+ border-bottom-right-radius: $radius{2px};
+}
+QTabBar::tab:bottom:selected {
+ border-top: 2px solid #0081db;
+}
+QTabBar::tab:bottom:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:bottom:selected:disabled {
+ border-color: #dadce0;
+}
+QTabBar::tab:left {
+ border-right: 2px solid #dadce0;
+ margin-top: 4px;
+ border-top-left-radius: $radius{2px};
+ border-bottom-left-radius: $radius{2px};
+}
+QTabBar::tab:left:selected {
+ border-right: 2px solid #0081db;
+}
+QTabBar::tab:left:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:left:selected:disabled {
+ border-color: #dadce0;
+}
+QTabBar::tab:right {
+ border-left: 2px solid #dadce0;
+ margin-top: 4px;
+ border-top-right-radius: $radius{2px};
+ border-bottom-right-radius: $radius{2px};
+}
+QTabBar::tab:right:selected {
+ border-left: 2px solid #0081db;
+}
+QTabBar::tab:right:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:right:selected:disabled {
+ border-color: #dadce0;
+}
+QDockWidget {
+ border: 1px solid #dadce0;
+ border-radius: $radius{4px};
+}
+QDockWidget::title {
+ padding: 3px;
+ spacing: 4px;
+ background: #edeef0;
+}
+QDockWidget::close-button,
+QDockWidget::float-button {
+ border-radius: $radius{2px};
+}
+QDockWidget::close-button:hover,
+QDockWidget::float-button:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QDockWidget::close-button:pressed,
+QDockWidget::float-button:pressed {
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QFrame {
+ border: 1px solid #dadce0;
+ padding: 1px;
+ border-radius: $radius{4px};
+}
+.QFrame {
+ padding: 0;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=NoFrame"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border-color: transparent;
+ padding: 0;
+}
+.QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=NoFrame"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border: none;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=Panel"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"2\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=Panel"}
+] {
+ border-color: #ffffff;
+ background: #ffffff;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=HLine"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"4\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=HLine"}
+] {
+ max-height: 2px;
+ border: none;
+ background: #dadce0;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=VLine"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"5\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=VLine"}
+] {
+ max-width: 2px;
+ border: none;
+ background: #dadce0;
+}
+QLCDNumber {
+ color: #4d5157;
+ min-width: 2em;
+ margin: 2px;
+}
+QLabel:!window,
+QLCDNumber:!window {
+ background-color: transparent;
+}
+QToolBox:selected {
+ border: 2px solid #0081db;
+}
+QToolBox::tab {
+ background: #edeef0;
+ border-bottom: 2px solid #dadce0;
+ border-top-left-radius: $radius{4px};
+ border-top-right-radius: $radius{4px};
+}
+QToolBox::tab:selected {
+ border-bottom: 2px solid #0081db;
+}
+QToolBox::tab:selected:disabled {
+ border-bottom: 2px solid #dadce0;
+}
+QSplitter::handle {
+ background: #dadce0;
+ margin: 1px 3px;
+}
+QSplitter::handle:hover {
+ background: #0081db;
+}
+QSplitter::handle:horizontal {
+ width: 5px;
+ image: url(${path}/light/svg/horizontal_rule__icon-foreground__rotate-90.svg);
+}
+QSplitter::handle:horizontal:disabled {
+ image: url(${path}/light/svg/horizontal_rule__icon-foreground-disabled__rotate-90.svg);
+}
+QSplitter::handle:vertical {
+ height: 5px;
+ image: url(${path}/light/svg/horizontal_rule__icon-foreground.svg);
+}
+QSplitter::handle:vertical:disabled {
+ image: url(${path}/light/svg/horizontal_rule__icon-foreground-disabled.svg);
+}
+QSplitterHandle::item:hover {}
+QAbstractScrollArea {
+ selection-background-color: #4ca6e5;
+ selection-color: #4d5157;
+ margin: 1px;
+}
+QAbstractScrollArea:disabled {
+ selection-background-color: #0081db;
+}
+QAbstractScrollArea::corner {
+ background: transparent;
+}
+QAbstractScrollArea > .QWidget {
+ background: transparent;
+}
+QAbstractScrollArea > .QWidget > .QWidget {
+ background: transparent;
+}
+QTextEdit, QPlainTextEdit {
+ background: #ffffff;
+}
+QTextEdit:focus,
+QTextEdit:selected,
+QPlainTextEdit:focus,
+QPlainTextEdit:selected {
+ border: 1px solid #0081db;
+ selection-background-color: #a2d8ff;
+}
+QTextEdit:!focus,
+QPlainTextEdit:!focus {
+ $env_patch{"version": ">=5.15.0", "value": "selection-background-color: #e4e6f2"};
+}
+QTextEdit:!active,
+QPlainTextEdit:!active {
+ $env_patch{"version": "<5.15.0", "value": "selection-background-color: #e4e6f2"};
+}
+QAbstractItemView {
+ alternate-background-color: #e9ecef;
+}
+QAbstractItemView::item {
+ $env_patch{"version": ">=6.0.0", "value": "border-color: transparent"};
+}
+QAbstractItemView:selected:!active,
+QAbstractItemView:selected:!focus,
+QAbstractItemView::item:selected:!active,
+QTreeView::branch:selected:!active {
+ background: #e4e6f2;
+}
+QAbstractItemView::item:selected,
+QTreeView::branch:selected {
+ background: #4ca6e5;
+ color: #4d5157;
+}
+QAbstractItemView::item:!selected:hover,
+QTreeView::branch:!selected:hover {
+ background: #d3d3d3;
+}
+QAbstractItemView::item:selected:disabled {
+ color: #babdc2;
+}
+QAbstractItemView QLineEdit,
+QAbstractItemView QAbstractSpinBox,
+QAbstractItemView QComboBox,
+QAbstractItemView QAbstractButton {
+ padding: 0;
+ margin: 1px;
+}
+QTreeView::branch {
+ border-image: url(${path}/light/svg/vertical_line__guides-stroke-inactive.svg) 0;
+}
+QTreeView::branch:active {
+ border-image: url(${path}/light/svg/vertical_line__icon-foreground.svg) 0;
+}
+QTreeView::branch:disabled {
+ border-image: url(${path}/light/svg/vertical_line__icon-foreground-disabled.svg) 0;
+}
+QTreeView::branch:has-siblings:adjoins-item,
+QTreeView::branch:!has-children:!has-siblings:adjoins-item {
+ border-image: unset;
+}
+QTreeView::branch:has-children:!has-siblings:closed,
+QTreeView::branch:closed:has-children:has-siblings {
+ border-image: unset;
+ image: url(${path}/light/svg/chevron_right__icon-foreground.svg);
+}
+QTreeView::branch:has-children:!has-siblings:closed:disabled,
+QTreeView::branch:closed:has-children:has-siblings:disabled {
+ image: url(${path}/light/svg/chevron_right__icon-foreground-disabled.svg);
+}
+QTreeView::branch:open:has-children:!has-siblings,
+QTreeView::branch:open:has-children:has-siblings {
+ border-image: unset;
+ image: url(${path}/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QTreeView::branch:open:has-children:!has-siblings:disabled,
+QTreeView::branch:open:has-children:has-siblings:disabled {
+ image: url(${path}/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QTableView {
+ gridline-color: #58595c;
+ background: #ffffff;
+}
+QTableView QTableCornerButton::section {
+ margin: 0 1px 1px 0;
+ background: #dadce0;
+ border-top-left-radius: $radius{2px};
+}
+QTableView QTableCornerButton::section:pressed {
+ background: #4ca6e5;
+}
+QTableView > QHeaderView{
+ background: #ffffff;
+}
+QHeaderView {
+ padding: 0;
+ margin: 0;
+ border: none;
+ border-radius: $radius{0};
+}
+QHeaderView::section {
+ background: #dadce0;
+ text-align: left;
+ padding: 0 4px;
+ border: none;
+}
+QHeaderView::section:horizontal:on,
+QHeaderView::section:vertical:on {
+ border-color: #0081db;
+}
+QHeaderView::section:horizontal:on:disabled,
+QHeaderView::section:vertical:on:disabled {
+ color: #dadce0;
+ border-color: #dadce0;
+}
+QHeaderView::section:horizontal {
+ border-top: 2px solid transparent;
+ margin-right: 1px;
+}
+QHeaderView::section:vertical {
+ border-left: 2px solid transparent;
+ margin-bottom: 1px;
+}
+QHeaderView::section:last,
+QHeaderView::section:only-one {
+ margin: 0;
+}
+QHeaderView::down-arrow {
+ margin: -2px -6px -6px -6px;
+ image: url(${path}/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QHeaderView::down-arrow:disabled {
+ image: url(${path}/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QHeaderView::up-arrow {
+ margin: -2px -6px -6px -6px;
+ image: url(${path}/light/svg/expand_less__icon-foreground.svg);
+}
+QHeaderView::up-arrow:disabled {
+ image: url(${path}/light/svg/expand_less__icon-foreground-disabled.svg);
+}
+QCalendarWidget {
+ border: none;
+}
+QCalendarWidget > .QWidget {
+ background: #ffffff;
+ border-bottom: 1px solid #dadce0;
+ border-radius: $radius{4px};
+ border-bottom-left-radius: $radius{0};
+ border-bottom-right-radius: $radius{0};
+}
+QCalendarWidget > .QWidget > QWidget {
+ padding: 1px;
+}
+QCalendarWidget > .QWidget > QSpinBox {
+ margin-left: 1px;
+}
+QCalendarWidget > .QWidget > QSpinBox::up-button,
+QCalendarWidget > .QWidget > QSpinBox::down-button {
+ margin: 1px 3px 1px 1px;
+}
+QCalendarWidget .QWidget > QToolButton {
+ border-radius: $radius{4px};
+}
+QCalendarWidget > .QWidget > QToolButton::menu-indicator {
+ height: 14px;
+ width: 14px;
+ top: 5px;
+ left: 3px;
+}
+QCalendarWidget > QTableView {
+ margin: 0;
+ border: none;
+ border-radius: $radius{4px};
+ border-top-left-radius: $radius{0};
+ border-top-right-radius: $radius{0};
+}
+QCalendarWidget > .QWidget > QToolButton#qt_calendar_prevmonth {
+ qproperty-icon: url(${path}/light/svg/arrow_upward__icon-foreground__rotate-270.svg);
+}
+QCalendarWidget > .QWidget > QToolButton#qt_calendar_nextmonth {
+ qproperty-icon: url(${path}/light/svg/arrow_upward__icon-foreground__rotate-90.svg);
+}
+QLineEdit,
+QAbstractSpinBox {
+ border: 1px solid #dadce0;
+ padding: 3px 4px;
+ min-height: 1em;
+ background: rgba(255.000, 255.000, 255.000, 0.000);
+ border-radius: $radius{4px};
+}
+QLineEdit:focus,
+QAbstractSpinBox:focus {
+ border: 1px solid #0081db;
+}
+QAbstractSpinBox::up-button,
+QAbstractSpinBox::down-button {
+ subcontrol-origin: border;
+ width: 12px;
+ height: 4px;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QAbstractSpinBox::up-button:hover,
+QAbstractSpinBox::down-button:hover {
+ background: #e2eafb;
+}
+QAbstractSpinBox::up-button {
+ subcontrol-position: top right;
+ margin: 3px 3px 1px 1px;
+}
+QAbstractSpinBox::up-arrow {
+ image: url(${path}/light/svg/arrow_drop_up__icon-foreground.svg);
+}
+QAbstractSpinBox::up-arrow:disabled {
+ image: url(${path}/light/svg/arrow_drop_up__icon-foreground-disabled.svg);
+}
+QAbstractSpinBox::down-button {
+ subcontrol-position: bottom right;
+ margin: 1px 3px 3px 1px;
+}
+QAbstractSpinBox::down-arrow {
+ image: url(${path}/light/svg/arrow_drop_up__icon-foreground__rotate-180.svg);
+}
+QAbstractSpinBox::down-arrow:disabled {
+ image: url(${path}/light/svg/arrow_drop_up__icon-foreground-disabled__rotate-180.svg);
+}
+QDateTimeEdit::drop-down {
+ padding-right: 4px;
+ width: 16px;
+ image: url(${path}/light/svg/calendar_today__icon-foreground.svg);
+}
+QDateTimeEdit::drop-down:disabled {
+ image: url(${path}/light/svg/calendar_today__icon-foreground-disabled.svg);
+}
+QDateTimeEdit::down-arrow[calendarPopup=true] {
+ image: none;
+}
+QDateTimeEdit QCalendarWidget QAbstractItemView {
+ padding: -1px;
+ border: none;
+}
+QFileDialog > QFrame QAbstractItemView {
+ border: none;
+}
+QFileDialog > QFrame > QFrame QFrame QFrame {
+ border: none;
+ padding: 0;
+}
+QFontDialog QListView {
+ min-height: 60px;
+}
+QFontDialog QScrollBar:vertical {
+ margin: 0;
+}
+QComboBox::indicator:checked,
+QMenu::indicator:checked {
+ width: 18px;
+ image: url(${path}/light/svg/check__icon-foreground.svg);
+}
+QMenu::indicator {
+ width: 18px;
+ background: #c4c7cc;
+ margin-left: 3px;
+ border-radius: $radius{4px};
+}
+QCheckBox,
+QRadioButton {
+ spacing: 8px;
+}
+QGroupBox::title,
+QAbstractItemView::item {
+ spacing: 6px;
+}
+QCheckBox::indicator,
+QGroupBox::indicator,
+QAbstractItemView::indicator,
+QRadioButton::indicator {
+ height: 18px;
+ width: 18px;
+}
+QCheckBox::indicator,
+QGroupBox::indicator,
+QAbstractItemView::indicator {
+ image: url(${path}/light/svg/check_box_outline_blank__icon-foreground.svg);
+}
+QCheckBox::indicator:unchecked:disabled,
+QGroupBox::indicator:unchecked:disabled,
+QAbstractItemView::indicator:unchecked:disabled {
+ image: url(${path}/light/svg/check_box_outline_blank__icon-foreground-disabled.svg);
+}
+QCheckBox::indicator:checked,
+QGroupBox::indicator:checked,
+QAbstractItemView::indicator:checked {
+ image: url(${path}/light/svg/check_box__highlight.svg);
+}
+QCheckBox::indicator:checked:disabled,
+QGroupBox::indicator:checked:disabled,
+QAbstractItemView::indicator:checked:disabled {
+ image: url(${path}/light/svg/check_box__icon-foreground-disabled.svg);
+}
+QCheckBox::indicator:indeterminate,
+QAbstractItemView::indicator:indeterminate {
+ image: url(${path}/light/svg/indeterminate_check_box__highlight.svg);
+}
+QCheckBox::indicator:indeterminate:disabled,
+QAbstractItemView::indicator:indeterminate:disabled {
+ image: url(${path}/light/svg/indeterminate_check_box__icon-foreground-disabled.svg);
+}
+QRadioButton::indicator:unchecked {
+ image: url(${path}/light/svg/radio_button_unchecked__icon-foreground.svg);
+}
+QRadioButton::indicator:unchecked:disabled {
+ image: url(${path}/light/svg/radio_button_unchecked__icon-foreground-disabled.svg);
+}
+QRadioButton::indicator:checked {
+ image: url(${path}/light/svg/radio_button_checked__highlight.svg);
+}
+QRadioButton::indicator:checked:disabled {
+ image: url(${path}/light/svg/radio_button_checked__icon-foreground-disabled.svg);
+}
+QComboBox QAbstractItemView,
+QStatusBar > QMenu,
+QDateTimeEdit QCalendarWidget QAbstractItemView,
+QDateTimeEdit QCalendarWidget .QWidget {
+ margin: 0;
+ border-radius: $radius{0};
+ $env_patch{"version": "<6.0.0", "os": "Darwin", "value": "border-radius: $radius{4px}"};
+}
+QMenu,
+QStatusBar > QMenu {
+ $env_patch{"version": "<6.0.0", "os": "Darwin", "value": "border-radius: $radius{8px}"};
+}
+PlotWidget {
+ padding: 0;
+}
+ParameterTree > .QWidget > .QWidget > .QWidget > QAbstractSpinBox::up-button,
+ParameterTree > .QWidget > .QWidget > .QWidget > QAbstractSpinBox::down-button {
+ margin: 2px 3px 1px 1px;
+ padding: 2px;
+}
+ParameterTree > .QWidget > .QWidget > .QWidget > QComboBox{
+ min-height: 1.2em;
+}
+
+"""
diff --git a/libs/qdarktheme/themes/light/svg.py b/libs/qdarktheme/themes/light/svg.py
new file mode 100644
index 00000000..e284072d
--- /dev/null
+++ b/libs/qdarktheme/themes/light/svg.py
@@ -0,0 +1,5 @@
+"""Contents that define svg for light theme."""
+
+SVG_RESOURCES = """
+{"arrow_drop_up__icon-foreground": "", "arrow_drop_up__icon-foreground-disabled": "", "arrow_drop_up__icon-foreground-disabled__rotate-180": "", "arrow_drop_up__icon-foreground__rotate-180": "", "arrow_drop_up__scrollbar-disabled": "", "arrow_drop_up__scrollbar-disabled__rotate-180": "", "arrow_drop_up__scrollbar-disabled__rotate-270": "", "arrow_drop_up__scrollbar-disabled__rotate-90": "", "arrow_drop_up__scrollbar-handle": "", "arrow_drop_up__scrollbar-handle-pressed": "", "arrow_drop_up__scrollbar-handle-pressed__rotate-180": "", "arrow_drop_up__scrollbar-handle-pressed__rotate-270": "", "arrow_drop_up__scrollbar-handle-pressed__rotate-90": "", "arrow_drop_up__scrollbar-handle__rotate-180": "", "arrow_drop_up__scrollbar-handle__rotate-270": "", "arrow_drop_up__scrollbar-handle__rotate-90": "", "arrow_upward__icon-foreground": "", "arrow_upward__icon-foreground__rotate-270": "", "arrow_upward__icon-foreground__rotate-90": "", "calendar_today__icon-foreground": "", "calendar_today__icon-foreground-disabled": "", "cancel__icon-foreground": "", "check__icon-foreground": "", "check_box__highlight": "", "check_box__icon-foreground-disabled": "", "check_box_outline_blank__icon-foreground": "", "check_box_outline_blank__icon-foreground-disabled": "", "check_circle__icon-foreground": "", "chevron_right__icon-foreground": "", "chevron_right__icon-foreground-disabled": "", "close__icon-foreground": "", "close__icon-foreground-disabled": "", "close__tabbar-button-unselected": "", "create_new_folder__icon-foreground": "", "delete__icon-foreground": "", "double_arrow__icon-foreground": "", "double_arrow__icon-foreground-disabled": "", "drag_indicator_horizontal__icon-foreground": "", "drag_indicator_horizontal__icon-foreground__rotate-90": "", "east__highlight": "", "expand_less__icon-foreground": "", "expand_less__icon-foreground-disabled": "", "expand_less__icon-foreground-disabled__rotate-180": "", "expand_less__icon-foreground__rotate-180": "", "flip_to_front__icon-foreground": "", "folder_open__icon-foreground": "", "help__icon-foreground": "", "horizontal_rule__icon-foreground": "", "horizontal_rule__icon-foreground-disabled": "", "horizontal_rule__icon-foreground-disabled__rotate-90": "", "horizontal_rule__icon-foreground__rotate-90": "", "indeterminate_check_box__highlight": "", "indeterminate_check_box__icon-foreground-disabled": "", "radio_button_checked__highlight": "", "radio_button_checked__icon-foreground-disabled": "", "radio_button_unchecked__icon-foreground": "", "radio_button_unchecked__icon-foreground-disabled": "", "restart_alt__icon-foreground": "", "save__icon-foreground": "", "vertical_line__guides-stroke-inactive": "", "vertical_line__icon-foreground": "", "vertical_line__icon-foreground-disabled": ""}
+""" # noqa: E501
diff --git a/libs/qdarktheme/util.py b/libs/qdarktheme/util.py
new file mode 100644
index 00000000..23e43d28
--- /dev/null
+++ b/libs/qdarktheme/util.py
@@ -0,0 +1,67 @@
+"""Utility methods for qdarktheme."""
+from __future__ import annotations
+
+import inspect
+import logging
+import operator as ope
+import re
+from pathlib import Path
+
+import libs.qdarktheme
+
+# greater_equal and less_equal must be evaluated before greater and less.
+OPERATORS = {"==": ope.eq, "!=": ope.ne, ">=": ope.ge, "<=": ope.le, ">": ope.gt, "<": ope.lt}
+
+
+def multi_replace(target: str, replacements: dict[str, str]) -> str:
+ """Given a string and a replacement map, it returns the replaced string.
+
+ See https://gist.github.com/bgusach/a967e0587d6e01e889fd1d776c5f3729.
+
+ Args:
+ target: String to execute replacements on.
+ replacements: Replacement dictionary {value to find: value to replace}.
+
+ Returns:
+ str: Target string that replaced with `replacements`.
+ """
+ if len(replacements) == 0:
+ return target
+
+ replacements_sorted = sorted(replacements, key=len, reverse=True)
+ replacements_escaped = [re.escape(i) for i in replacements_sorted]
+ pattern = re.compile("|".join(replacements_escaped))
+ return pattern.sub(lambda match: replacements[match.group()], target)
+
+
+def get_logger(logger_name: str) -> logging.Logger:
+ """Return the logger with the name specified by logger_name arg.
+
+ Args:
+ logger_name: The name of logger.
+
+ Returns:
+ Logger reformatted for this package.
+ """
+ logger = logging.getLogger(logger_name)
+ logger.propagate = False
+ logger.setLevel(logging.INFO)
+ ch = logging.StreamHandler()
+ ch.setFormatter(logging.Formatter("[%(name)s] [%(levelname)s] %(message)s"))
+ logger.addHandler(ch)
+ return logger
+
+
+def get_qdarktheme_root_path() -> Path:
+ """Return the qdarktheme package root path.
+
+ Returns:
+ qdarktheme package root path.
+ """
+ return Path(inspect.getfile(libs.qdarktheme)).parent
+
+
+def compare_v(v1: str, operator: str, v2: str) -> bool:
+ """Comparing two versions."""
+ v1_list, v2_list = (tuple(map(int, (v.split(".")))) for v in (v1, v2))
+ return OPERATORS[operator](v1_list, v2_list)
diff --git a/libs/qdarktheme/widget_gallery/__init__.py b/libs/qdarktheme/widget_gallery/__init__.py
new file mode 100644
index 00000000..cffed1ef
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/__init__.py
@@ -0,0 +1,8 @@
+"""Example of PyQtDarkTheme use for Qt applications.
+
+To check example app, run:
+
+```shell
+python -m qdarktheme.widget_gallery
+```
+"""
diff --git a/libs/qdarktheme/widget_gallery/__main__.py b/libs/qdarktheme/widget_gallery/__main__.py
new file mode 100644
index 00000000..c94490fe
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/__main__.py
@@ -0,0 +1,17 @@
+"""Module allowing for `python -m qdarktheme.widget_gallery`."""
+import sys
+
+import libs.qdarktheme
+from libs.qdarktheme.qtpy.QtCore import Qt
+from libs.qdarktheme.qtpy.QtWidgets import QApplication
+from libs.qdarktheme.widget_gallery.mainwindow import WidgetGallery
+
+if __name__ == "__main__":
+ app = QApplication(sys.argv)
+ if hasattr(Qt.ApplicationAttribute, "AA_UseHighDpiPixmaps"): # Enable High DPI display with Qt5
+ app.setAttribute(Qt.ApplicationAttribute.AA_UseHighDpiPixmaps) # type: ignore
+ win = WidgetGallery()
+ win.menuBar().setNativeMenuBar(False)
+ app.setStyleSheet(libs.qdarktheme.load_stylesheet())
+ win.show()
+ app.exec()
diff --git a/libs/qdarktheme/widget_gallery/mainwindow.py b/libs/qdarktheme/widget_gallery/mainwindow.py
new file mode 100644
index 00000000..bae1aa05
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/mainwindow.py
@@ -0,0 +1,204 @@
+"""Main module of widget gallery."""
+import libs.qdarktheme
+from libs.qdarktheme.qtpy.QtCore import QDir, Qt, Slot
+from libs.qdarktheme.qtpy.QtGui import QAction, QActionGroup, QFont, QIcon
+from libs.qdarktheme.qtpy.QtWidgets import (
+ QApplication,
+ QColorDialog,
+ QFileDialog,
+ QFontDialog,
+ QLabel,
+ QMainWindow,
+ QMenuBar,
+ QMessageBox,
+ QSizePolicy,
+ QStackedWidget,
+ QStatusBar,
+ QToolBar,
+ QToolButton,
+ QWidget,
+)
+from libs.qdarktheme.util import get_qdarktheme_root_path
+from libs.qdarktheme.widget_gallery.ui.dock_ui import DockUI
+from libs.qdarktheme.widget_gallery.ui.frame_ui import FrameUI
+from libs.qdarktheme.widget_gallery.ui.widgets_ui import WidgetsUI
+
+
+class _WidgetGalleryUI:
+ def setup_ui(self, main_win: QMainWindow) -> None:
+ # Actions
+ self.action_open_folder = QAction(QIcon("icons:folder_open_24dp.svg"), "Open folder dialog")
+ self.action_open_color_dialog = QAction(QIcon("icons:palette_24dp.svg"), "Open color dialog")
+ self.action_open_font_dialog = QAction(QIcon("icons:font_download_24dp.svg"), "Open font dialog")
+ self.action_enable = QAction(QIcon("icons:circle_24dp.svg"), "Enable")
+ self.action_disable = QAction(QIcon("icons:clear_24dp.svg"), "Disable")
+ self.actions_theme = [QAction(theme, main_win) for theme in ["dark", "light"]]
+ self.actions_page = (
+ QAction(QIcon("icons:widgets_24dp.svg"), "Move to widgets"),
+ QAction(QIcon("icons:flip_to_front_24dp.svg"), "Move to dock"),
+ QAction(QIcon("icons:crop_din_24dp.svg"), "Move to frame"),
+ )
+ self.actions_message_box = (
+ QAction(text="Open question dialog"),
+ QAction(text="Open information dialog"),
+ QAction(text="Open warning dialog"),
+ QAction(text="Open critical dialog"),
+ )
+ self.actions_corner_radius = (QAction(text="rounded"), QAction(text="sharp"))
+
+ action_group_toolbar = QActionGroup(main_win)
+
+ # Widgets
+ self.central_window = QMainWindow()
+ self.stack_widget = QStackedWidget()
+ self.toolbar = QToolBar("Toolbar")
+
+ activitybar = QToolBar("activitybar")
+ statusbar = QStatusBar()
+ menubar = QMenuBar()
+ tool_btn_settings, tool_btn_theme, tool_btn_enable, tool_btn_disable, tool_btn_message_box = (
+ QToolButton() for _ in range(5)
+ )
+
+ spacer = QToolButton()
+
+ # Setup Actions
+ for action in self.actions_page:
+ action.setCheckable(True)
+ action_group_toolbar.addAction(action)
+ self.actions_page[0].setChecked(True)
+
+ # Setup Widgets
+ spacer.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
+ spacer.setEnabled(False)
+
+ activitybar.setMovable(False)
+ activitybar.addActions(self.actions_page)
+ activitybar.addWidget(spacer)
+ activitybar.addWidget(tool_btn_settings)
+
+ tool_btn_settings.setIcon(QIcon("icons:settings_24dp.svg"))
+ tool_btn_settings.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
+ tool_btn_enable.setDefaultAction(self.action_enable)
+ tool_btn_disable.setDefaultAction(self.action_disable)
+ tool_btn_message_box.setIcon(QIcon("icons:announcement_24dp.svg"))
+ tool_btn_message_box.setPopupMode(QToolButton.ToolButtonPopupMode.MenuButtonPopup)
+ tool_btn_theme.setIcon(QIcon("icons:contrast_24dp.svg"))
+ tool_btn_theme.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
+
+ self.toolbar.addActions((self.action_open_folder, self.action_open_color_dialog, self.action_open_font_dialog))
+ self.toolbar.addSeparator()
+ self.toolbar.addWidget(QLabel("Popup"))
+ self.toolbar.addWidget(tool_btn_message_box)
+ self.toolbar.addWidget(tool_btn_theme)
+
+ statusbar.addPermanentWidget(tool_btn_enable)
+ statusbar.addPermanentWidget(tool_btn_disable)
+ statusbar.showMessage("Enable")
+
+ menu_toggle = menubar.addMenu("&Toggle")
+ menu_toggle.addActions((self.action_enable, self.action_disable))
+ menu_theme = menubar.addMenu("&Theme")
+ menu_theme.addActions(self.actions_theme)
+ menu_dialog = menubar.addMenu("&Dialog")
+ menu_option = menubar.addMenu("&Option")
+ menu_option.addActions(self.actions_corner_radius)
+ menu_dialog.addActions((self.action_open_folder, self.action_open_color_dialog, self.action_open_font_dialog))
+ menu_message_box = menu_dialog.addMenu("&Messages")
+ menu_message_box.addActions(self.actions_message_box)
+
+ tool_btn_settings.setMenu(menu_toggle)
+ tool_btn_theme.setMenu(menu_theme)
+ tool_btn_message_box.setMenu(menu_message_box)
+
+ self.action_enable.setEnabled(False)
+
+ # Layout
+ for ui in (WidgetsUI, DockUI, FrameUI):
+ container = QWidget()
+ ui().setup_ui(container)
+ self.stack_widget.addWidget(container)
+
+ self.central_window.setCentralWidget(self.stack_widget)
+ self.central_window.addToolBar(self.toolbar)
+
+ main_win.setCentralWidget(self.central_window)
+ main_win.addToolBar(Qt.ToolBarArea.LeftToolBarArea, activitybar)
+ main_win.setMenuBar(menubar)
+ main_win.setStatusBar(statusbar)
+
+
+class WidgetGallery(QMainWindow):
+ """The main window class of example app."""
+
+ def __init__(self) -> None:
+ """Initialize the WidgetGallery class."""
+ super().__init__()
+ QDir.addSearchPath("icons", f"{get_qdarktheme_root_path().as_posix()}/widget_gallery/svg")
+ self._ui = _WidgetGalleryUI()
+ self._ui.setup_ui(self)
+ self._theme = "dark"
+ self._border_radius = "rounded"
+
+ # Signal
+ self._ui.action_open_folder.triggered.connect(
+ lambda: QFileDialog.getOpenFileName(self, "Open File", options=QFileDialog.Option.DontUseNativeDialog)
+ )
+ self._ui.action_open_color_dialog.triggered.connect(
+ lambda: QColorDialog.getColor(parent=self, options=QColorDialog.ColorDialogOption.DontUseNativeDialog)
+ )
+ self._ui.action_open_font_dialog.triggered.connect(
+ lambda: QFontDialog.getFont(QFont(), parent=self, options=QFontDialog.FontDialogOption.DontUseNativeDialog)
+ )
+ self._ui.action_enable.triggered.connect(self._toggle_state)
+ self._ui.action_disable.triggered.connect(self._toggle_state)
+ for action in self._ui.actions_theme:
+ action.triggered.connect(self._change_theme)
+ for action in self._ui.actions_page:
+ action.triggered.connect(self._change_page)
+ for action in self._ui.actions_message_box:
+ action.triggered.connect(self._popup_message_box)
+ for action in self._ui.actions_corner_radius:
+ action.triggered.connect(self._change_corner_radius)
+
+ @Slot()
+ def _change_page(self) -> None:
+ action_name: str = self.sender().text() # type: ignore
+ if "widgets" in action_name:
+ index = 0
+ elif "dock" in action_name:
+ index = 1
+ else:
+ index = 2
+ self._ui.stack_widget.setCurrentIndex(index)
+
+ @Slot()
+ def _toggle_state(self) -> None:
+ state: str = self.sender().text() # type: ignore
+ self._ui.central_window.centralWidget().setEnabled(state == "Enable")
+ self._ui.toolbar.setEnabled(state == "Enable")
+ self._ui.action_enable.setEnabled(state == "Disable")
+ self._ui.action_disable.setEnabled(state == "Enable")
+ self.statusBar().showMessage(state)
+
+ @Slot()
+ def _change_theme(self) -> None:
+ self._theme = self.sender().text() # type: ignore
+ QApplication.instance().setStyleSheet(libs.qdarktheme.load_stylesheet(self._theme, self._border_radius))
+
+ @Slot()
+ def _change_corner_radius(self) -> None:
+ self._border_radius: str = self.sender().text() # type: ignore
+ QApplication.instance().setStyleSheet(libs.qdarktheme.load_stylesheet(self._theme, self._border_radius))
+
+ @Slot()
+ def _popup_message_box(self) -> None:
+ action_name: str = self.sender().text() # type: ignore
+ if "question" in action_name:
+ QMessageBox.question(self, "Question", "Question")
+ elif "information" in action_name:
+ QMessageBox.information(self, "Information", "Information")
+ elif "warning" in action_name:
+ QMessageBox.warning(self, "Warning", "Warning")
+ elif "critical" in action_name:
+ QMessageBox.critical(self, "Critical", "Critical")
diff --git a/libs/qdarktheme/widget_gallery/svg/announcement_24dp.svg b/libs/qdarktheme/widget_gallery/svg/announcement_24dp.svg
new file mode 100644
index 00000000..4ec4d5e0
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/announcement_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/circle_24dp.svg b/libs/qdarktheme/widget_gallery/svg/circle_24dp.svg
new file mode 100644
index 00000000..b2f3cd93
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/circle_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/clear_24dp.svg b/libs/qdarktheme/widget_gallery/svg/clear_24dp.svg
new file mode 100644
index 00000000..9779a070
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/clear_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/contrast_24dp.svg b/libs/qdarktheme/widget_gallery/svg/contrast_24dp.svg
new file mode 100644
index 00000000..2e1e790c
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/contrast_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/crop_din_24dp.svg b/libs/qdarktheme/widget_gallery/svg/crop_din_24dp.svg
new file mode 100644
index 00000000..cfb0130d
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/crop_din_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/favorite_border_24dp.svg b/libs/qdarktheme/widget_gallery/svg/favorite_border_24dp.svg
new file mode 100644
index 00000000..4cc68d15
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/favorite_border_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/flip_to_front_24dp.svg b/libs/qdarktheme/widget_gallery/svg/flip_to_front_24dp.svg
new file mode 100644
index 00000000..0a04e513
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/flip_to_front_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/folder_open_24dp.svg b/libs/qdarktheme/widget_gallery/svg/folder_open_24dp.svg
new file mode 100644
index 00000000..d816ec20
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/folder_open_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/font_download_24dp.svg b/libs/qdarktheme/widget_gallery/svg/font_download_24dp.svg
new file mode 100644
index 00000000..2f4d6c12
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/font_download_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/palette_24dp.svg b/libs/qdarktheme/widget_gallery/svg/palette_24dp.svg
new file mode 100644
index 00000000..0b9f2d2d
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/palette_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/settings_24dp.svg b/libs/qdarktheme/widget_gallery/svg/settings_24dp.svg
new file mode 100644
index 00000000..4804f00a
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/settings_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/svg/widgets_24dp.svg b/libs/qdarktheme/widget_gallery/svg/widgets_24dp.svg
new file mode 100644
index 00000000..f0da1fa2
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/svg/widgets_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libs/qdarktheme/widget_gallery/ui/__init__.py b/libs/qdarktheme/widget_gallery/ui/__init__.py
new file mode 100644
index 00000000..be4973ab
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/ui/__init__.py
@@ -0,0 +1 @@
+"""Package including ui for WidgetGallery."""
diff --git a/libs/qdarktheme/widget_gallery/ui/dock_ui.py b/libs/qdarktheme/widget_gallery/ui/dock_ui.py
new file mode 100644
index 00000000..45a505c8
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/ui/dock_ui.py
@@ -0,0 +1,40 @@
+"""Module setting up ui of dock window."""
+from libs.qdarktheme.qtpy.QtCore import Qt
+from libs.qdarktheme.qtpy.QtWidgets import QDockWidget, QMainWindow, QTextEdit, QVBoxLayout, QWidget
+
+
+class DockUI:
+ """The ui class of dock window."""
+
+ def setup_ui(self, win: QWidget) -> None:
+ """Set up ui."""
+ # Widgets
+ left_dock = QDockWidget("Left dock")
+ right_dock = QDockWidget("Right dock")
+ top_dock = QDockWidget("Top dock")
+ bottom_dock = QDockWidget("Bottom dock")
+
+ # Setup widgets
+ left_dock.setWidget(QTextEdit("This is the left widget."))
+ right_dock.setWidget(QTextEdit("This is the right widget."))
+ top_dock.setWidget(QTextEdit("This is the top widget."))
+ bottom_dock.setWidget(QTextEdit("This is the bottom widget."))
+ for dock in (left_dock, right_dock, top_dock, bottom_dock):
+ dock.setAllowedAreas(
+ Qt.DockWidgetArea.LeftDockWidgetArea
+ | Qt.DockWidgetArea.RightDockWidgetArea
+ | Qt.DockWidgetArea.BottomDockWidgetArea
+ | Qt.DockWidgetArea.TopDockWidgetArea
+ )
+
+ # Layout
+ main_win = QMainWindow()
+ main_win.setCentralWidget(QTextEdit("This is the central widget."))
+ main_win.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, left_dock)
+ main_win.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, right_dock)
+ main_win.addDockWidget(Qt.DockWidgetArea.TopDockWidgetArea, top_dock)
+ main_win.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, bottom_dock)
+
+ layout = QVBoxLayout(win)
+ layout.addWidget(main_win)
+ layout.setContentsMargins(0, 0, 0, 0)
diff --git a/libs/qdarktheme/widget_gallery/ui/frame_ui.py b/libs/qdarktheme/widget_gallery/ui/frame_ui.py
new file mode 100644
index 00000000..0cbb82eb
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/ui/frame_ui.py
@@ -0,0 +1,75 @@
+"""Module setting up ui of frame window."""
+from libs.qdarktheme.qtpy.QtGui import QIcon
+from libs.qdarktheme.qtpy.QtWidgets import (
+ QCalendarWidget,
+ QCheckBox,
+ QFrame,
+ QGridLayout,
+ QGroupBox,
+ QHBoxLayout,
+ QPushButton,
+ QRadioButton,
+ QScrollArea,
+ QSpinBox,
+ QToolButton,
+ QVBoxLayout,
+ QWidget,
+)
+
+
+class FrameUI:
+ """The ui class of frame window."""
+
+ def setup_ui(self, win: QWidget) -> None:
+ """Set up ui."""
+ # Widgets
+ group_box = QGroupBox("frameShape = Box")
+ group_panel = QGroupBox("frameShape = Panel")
+ group_none = QGroupBox("frameShape = NoFrame")
+ group_line = QGroupBox("frameShape = VLine HLine")
+ frame_box, frame_panel, frame_none, frame_v_line, frame_h_line = (QFrame() for _ in range(5))
+
+ # Setup widgets
+ frame_box.setFrameShape(QFrame.Shape.Box)
+ frame_panel.setFrameShape(QFrame.Shape.Panel)
+ frame_none.setFrameShape(QFrame.Shape.NoFrame)
+ frame_v_line.setFrameShape(QFrame.Shape.VLine)
+ frame_h_line.setFrameShape(QFrame.Shape.HLine)
+
+ # Layout
+ for frame in (frame_box, frame_panel, frame_none):
+ push_btn_flat = QPushButton("Push button(flat)")
+ push_btn_flat.setFlat(True)
+ tool_btn = QToolButton()
+ tool_btn.setIcon(QIcon("icons:favorite_border_24dp.svg"))
+ calender = QCalendarWidget()
+
+ g_layout = QGridLayout(frame)
+ g_layout.addWidget(QPushButton("Push button"), 0, 0)
+ g_layout.addWidget(push_btn_flat, 0, 1)
+ g_layout.addWidget(QSpinBox(), 1, 0)
+ g_layout.addWidget(tool_btn, 1, 1)
+ g_layout.addWidget(QRadioButton("Radio button"), 2, 0)
+ g_layout.addWidget(QCheckBox("Check box"), 2, 1)
+ g_layout.addWidget(calender, 3, 0, 1, 2)
+
+ for group, frame in ((group_box, frame_box), (group_panel, frame_panel), (group_none, frame_none)):
+ v_layout = QVBoxLayout(group)
+ v_layout.addWidget(frame)
+
+ h_layout = QHBoxLayout(group_line)
+ h_layout.addWidget(frame_v_line)
+ h_layout.addWidget(frame_h_line)
+
+ widget_container = QWidget()
+ g_layout = QGridLayout(widget_container)
+ g_layout.addWidget(group_box, 0, 0)
+ g_layout.addWidget(group_panel, 0, 1)
+ g_layout.addWidget(group_none, 1, 0)
+ g_layout.addWidget(group_line, 1, 1)
+
+ scroll_area = QScrollArea()
+ scroll_area.setWidget(widget_container)
+
+ v_main_layout = QVBoxLayout(win)
+ v_main_layout.addWidget(scroll_area)
diff --git a/libs/qdarktheme/widget_gallery/ui/widgets_ui.py b/libs/qdarktheme/widget_gallery/ui/widgets_ui.py
new file mode 100644
index 00000000..c215244e
--- /dev/null
+++ b/libs/qdarktheme/widget_gallery/ui/widgets_ui.py
@@ -0,0 +1,293 @@
+"""Module setting up ui of widgets window."""
+from __future__ import annotations
+
+from typing import Any
+
+from libs.qdarktheme.qtpy.QtCore import QAbstractTableModel, QModelIndex, Qt
+from libs.qdarktheme.qtpy.QtGui import QIcon, QTextOption
+from libs.qdarktheme.qtpy.QtWidgets import (
+ QCheckBox,
+ QComboBox,
+ QDateTimeEdit,
+ QDial,
+ QGridLayout,
+ QGroupBox,
+ QLabel,
+ QLCDNumber,
+ QLineEdit,
+ QListWidget,
+ QProgressBar,
+ QPushButton,
+ QRadioButton,
+ QScrollArea,
+ QSlider,
+ QSpinBox,
+ QSplitter,
+ QTableView,
+ QTabWidget,
+ QTextEdit,
+ QToolBox,
+ QToolButton,
+ QTreeWidget,
+ QTreeWidgetItem,
+ QVBoxLayout,
+ QWidget,
+)
+
+
+class _Group1(QGroupBox):
+ def __init__(self) -> None:
+ super().__init__("Buttons")
+
+ # Widgets
+ group_push = QGroupBox("Push Button")
+ group_tool = QGroupBox("Tool Button")
+ group_radio = QGroupBox("Radio Button")
+ group_checkbox = QGroupBox("Check Box")
+
+ push_btn, push_btn_toggled = QPushButton("NORMAL"), QPushButton("TOGGLED")
+ push_btn_flat, push_btn_flat_toggled = QPushButton("NORMAL"), QPushButton("TOGGLED")
+ tool_btn, tool_btn_toggled, tool_btn_text = QToolButton(), QToolButton(), QToolButton()
+ radio_btn_1, radio_btn_2 = QRadioButton("Normal 1"), QRadioButton("Normal 2")
+ checkbox, checkbox_tristate = QCheckBox("Normal"), QCheckBox("Tristate")
+
+ # Setup widgets
+ self.setCheckable(True)
+ push_btn_flat.setFlat(True)
+ push_btn_flat_toggled.setFlat(True)
+ for btn in (push_btn_toggled, push_btn_flat_toggled):
+ btn.setCheckable(True)
+ btn.setChecked(True)
+
+ tool_btn.setIcon(QIcon("icons:favorite_border_24dp.svg"))
+ tool_btn_toggled.setIcon(QIcon("icons:favorite_border_24dp.svg"))
+ tool_btn_text.setIcon(QIcon("icons:favorite_border_24dp.svg"))
+ tool_btn_text.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
+ tool_btn_text.setText("Text")
+ tool_btn_toggled.setCheckable(True)
+ tool_btn_toggled.setChecked(True)
+
+ radio_btn_1.setChecked(True)
+ checkbox.setChecked(True)
+ checkbox_tristate.setTristate(True)
+ checkbox_tristate.setCheckState(Qt.CheckState.PartiallyChecked)
+
+ # Layout
+ g_layout_push = QGridLayout()
+ g_layout_push.addWidget(QLabel("Normal"), 0, 0)
+ g_layout_push.addWidget(push_btn, 1, 0)
+ g_layout_push.addWidget(push_btn_toggled, 2, 0)
+ g_layout_push.addWidget(QLabel("Flat"), 0, 1)
+ g_layout_push.addWidget(push_btn_flat, 1, 1)
+ g_layout_push.addWidget(push_btn_flat_toggled, 2, 1)
+ group_push.setLayout(g_layout_push)
+
+ v_layout_tool = QVBoxLayout()
+ v_layout_tool.addWidget(tool_btn)
+ v_layout_tool.addWidget(tool_btn_toggled)
+ v_layout_tool.addWidget(tool_btn_text)
+ group_tool.setLayout(v_layout_tool)
+
+ v_layout_radio = QVBoxLayout()
+ v_layout_radio.addWidget(radio_btn_1)
+ v_layout_radio.addWidget(radio_btn_2)
+ group_radio.setLayout(v_layout_radio)
+
+ v_layout_checkbox = QVBoxLayout()
+ v_layout_checkbox.addWidget(checkbox)
+ v_layout_checkbox.addWidget(checkbox_tristate)
+ group_checkbox.setLayout(v_layout_checkbox)
+
+ g_layout_main = QGridLayout(self)
+ g_layout_main.addWidget(group_push, 0, 0)
+ g_layout_main.addWidget(group_tool, 0, 1)
+ g_layout_main.addWidget(group_radio, 1, 0)
+ g_layout_main.addWidget(group_checkbox, 1, 1)
+
+
+class _Group2(QGroupBox):
+ def __init__(self) -> None:
+ super().__init__("Line boxes")
+ # Widgets
+ group_spinbox = QGroupBox("Spinbox")
+ group_combobox = QGroupBox("Combobox")
+ group_editable = QGroupBox("Line edit")
+ group_date = QGroupBox("Date time edit")
+
+ spinbox, spinbox_suffix = QSpinBox(), QSpinBox()
+ combobox, combobox_line_edit = QComboBox(), QComboBox()
+ lineedit = QLineEdit()
+ date_time_edit, date_time_edit_calendar = QDateTimeEdit(), QDateTimeEdit()
+
+ # Setup widgets
+ self.setCheckable(True)
+ spinbox_suffix.setSuffix(" m")
+
+ combobox.addItems(("Item 1", "Item 2", "Item 3"))
+ combobox_line_edit.addItems(("Item 1", "Item 2", "Item 3"))
+ combobox_line_edit.setEditable(True)
+
+ lineedit.setPlaceholderText("Placeholder text")
+ date_time_edit_calendar.setCalendarPopup(True)
+
+ # Layout
+ v_layout_spin = QVBoxLayout()
+ v_layout_spin.addWidget(spinbox)
+ v_layout_spin.addWidget(spinbox_suffix)
+ group_spinbox.setLayout(v_layout_spin)
+
+ v_layout_combo = QVBoxLayout()
+ v_layout_combo.addWidget(combobox)
+ v_layout_combo.addWidget(combobox_line_edit)
+ group_combobox.setLayout(v_layout_combo)
+
+ v_layout_lineedit = QVBoxLayout()
+ v_layout_lineedit.addWidget(lineedit)
+ group_editable.setLayout(v_layout_lineedit)
+
+ v_layout_date = QVBoxLayout()
+ v_layout_date.addWidget(date_time_edit)
+ v_layout_date.addWidget(date_time_edit_calendar)
+ group_date.setLayout(v_layout_date)
+
+ g_layout_main = QGridLayout(self)
+ g_layout_main.addWidget(group_spinbox, 0, 0)
+ g_layout_main.addWidget(group_combobox, 0, 1)
+ g_layout_main.addWidget(group_editable, 1, 0)
+ g_layout_main.addWidget(group_date, 1, 1)
+
+
+class _TableModel(QAbstractTableModel):
+ def __init__(self) -> None:
+ super().__init__()
+ self._data = [[i * 10 + j for j in range(4)] for i in range(5)]
+
+ def data(self, index: QModelIndex, role: int) -> Any:
+ if role == Qt.ItemDataRole.DisplayRole:
+ return self._data[index.row()][index.column()]
+ if role == Qt.ItemDataRole.CheckStateRole and index.column() == 1:
+ return Qt.CheckState.Checked if index.row() % 2 == 0 else Qt.CheckState.Unchecked
+ if role == Qt.ItemDataRole.EditRole and index.column() == 2:
+ return self._data[index.row()][index.column()] # pragma: no cover
+ return None
+
+ def rowCount(self, index) -> int: # noqa: N802
+ return len(self._data)
+
+ def columnCount(self, index) -> int: # noqa: N802
+ return len(self._data[0])
+
+ def flags(self, index: QModelIndex) -> Qt.ItemFlag:
+ flag = super().flags(index)
+ if index.column() == 1:
+ flag |= Qt.ItemFlag.ItemIsUserCheckable
+ elif index.column() in (2, 3):
+ flag |= Qt.ItemFlag.ItemIsEditable
+ return flag # type: ignore
+
+ def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> Any: # noqa: N802
+ if role != Qt.ItemDataRole.DisplayRole:
+ return None
+ if orientation == Qt.Orientation.Horizontal:
+ return ["Normal", "Checkbox", "Spinbox", "LineEdit"][section]
+ return super().headerData(section, orientation, role)
+
+
+class _Group3(QGroupBox):
+ def __init__(self) -> None:
+ super().__init__("Scroll area and QTabWidget (QGroupBox.flat = True)")
+
+ # Widgets
+ tab_widget = QTabWidget()
+ tab_text_edit = QTextEdit()
+ tab_table = QTableView()
+ tab_list = QListWidget()
+ tab_tree = QTreeWidget()
+
+ # Setup widgets
+ self.setCheckable(True)
+ self.setFlat(True)
+ tab_widget.setTabsClosable(True)
+ tab_widget.setMovable(True)
+ tab_text_edit.append("PyQtDarkTheme")
+ tab_text_edit.append("Dark theme for PySide and PyQt.")
+ tab_text_edit.append("This project is licensed under the MIT license.")
+ tab_text_edit.setWordWrapMode(QTextOption.WrapMode.NoWrap)
+
+ tab_table.setModel(_TableModel())
+ tab_table.setSortingEnabled(True)
+
+ tab_list.addItems([f"Item {i+1}" for i in range(30)])
+ tab_list.setAlternatingRowColors(True)
+
+ tab_tree.setColumnCount(2)
+ for i in range(5):
+ item = QTreeWidgetItem([f"Item {i+1}" for _ in range(2)])
+ for j in range(2):
+ item.addChild(QTreeWidgetItem([f"Child Item {i+1}_{j+1}" for _ in range(2)]))
+ tab_tree.insertTopLevelItem(i, item)
+
+ # layout
+ tab_widget.addTab(tab_table, "Table")
+ tab_widget.addTab(tab_text_edit, "Text Edit")
+ tab_widget.addTab(tab_list, "List")
+ tab_widget.addTab(tab_tree, "Tree")
+
+ v_layout_main = QVBoxLayout(self)
+ v_layout_main.addWidget(tab_widget)
+
+
+class _Group4(QGroupBox):
+ def __init__(self) -> None:
+ super().__init__("QToolBox")
+ # Widgets
+ toolbox = QToolBox()
+ slider = QSlider(Qt.Orientation.Horizontal)
+ dial_ticks = QDial()
+ progressbar = QProgressBar()
+ lcd_number = QLCDNumber()
+
+ # Setup widgets
+ self.setCheckable(True)
+ toolbox.addItem(slider, "Slider")
+ toolbox.addItem(dial_ticks, "Dial")
+ toolbox.addItem(progressbar, "Progress Bar")
+ toolbox.addItem(lcd_number, "LCD Number")
+ slider.setValue(50)
+ dial_ticks.setNotchesVisible(True)
+ progressbar.setValue(50)
+ lcd_number.setSegmentStyle(QLCDNumber.SegmentStyle.Flat)
+ lcd_number.display(123)
+
+ # Layout
+ v_layout = QVBoxLayout(self)
+ v_layout.addWidget(toolbox)
+
+
+class WidgetsUI:
+ """The ui class of widgets window."""
+
+ def setup_ui(self, win: QWidget) -> None:
+ """Set up ui."""
+ # Widgets
+ h_splitter_1, h_splitter_2 = QSplitter(Qt.Orientation.Horizontal), QSplitter(Qt.Orientation.Horizontal)
+
+ # Setup widgets
+ h_splitter_1.setMinimumHeight(350) # Fix bug layout crush
+
+ # Layout
+ h_splitter_1.addWidget(_Group1())
+ h_splitter_1.addWidget(_Group2())
+ h_splitter_2.addWidget(_Group3())
+ h_splitter_2.addWidget(_Group4())
+
+ widget_container = QWidget()
+ v_layout = QVBoxLayout(widget_container)
+ v_layout.addWidget(h_splitter_1)
+ v_layout.addWidget(h_splitter_2)
+
+ scroll_area = QScrollArea()
+ scroll_area.setWidget(widget_container)
+
+ v_main_layout = QVBoxLayout(win)
+ v_main_layout.addWidget(scroll_area)
diff --git a/requirements.txt b/requirements.txt
index e819fd51..e01a83b7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -47,7 +47,7 @@ pyopengl
pyqt6>=6.1.0
freetype-py
vispy>=0.9.0
-pyqtdarktheme==1.1.1
+# pyqtdarktheme==1.1.1
svgtrace