- added qdarktheme package into the code

This commit is contained in:
Marius Stanciu
2023-10-19 13:49:14 +03:00
parent 656bec2e7c
commit 28dbb70126
42 changed files with 3548 additions and 22 deletions

View File

@@ -0,0 +1,8 @@
"""Example of PyQtDarkTheme use for Qt applications.
To check example app, run:
```shell
python -m qdarktheme.widget_gallery
```
"""

View File

@@ -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()

View File

@@ -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")

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8 9c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1s1 .45 1 1v4c0 .55-.45 1-1 1zm1 4h-2v-2h2v2z"/></svg>

After

Width:  |  Height:  |  Size: 308 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#008000"><g><rect fill="none" height="24" width="24"/></g><g><path d="M12,2C6.47,2,2,6.47,2,12c0,5.53,4.47,10,10,10s10-4.47,10-10C22,6.47,17.53,2,12,2z M12,20c-4.42,0-8-3.58-8-8 c0-4.42,3.58-8,8-8s8,3.58,8,8C20,16.42,16.42,20,12,20z"/></g></svg>

After

Width:  |  Height:  |  Size: 372 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FF0000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M18.3 5.71c-.39-.39-1.02-.39-1.41 0L12 10.59 7.11 5.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41L10.59 12 5.7 16.89c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 13.41l4.89 4.89c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z"/></svg>

After

Width:  |  Height:  |  Size: 430 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><g><rect fill="none" height="24" width="24"/></g><g><path d="M12,22c5.52,0,10-4.48,10-10S17.52,2,12,2S2,6.48,2,12S6.48,22,12,22z M13,4.07c3.94,0.49,7,3.85,7,7.93s-3.05,7.44-7,7.93 V4.07z"/></g></svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14z"/></svg>

After

Width:  |  Height:  |  Size: 249 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#ff1493"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19.66 3.99c-2.64-1.8-5.9-.96-7.66 1.1-1.76-2.06-5.02-2.91-7.66-1.1-1.4.96-2.28 2.58-2.34 4.29-.14 3.88 3.3 6.99 8.55 11.76l.1.09c.76.69 1.93.69 2.69-.01l.11-.1c5.25-4.76 8.68-7.87 8.55-11.75-.06-1.7-.94-3.32-2.34-4.28zM12.1 18.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z"/></svg>

After

Width:  |  Height:  |  Size: 548 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm2 4v-2H3c0 1.1.89 2 2 2zM3 9h2V7H3v2zm12 12h2v-2h-2v2zm4-18H9c-1.11 0-2 .9-2 2v10c0 1.1.89 2 2 2h10c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 12h-8c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h8c.55 0 1 .45 1 1v8c0 .55-.45 1-1 1zm-7 6h2v-2h-2v2zm-4 0h2v-2H7v2z"/></svg>

After

Width:  |  Height:  |  Size: 432 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 6h-8l-1.41-1.41C10.21 4.21 9.7 4 9.17 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-1 12H5c-.55 0-1-.45-1-1V9c0-.55.45-1 1-1h14c.55 0 1 .45 1 1v8c0 .55-.45 1-1 1z"/></svg>

After

Width:  |  Height:  |  Size: 360 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9.93 13.5h4.14L12 7.98 9.93 13.5zM20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-4.29 15.88l-.9-2.38H9.17l-.89 2.37c-.14.38-.5.63-.91.63-.68 0-1.15-.69-.9-1.32l4.25-10.81c.22-.53.72-.87 1.28-.87s1.06.34 1.27.87l4.25 10.81c.25.63-.22 1.32-.9 1.32-.4 0-.76-.25-.91-.62z"/></svg>

After

Width:  |  Height:  |  Size: 457 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><g><rect fill="none" height="24" width="24"/></g><g><path d="M12,2C6.49,2,2,6.49,2,12s4.49,10,10,10c1.38,0,2.5-1.12,2.5-2.5c0-0.61-0.23-1.2-0.64-1.67c-0.08-0.1-0.13-0.21-0.13-0.33 c0-0.28,0.22-0.5,0.5-0.5H16c3.31,0,6-2.69,6-6C22,6.04,17.51,2,12,2z M17.5,13c-0.83,0-1.5-0.67-1.5-1.5c0-0.83,0.67-1.5,1.5-1.5 s1.5,0.67,1.5,1.5C19,12.33,18.33,13,17.5,13z M14.5,9C13.67,9,13,8.33,13,7.5C13,6.67,13.67,6,14.5,6S16,6.67,16,7.5 C16,8.33,15.33,9,14.5,9z M5,11.5C5,10.67,5.67,10,6.5,10S8,10.67,8,11.5C8,12.33,7.33,13,6.5,13S5,12.33,5,11.5z M11,7.5 C11,8.33,10.33,9,9.5,9S8,8.33,8,7.5C8,6.67,8.67,6,9.5,6S11,6.67,11,7.5z"/></g></svg>

After

Width:  |  Height:  |  Size: 758 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><rect fill="none" height="24" width="24"/><path d="M19.5,12c0-0.23-0.01-0.45-0.03-0.68l1.86-1.41c0.4-0.3,0.51-0.86,0.26-1.3l-1.87-3.23c-0.25-0.44-0.79-0.62-1.25-0.42 l-2.15,0.91c-0.37-0.26-0.76-0.49-1.17-0.68l-0.29-2.31C14.8,2.38,14.37,2,13.87,2h-3.73C9.63,2,9.2,2.38,9.14,2.88L8.85,5.19 c-0.41,0.19-0.8,0.42-1.17,0.68L5.53,4.96c-0.46-0.2-1-0.02-1.25,0.42L2.41,8.62c-0.25,0.44-0.14,0.99,0.26,1.3l1.86,1.41 C4.51,11.55,4.5,11.77,4.5,12s0.01,0.45,0.03,0.68l-1.86,1.41c-0.4,0.3-0.51,0.86-0.26,1.3l1.87,3.23c0.25,0.44,0.79,0.62,1.25,0.42 l2.15-0.91c0.37,0.26,0.76,0.49,1.17,0.68l0.29,2.31C9.2,21.62,9.63,22,10.13,22h3.73c0.5,0,0.93-0.38,0.99-0.88l0.29-2.31 c0.41-0.19,0.8-0.42,1.17-0.68l2.15,0.91c0.46,0.2,1,0.02,1.25-0.42l1.87-3.23c0.25-0.44,0.14-0.99-0.26-1.3l-1.86-1.41 C19.49,12.45,19.5,12.23,19.5,12z M12.04,15.5c-1.93,0-3.5-1.57-3.5-3.5s1.57-3.5,3.5-3.5s3.5,1.57,3.5,3.5S13.97,15.5,12.04,15.5z"/></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#d89e76"><path d="M0 0h24v24H0z" fill="none"/><path d="M13 13v8h8v-8h-8zM3 21h8v-8H3v8zM3 3v8h8V3H3zm13.66-1.31L11 7.34 16.66 13l5.66-5.66-5.66-5.65z"/></svg>

After

Width:  |  Height:  |  Size: 251 B

View File

@@ -0,0 +1 @@
"""Package including ui for WidgetGallery."""

View File

@@ -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)

View File

@@ -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)

View File

@@ -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("<b>PyQtDarkTheme</b>")
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)