eric7/EricWidgets/EricIconBar.py

Mon, 06 Sep 2021 19:52:37 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 06 Sep 2021 19:52:37 +0200
branch
eric7
changeset 8583
aac629a05f8b
child 8584
90391fda03d5
permissions
-rw-r--r--

Modernized the look of the side bars.

# -*- coding: utf-8 -*-

# Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a bar widget showing just icons.
"""

from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt
from PyQt6.QtGui import QColor
from PyQt6.QtWidgets import QWidget, QBoxLayout, QWIDGETSIZE_MAX

from .EricClickableLabel import EricClickableLabel


class EricIconBar(QWidget):
    """
    Class implementing a bar widget showing just icons.
    
    @signal currentChanged(index) emitted to indicate a change of the current
        index
    @signal currentClicked(index) emitted to indicate, that the current icon
        was clicked
    """
    IconSize = 48
    BorderSize = 2
    
    WidgetStyleSheetTemplate = "QWidget {{ background-color: {0}; }}"
    LabelStyleSheetTemplate = "QLabel {{ background-color: {0}; }}"
    
    currentChanged = pyqtSignal(int)
    currentClicked = pyqtSignal(int)
    
    def __init__(self, orientation=Qt.Orientation.Horizontal, parent=None):
        """
        Constructor
        
        @param orientation orientation for the widget
        @type Qt.Orientation
        @param parent reference to the parent widget (defaults to None)
        @type QWidget (optional)
        """
        super().__init__(parent)
        
        self.__fixedHeightWidth = (
            EricIconBar.IconSize + 2 * EricIconBar.BorderSize
        )
        
        # set initial values
        self.__color = QColor("#008800")
        self.__orientation = Qt.Orientation.Horizontal
        self.__currentIndex = -1
        
        # initialize with horizontal layout and change later if needed
        self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
        self.setFixedHeight(self.__fixedHeightWidth)
        
        self.__layout = QBoxLayout(QBoxLayout.Direction.LeftToRight)
        self.__layout.setContentsMargins(
            EricIconBar.BorderSize, EricIconBar.BorderSize,
            EricIconBar.BorderSize, EricIconBar.BorderSize)
        self.__layout.setSpacing(EricIconBar.BorderSize)
        
        self.__layout.addStretch()
        
        self.setLayout(self.__layout)
        
        if orientation != self.__orientation:
            self.setOrientation(orientation)
        
        self.setColor(self.__color)
    
    def setOrientation(self, orientation):
        """
        Public method to set the widget orientation.
        
        @param orientation orientation to be set
        @type Qt.Orientation
        """
        # reset list widget size constraints
        self.setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)
        
        if orientation == Qt.Orientation.Horizontal:
            self.setFixedHeight(self.__fixedHeightWidth)
            self.__layout.setDirection(QBoxLayout.Direction.LeftToRight)
        elif orientation == Qt.Orientation.Vertical:
            self.setFixedWidth(self.__fixedHeightWidth)
            self.__layout.setDirection(QBoxLayout.Direction.TopToBottom)
        
        self.__orientation = orientation
    
    def orientation(self):
        """
        Public method to get the orientation of the widget.
        
        @return orientation of the widget
        @rtype Qt.Orientation
        """
        return self.__orientation
    
    def setColor(self, color):
        """
        Public method to set the color of the widget.
        
        @param color color of the widget
        @type QColor
        """
        self.__color = color
        self.__highlightColor = color.darker()
        
        self.setStyleSheet(
            EricIconBar.WidgetStyleSheetTemplate.format(color.name()))
        
        label = self.__layout.itemAt(self.__currentIndex)
        if label:
            label.widget().setStyleSheet(
                EricIconBar.LabelStyleSheetTemplate
                .format(self.__highlightColor.name())
            )
    
    def color(self):
        """
        Public method to return the current color.
        
        @return current color
        @rtype QColor
        """
        return self.__color
    
    def __createIcon(self, iconPixmap, label=""):
        """
        Private method to creat an icon label.
        
        @param iconPixmap reference to the icon
        @type QPixmap
        @param label label text to be shown as a tooltip (defaults to "")
        @type str (optional)
        @return created and connected label
        @rtype EricClickableLabel
        """
        iconLabel = EricClickableLabel(self)
        iconLabel.setFixedSize(EricIconBar.IconSize, EricIconBar.IconSize)
        iconLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
        iconLabel.setPixmap(iconPixmap)
        if label:
            iconLabel.setToolTip(label)
        
        iconLabel.clicked.connect(lambda: self.__iconClicked(iconLabel))
        
        return iconLabel
    
    def addIcon(self, iconPixmap, label=""):
        """
        Public method to add an icon to the bar.
        
        @param iconPixmap reference to the icon
        @type QPixmap
        @param label label text to be shown as a tooltip (defaults to "")
        @type str (optional)
        """
        # the stretch item is always the last one
        self.insertIcon(self.count(), iconPixmap, label=label)
    
    def insertIcon(self, index, iconPixmap, label=""):
        """
        Public method to insert an icon into the bar.
        
        @param index position to insert the icon at
        @type int
        @param iconPixmap reference to the icon
        @type QPixmap
        @param label label text to be shown as a tooltip (defaults to "")
        @type str (optional)
        """
        iconLabel = self.__createIcon(iconPixmap, label=label)
        self.__layout.insertWidget(index, iconLabel)
        
        if self.__currentIndex < 0:
            self.setCurrentIndex(index)
        elif index <= self.__currentIndex:
            self.setCurrentIndex(self.__currentIndex + 1)
    
    def removeIcon(self, index):
        """
        Public method to remove an icon from the bar.
        
        @param index index of the icon to be removed
        @type int
        """
        label = self.__layout.itemAt(index)
        self.__layout.removeWidget(label)
        
        if index == self.__currentIndex:
            self.setCurrentIndex(index)
        elif index < self.__currentIndex:
            self.setCurrentIndex(self.__currentIndex - 1)
    
    @pyqtSlot()
    def __iconClicked(self, label):
        """
        Private slot to handle an icon been clicked.
        
        @param label reference to the clicked label
        @type EricClickableLabel
        """
        index = self.__layout.indexOf(label)
        if index == self.__currentIndex:
            self.currentClicked.emit(self.__currentIndex)
        else:
            self.setCurrentIndex(index)
    
    def setCurrentIndex(self, index):
        """
        Public method to set the current index.
        
        @param index current index to be set
        @type int
        """
        if index >= self.count():
            index = -1
        
        if index != self.__currentIndex:
            # reset style of previous current icon
            oldLabel = self.__layout.itemAt(self.__currentIndex)
            if oldLabel:
                oldLabel.widget().setStyleSheet("")
            
            # set style of new current icon
            newLabel = self.__layout.itemAt(index)
            if newLabel:
                newLabel.widget().setStyleSheet(
                    EricIconBar.LabelStyleSheetTemplate
                    .format(self.__highlightColor.name())
                )
            
            self.__currentIndex = index
            self.currentChanged.emit(self.__currentIndex)
    
    def currentIndex(self):
        """
        Public method to get the current index.
        
        @return current index
        @rtype int
        """
        return self.__currentIndex
    
    def count(self):
        """
        Public method to get the number of icon labels.
        
        @return number of icon labels
        @rtype int
        """
        return self.__layout.count() - 1
    
    def wheelEvent(self, evt):
        """
        Protected method to handle a wheel event.
        
        @param evt reference to the wheel event
        @type QWheelEvent
        """
        delta = evt.angleDelta().y()
        if delta > 0:
            self.previousIcon()
        else:
            self.nextIcon()
    
    @pyqtSlot()
    def previousIcon(self):
        """
        Public slot to set the icon before the current one.
        """
        index = self.__currentIndex - 1
        if index < 0:
            # wrap around
            index = self.count() - 1
        
        self.setCurrentIndex(index)
    
    @pyqtSlot()
    def nextIcon(self):
        """
        Public slot to set the icon after the current one.
        """
        index = self.__currentIndex + 1
        if index == self.count():
            # wrap around
            index = 0
        
        self.setCurrentIndex(index)

eric ide

mercurial