--- a/eric7/EricWidgets/EricIconBar.py Fri Nov 12 17:58:46 2021 +0100 +++ b/eric7/EricWidgets/EricIconBar.py Mon Nov 15 19:50:39 2021 +0100 @@ -10,11 +10,15 @@ import contextlib from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QCoreApplication -from PyQt6.QtGui import QColor, QIcon -from PyQt6.QtWidgets import QWidget, QBoxLayout, QWIDGETSIZE_MAX +from PyQt6.QtGui import QColor, QIcon, QCursor, QPalette +from PyQt6.QtWidgets import QWidget, QBoxLayout, QWIDGETSIZE_MAX, QMenu + +from EricWidgets.EricApplication import ericApp from .EricClickableLabel import EricClickableLabel +import UI.PixmapCache + class EricIconBar(QWidget): """ @@ -54,6 +58,13 @@ } DefaultBarSize = "md" + MoreLabelAspect = 36 / 96 + + MenuStyleSheetTemplate = ( + "QMenu {{ background-color: {0}; " + "selection-background-color: {1}; " + "border: 1px solid; }}" + ) WidgetStyleSheetTemplate = "QWidget {{ background-color: {0}; }}" LabelStyleSheetTemplate = "QLabel {{ background-color: {0}; }}" @@ -85,6 +96,8 @@ self.__fixedHeightWidth = ( self.__barSize + 2 * self.__borderSize ) + self.__minimumHeightWidth = int( + self.__barSize * self.MoreLabelAspect) + 2 * self.__borderSize # set initial values self.__color = QColor("#008800") @@ -95,6 +108,7 @@ # initialize with horizontal layout and change later if needed self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) self.setFixedHeight(self.__fixedHeightWidth) + self.setMinimumWidth(self.__minimumHeightWidth) self.__layout = QBoxLayout(QBoxLayout.Direction.LeftToRight) self.__layout.setContentsMargins( @@ -109,6 +123,11 @@ self.setOrientation(orientation) self.setColor(self.__color) + + self.__createMoreLabel() + self.__layout.insertWidget(0, self.__moreLabel) + + self.__adjustIconLabels() def setOrientation(self, orientation): """ @@ -120,14 +139,26 @@ # reset list widget size constraints self.setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) + # remove the 'More' icon + itm = self.__layout.takeAt(self.__layout.count() - 2) + itm.widget().deleteLater() + del itm + if orientation == Qt.Orientation.Horizontal: self.setFixedHeight(self.__fixedHeightWidth) + self.setMinimumWidth(self.__minimumHeightWidth) self.__layout.setDirection(QBoxLayout.Direction.LeftToRight) elif orientation == Qt.Orientation.Vertical: self.setFixedWidth(self.__fixedHeightWidth) + self.setMinimumHeight(self.__minimumHeightWidth) self.__layout.setDirection(QBoxLayout.Direction.TopToBottom) self.__orientation = orientation + + self.__createMoreLabel() + self.__layout.insertWidget(self.__layout.count() - 1, self.__moreLabel) + + self.__adjustIconLabels() def orientation(self): """ @@ -146,17 +177,26 @@ 'lg', 'xl', 'xxl') @type str """ + # remove the 'More' icon + itm = self.__layout.takeAt(self.__layout.count() - 2) + itm.widget().deleteLater() + del itm + self.__barSize, self.__borderSize = ( EricIconBar.BarSizes[barSize][:2]) self.__barSizeKey = barSize self.__fixedHeightWidth = ( self.__barSize + 2 * self.__borderSize ) + self.__minimumHeightWidth = int( + self.__barSize * self.MoreLabelAspect) + 2 * self.__borderSize if self.__orientation == Qt.Orientation.Horizontal: self.setFixedHeight(self.__fixedHeightWidth) + self.setMinimumWidth(self.__minimumHeightWidth) elif self.__orientation == Qt.Orientation.Vertical: self.setFixedWidth(self.__fixedHeightWidth) + self.setMinimumHeight(self.__minimumHeightWidth) self.__layout.setContentsMargins( self.__borderSize, self.__borderSize, @@ -169,6 +209,11 @@ widget.setFixedSize(self.__barSize, self.__barSize) widget.setPixmap( icon.pixmap(self.__barSize, self.__barSize)) + + self.__createMoreLabel() + self.__layout.insertWidget(self.__layout.count() - 1, self.__moreLabel) + + self.__adjustIconLabels() def barSize(self): """ @@ -231,6 +276,31 @@ return iconLabel + def __createMoreLabel(self): + """ + Private method to create the label to be shown for too many icons. + """ + self.__moreLabel = EricClickableLabel(self) + self.__moreLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) + if self.__orientation == Qt.Orientation.Horizontal: + self.__moreLabel.setFixedSize( + int(self.__barSize * self.MoreLabelAspect), self.__barSize) + self.__moreLabel.setPixmap( + UI.PixmapCache.getIcon("sbDotsH96").pixmap( + int(self.__barSize * self.MoreLabelAspect), self.__barSize + ) + ) + else: + self.__moreLabel.setFixedSize( + self.__barSize, int(self.__barSize * self.MoreLabelAspect)) + self.__moreLabel.setPixmap( + UI.PixmapCache.getIcon("sbDotsV96").pixmap( + self.__barSize, int(self.__barSize * self.MoreLabelAspect) + ) + ) + + self.__moreLabel.clicked.connect(self.__moreLabelClicked) + def addIcon(self, icon, label=""): """ Public method to add an icon to the bar. @@ -262,6 +332,8 @@ self.setCurrentIndex(index) elif index <= self.__currentIndex: self.setCurrentIndex(self.__currentIndex + 1) + + self.__adjustIconLabels() def removeIcon(self, index): """ @@ -282,6 +354,8 @@ self.setCurrentIndex(index) elif index < self.__currentIndex: self.setCurrentIndex(self.__currentIndex - 1) + + self.__adjustIconLabels() @pyqtSlot() def __iconClicked(self, label): @@ -343,7 +417,7 @@ @return number of icon labels @rtype int """ - return self.__layout.count() - 1 + return len(self.__icons) def wheelEvent(self, evt): """ @@ -381,3 +455,76 @@ index = 0 self.setCurrentIndex(index) + + @pyqtSlot() + def __moreLabelClicked(self): + """ + Private slot to handle a click onto the 'More' label. + """ + menu = QMenu(self) + baseColor = ericApp().palette().color( + QPalette.ColorRole.Base) + highlightColor = ericApp().palette().color( + QPalette.ColorRole.Highlight) + menu.setStyleSheet( + EricIconBar.MenuStyleSheetTemplate.format( + baseColor.name(), highlightColor.name())) + + for index in range(self.__layout.count() - 2): + iconLabel = self.__layout.itemAt(index) + if iconLabel: + widget = iconLabel.widget() + if not widget.isVisible(): + act = menu.addAction(widget.toolTip()) + act.setData(index) + + selectedAction = menu.exec(QCursor.pos()) + if selectedAction is not None: + index = selectedAction.data() + if index >= 0: + if index == self.__currentIndex: + self.currentClicked.emit(self.__currentIndex) + else: + self.setCurrentIndex(index) + + def resizeEvent(self, evt): + """ + Protected method to handle resizing of the icon bar. + + @param evt reference to the event object + @type QResizeEvent + """ + self.__adjustIconLabels() + + def __adjustIconLabels(self): + """ + Private method to adjust the visibility of the icon labels. + """ + size = ( + self.width() + if self.orientation() == Qt.Orientation.Horizontal else + self.height() + ) - 2 * self.__borderSize + + iconsSize = ( + self.count() * self.__barSize + + (self.count() - 1) * self.__layout.spacing() + ) + + if size < iconsSize: + self.__moreLabel.show() + iconsSize += int(self.__barSize * self.MoreLabelAspect) + for index in range(self.count() - 1, -1, -1): + iconLabel = self.__layout.itemAt(index) + if iconLabel: + if size < iconsSize: + iconLabel.widget().hide() + iconsSize -= self.__barSize - self.__layout.spacing() + else: + iconLabel.widget().show() + else: + self.__moreLabel.hide() + for index in range(self.__layout.count() - 2): + iconLabel = self.__layout.itemAt(index) + if iconLabel: + iconLabel.widget().show()