eric7/EricWidgets/EricIconBar.py

branch
eric7
changeset 8768
09a4a3c5b161
parent 8725
842ba8a9dbbb
child 8772
70f9dfe7116a
--- 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()

eric ide

mercurial