Skip to content

Instantly share code, notes, and snippets.

@wmalarski
Created November 13, 2019 23:53
Show Gist options
  • Save wmalarski/2a64b836f843ceb89e95dd71114f725d to your computer and use it in GitHub Desktop.
Save wmalarski/2a64b836f843ceb89e95dd71114f725d to your computer and use it in GitHub Desktop.
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