Created
November 13, 2019 23:53
-
-
Save wmalarski/2a64b836f843ceb89e95dd71114f725d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
from enum import Enum, IntEnum | |
from typing import Dict, Union, List | |
from PySide2.QtCore import Qt, QObject, QModelIndex | |
from PySide2.QtGui import QPaintEvent, QPalette, QColor | |
from PySide2.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout, QTreeWidget, QTreeWidgetItem, \ | |
QToolButton, QWidgetAction, QCheckBox, QAction, QDockWidget, QPushButton, QStyle, QStylePainter, QStyleOptionButton, \ | |
QStyleOptionToolButton, QFrame, QLabel, QVBoxLayout | |
class UnderScoreToolButton(QWidget): | |
class Position(Enum): | |
Top = 'top' | |
Bottom = 'bottom' | |
Left = 'left' | |
Right = 'right' | |
def __init__(self, position: Position, parent): | |
super().__init__(parent) | |
horizontal = position in [self.Position.Bottom, self.Position.Top] | |
layout = QVBoxLayout(self) if horizontal else QHBoxLayout(self) | |
layout.setContentsMargins(0, 0, 0, 0) | |
layout.setSpacing(1) | |
self.setLayout(layout) | |
self.button = QToolButton(self) | |
layout.addWidget(self.button) | |
self.button.clicked.connect(self._on_button_clicked) | |
self._label = QLabel(self) | |
if horizontal: | |
self._label.setFixedHeight(2) | |
else: | |
self._label.setFixedWidth(2) | |
if position in [self.Position.Top, self.Position.Left]: | |
layout.insertWidget(0, self._label) | |
else: | |
layout.addWidget(self._label) | |
def _redraw_line(self): | |
palette: QPalette = self.palette() | |
color = palette.color(QPalette.WindowText if self.button.isChecked() else QPalette.Window) | |
self._label.setStyleSheet(f"background: rgb({color.red()}, {color.green()}, {color.blue()});") | |
def _on_button_clicked(self, toggled): | |
self._redraw_line() | |
class CheckToolButton(QToolButton): | |
def __init__(self, parent): | |
super().__init__(parent) | |
def initStyleOption(self, option: QStyleOptionToolButton): | |
if option is None: | |
return | |
option.initFrom(self) | |
if self.isChecked(): | |
option.state |= QStyle.State_Sunken | |
option.state |= QStyle.State_On if self.isChecked() else QStyle.State_Off | |
if self.testAttribute(Qt.WA_Hover) and self.underMouse(): | |
option.state |= QStyle.State_MouseOver | |
else: | |
option.state ^= QStyle.State_MouseOver | |
option.text = self.text() | |
option.icon = self.icon() | |
option.iconSize = self.iconSize() | |
def paintEvent(self, event: QPaintEvent): | |
p = QStylePainter(self) | |
opt = QStyleOptionButton() | |
self.initStyleOption(opt) | |
p.drawControl(QStyle.CE_CheckBox, opt) | |
class MainWidget(QWidget): | |
_actions = { | |
'aaa': { | |
'int_sss': 'sss1', | |
'int_ssd': 'sss2', | |
'int_ssf': 'sss3', | |
}, | |
'bbb': { | |
'ccc': { | |
'int_ssg': 'sss4', | |
'int_ssh': 'sss5', | |
}, | |
'int_ssj': 'sss6', | |
'int_ssk': 'sss7', | |
} | |
} | |
ActionRole = 111 | |
ActionResetRole = 112 | |
def __init__(self, parent): | |
super().__init__(parent) | |
layout = QHBoxLayout(self) | |
self.setLayout(layout) | |
self._tree_widget = QTreeWidget(self) | |
self._tree_widget.setColumnCount(2) | |
self.tools_actions = self._build_tree(self._tree_widget, self._tree_widget.invisibleRootItem(), self._actions) | |
layout.addWidget(self._tree_widget) | |
@staticmethod | |
def _build_tree(tree: QTreeWidget, tree_item: QTreeWidgetItem, actions_dict: Dict[str, Union[Dict, str]]): | |
actions = [] | |
for action_str, union in actions_dict.items(): | |
child_item = QTreeWidgetItem(tree_item) | |
child_item.setText(0, action_str) | |
child_item.setCheckState(0, Qt.Unchecked) | |
tree_item.addChild(child_item) | |
if isinstance(union, dict): | |
actions += MainWidget._build_tree(tree, child_item, union) | |
elif isinstance(union, str): | |
tool_button = CheckToolButton(tree) | |
tree.setItemWidget(child_item, 1, tool_button) | |
dock = QDockWidget(union, tree) | |
tree.window().addDockWidget(Qt.LeftDockWidgetArea, dock) | |
action = dock.toggleViewAction() | |
child_item.setData(0, MainWidget.ActionRole, action) | |
child_item.setData(0, MainWidget.ActionResetRole, False) | |
dock.setVisible(False) | |
tool_button.setDefaultAction(action) | |
action.setText(action_str) | |
actions.append((child_item, action)) | |
return actions | |
class MainWindow(QMainWindow): | |
def __init__(self): | |
super().__init__() | |
widget = MainWidget(self) | |
self.setCentralWidget(widget) | |
tool_bar = self.addToolBar("main") | |
for action in list(zip(*widget.tools_actions))[1]: | |
button = UnderScoreToolButton(UnderScoreToolButton.Position.Bottom, self) | |
button.button.setDefaultAction(action) | |
tool_bar.addWidget(button) | |
def main(): | |
# Create the Qt Application | |
app = QApplication(sys.argv) | |
# Create and show the form | |
mw = MainWindow() | |
mw.show() | |
# Run the main Qt loop | |
sys.exit(app.exec_()) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment