#!/usr/bin/env python # --!-- coding: utf8 --!-- from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QToolBar, QDockWidget, QAction, QToolButton, QSizePolicy, QStylePainter, \ QStyleOptionButton, QStyle from manuskript.ui import style class collapsibleDockWidgets(QToolBar): """ QMainWindow "mixin" which provides auto-hiding support for dock widgets (not toolbars). """ TRANSPOSED_AREA = { Qt.LeftDockWidgetArea: Qt.LeftToolBarArea, Qt.RightDockWidgetArea: Qt.RightToolBarArea, Qt.TopDockWidgetArea: Qt.TopToolBarArea, Qt.BottomDockWidgetArea: Qt.BottomToolBarArea, } def __init__(self, area, parent, name=""): QToolBar.__init__(self, parent) self._area = area if not name: name = self.tr("Dock Widgets Toolbar") self.setObjectName(name) self.setWindowTitle(name) self.setFloatable(False) self.setMovable(False) # self.setAllowedAreas(self.TRANSPOSED_AREA[self._area]) self.parent().addToolBar(self.TRANSPOSED_AREA[self._area], self) self._dockToButtonAction = {} # Dock widgets for d in self._dockWidgets(): b = verticalButton(self) b.setDefaultAction(d.toggleViewAction()) # d.setStyleSheet("QDockWidget::title{background-color: red;}") # d.setTitleBarWidget(QLabel(d.windowTitle())) d.setStyleSheet(style.dockSS()) a = self.addWidget(b) self._dockToButtonAction[d] = a self.addSeparator() # Other widgets self.otherWidgets = [] self.currentGroup = None self.setStyleSheet(style.toolBarSS()) self.layout().setContentsMargins(0,0,0,0) def _dockWidgets(self): mw = self.parent() for w in mw.findChildren(QDockWidget, None): yield w def addCustomWidget(self, text, widget, group=None, defaultVisibility=True): """ Adds a custom widget to the toolbar. `text` is the name that will displayed on the button to switch visibility. `widget` is the widget to control from the toolbar. `group` is an integer (or any hashable) if the current widget should not be displayed all the time. Call `collapsibleDockWidgets.setCurrentGroup` to switch to that group and hide other widgets. `defaultVisibility` is the default visibility of the item when it is added. This allows for the widget to be added to `collapsibleDockWidgets` after they've been created but before they are shown, and yet specify their desired visibility. Otherwise it creates troubles, see #167 on github: https://github.com/olivierkes/manuskript/issues/167. """ a = QAction(text, self) a.setCheckable(True) a.setChecked(defaultVisibility) a.toggled.connect(widget.setVisible) widget.setVisible(defaultVisibility) # widget.installEventFilter(self) b = verticalButton(self) b.setDefaultAction(a) #b.setChecked(widget.isVisible()) a2 = self.addWidget(b) self.otherWidgets.append((b, a2, widget, group)) # def eventFilter(self, widget, event): # if event.type() in [QEvent.Show, QEvent.Hide]: # for btn, action, w, grp in self.otherWidgets: # if w == widget: # btn.defaultAction().setChecked(event.type() == QEvent.Show) # return False def setCurrentGroup(self, group): self.currentGroup = group for btn, action, widget, grp in self.otherWidgets: if not grp == group or grp is None: action.setVisible(False) else: action.setVisible(True) def setDockVisibility(self, dock, val): dock.setVisible(val) self._dockToButtonAction[dock].setVisible(val) def saveState(self): """ Saves and returns the state of the custom widgets. The visibility of the docks is not saved since it is included in `QMainWindow.saveState`. """ state = [] for btn, act, w, grp in self.otherWidgets: state.append( (grp, btn.text(), btn.isChecked()) ) return state def restoreState(self, state): """Restores the state of the custom widgets.""" for group, title, status in state: for btn, act, widget, grp in self.otherWidgets: # Strip '&' from both title and btn.text() to improve matching because # title contains "&" shortcut character whereas btn.text() does not. if group == grp and title.replace('&', '') == btn.text().replace('&', ''): btn.setChecked(status) btn.defaultAction().setChecked(status) widget.setVisible(status) class verticalButton(QToolButton): def __init__(self, parent): QToolButton.__init__(self, parent) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum) self.setStyleSheet(style.verticalToolButtonSS()) def sizeHint(self): return QToolButton.sizeHint(self).transposed() def paintEvent(self, event): p = QStylePainter(self) p.rotate(90) p.translate(0, - self.width()) opt = QStyleOptionButton() opt.initFrom(self) opt.text = self.text() if self.isChecked(): opt.state |= QStyle.State_On s = opt.rect.size().transposed() opt.rect.setSize(s) p.drawControl(QStyle.CE_PushButton, opt)