--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricWidgets/EricIconBar.py Mon Sep 06 19:52:37 2021 +0200 @@ -0,0 +1,293 @@ +# -*- 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)