eric7/E5Gui/E5Led.py

branch
eric7
changeset 8312
800c432b34c8
parent 8268
6b8128e0c9d1
child 8318
962bce857696
diff -r 4e8b98454baa -r 800c432b34c8 eric7/E5Gui/E5Led.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/E5Gui/E5Led.py	Sat May 15 18:45:04 2021 +0200
@@ -0,0 +1,336 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2006 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a LED widget.
+
+It was inspired by KLed.
+"""
+
+import enum
+
+from PyQt5.QtCore import pyqtSignal, Qt, QSize, QPoint
+from PyQt5.QtGui import QColor, QRadialGradient, QPalette, QPainter, QBrush
+from PyQt5.QtWidgets import QWidget
+
+
+class E5LedType(enum.Enum):
+    """
+    Class defining the LED types.
+    """
+    RECTANGULAR = 0
+    CIRCULAR = 1
+
+
+class E5Led(QWidget):
+    """
+    Class implementing a LED widget.
+    """
+    def __init__(self, parent=None, color=None, shape=E5LedType.CIRCULAR,
+                 rectRatio=1):
+        """
+        Constructor
+        
+        @param parent reference to parent widget
+        @type QWidget
+        @param color color of the LED
+        @type QColor
+        @param shape shape of the LED
+        @type E5LedType
+        @param rectRatio ratio width to height, if shape is rectangular
+        @type float
+        """
+        super().__init__(parent)
+        
+        if color is None:
+            color = QColor("green")
+        
+        self.__led_on = True
+        self.__dark_factor = 300
+        self.__offcolor = color.darker(self.__dark_factor)
+        self.__led_color = color
+        self.__framedLed = True
+        self.__shape = shape
+        self.__rectRatio = rectRatio
+        
+        self.setColor(color)
+        
+    def paintEvent(self, evt):
+        """
+        Protected slot handling the paint event.
+        
+        @param evt paint event object
+        @type QPaintEvent
+        """
+        if self.__shape == E5LedType.CIRCULAR:
+            self.__paintRound()
+        elif self.__shape == E5LedType.RECTANGULAR:
+            self.__paintRectangular()
+    
+    def __getBestRoundSize(self):
+        """
+        Private method to calculate the width of the LED.
+        
+        @return new width of the LED (integer)
+        """
+        width = min(self.width(), self.height())
+        width -= 2  # leave one pixel border
+        return width > -1 and width or 0
+        
+    def __paintRound(self):
+        """
+        Private method to paint a round raised LED.
+        """
+        # Initialize coordinates, width and height of the LED
+        width = self.__getBestRoundSize()
+        
+        # Calculate the gradient for the LED
+        wh = width / 2
+        color = self.__led_on and self.__led_color or self.__offcolor
+        gradient = QRadialGradient(wh, wh, wh, 0.8 * wh, 0.8 * wh)
+        gradient.setColorAt(0.0, color.lighter(200))
+        gradient.setColorAt(0.6, color)
+        if self.__framedLed:
+            gradient.setColorAt(0.9, color.darker())
+            gradient.setColorAt(
+                1.0, self.palette().color(QPalette.ColorRole.Dark))
+        else:
+            gradient.setColorAt(1.0, color.darker())
+        
+        # now do the drawing
+        paint = QPainter(self)
+        paint.setRenderHint(QPainter.RenderHint.Antialiasing, True)
+        paint.setBrush(QBrush(gradient))
+        paint.setPen(Qt.PenStyle.NoPen)
+        paint.drawEllipse(1, 1, width, width)
+        paint.end()
+        
+    def __paintRectangular(self):
+        """
+        Private method to paint a rectangular raised LED.
+        """
+        # Initialize coordinates, width and height of the LED
+        width = self.height() * self.__rectRatio
+        left = max(0, int((self.width() - width) / 2) - 1)
+        right = min(int((self.width() + width) / 2), self.width())
+        height = self.height()
+        
+        # now do the drawing
+        painter = QPainter(self)
+        painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
+        color = self.__led_on and self.__led_color or self.__offcolor
+
+        painter.setPen(color.lighter(200))
+        painter.drawLine(left, 0, left, height - 1)
+        painter.drawLine(left + 1, 0, right - 1, 0)
+        if self.__framedLed:
+            painter.setPen(self.palette().color(QPalette.ColorRole.Dark))
+        else:
+            painter.setPen(color.darker())
+        painter.drawLine(left + 1, height - 1, right - 1, height - 1)
+        painter.drawLine(right - 1, 1, right - 1, height - 1)
+        painter.fillRect(left + 1, 1, right - 2, height - 2, QBrush(color))
+        painter.end()
+        
+    def isOn(self):
+        """
+        Public method to return the LED state.
+        
+        @return flag indicating the light state (boolean)
+        """
+        return self.__led_on
+        
+    def shape(self):
+        """
+        Public method to return the LED shape.
+        
+        @return LED shape
+        @rtype E5LedType
+        """
+        return self.__shape
+        
+    def ratio(self):
+        """
+        Public method to return the LED rectangular ratio [= width / height].
+        
+        @return LED rectangular ratio (float)
+        """
+        return self.__rectRatio
+        
+    def color(self):
+        """
+        Public method to return the LED color.
+        
+        @return color of the LED (QColor)
+        """
+        return self.__led_color
+        
+    def setOn(self, state):
+        """
+        Public method to set the LED to on.
+        
+        @param state new state of the LED (boolean)
+        """
+        if self.__led_on != state:
+            self.__led_on = state
+            self.update()
+        
+    def setShape(self, shape):
+        """
+        Public method to set the LED shape.
+        
+        @param shape new LED shape
+        @type E5LedType
+        """
+        if self.__shape != shape:
+            self.__shape = shape
+            self.update()
+        
+    def setRatio(self, ratio):
+        """
+        Public method to set the LED rectangular ratio (width / height).
+        
+        @param ratio new LED rectangular ratio (float)
+        """
+        if self.__rectRatio != ratio:
+            self.__rectRatio = ratio
+            self.update()
+        
+    def setColor(self, color):
+        """
+        Public method to set the LED color.
+        
+        @param color color for the LED (QColor)
+        """
+        if self.__led_color != color:
+            self.__led_color = color
+            self.__offcolor = color.darker(self.__dark_factor)
+            self.update()
+        
+    def setDarkFactor(self, darkfactor):
+        """
+        Public method to set the dark factor.
+        
+        @param darkfactor value to set for the dark factor (integer)
+        """
+        if self.__dark_factor != darkfactor:
+            self.__dark_factor = darkfactor
+            self.__offcolor = self.__led_color.darker(darkfactor)
+            self.update()
+        
+    def darkFactor(self):
+        """
+        Public method to return the dark factor.
+        
+        @return the current dark factor (integer)
+        """
+        return self.__dark_factor
+        
+    def toggle(self):
+        """
+        Public slot to toggle the LED state.
+        """
+        self.setOn(not self.__led_on)
+        
+    def on(self):
+        """
+        Public slot to set the LED to on.
+        """
+        self.setOn(True)
+        
+    def off(self):
+        """
+        Public slot to set the LED to off.
+        """
+        self.setOn(False)
+        
+    def setFramed(self, framed):
+        """
+        Public slot to set the __framedLed attribute.
+        
+        @param framed flag indicating the framed state (boolean)
+        """
+        if self.__framedLed != framed:
+            self.__framedLed = framed
+            self.__off_map = None
+            self.__on_map = None
+            self.update()
+        
+    def isFramed(self):
+        """
+        Public method to return the framed state.
+        
+        @return flag indicating the current framed state (boolean)
+        """
+        return self.__framedLed
+        
+    def sizeHint(self):
+        """
+        Public method to give a hint about our desired size.
+        
+        @return size hint (QSize)
+        """
+        return QSize(18, 18)
+        
+    def minimumSizeHint(self):
+        """
+        Public method to give a hint about our minimum size.
+        
+        @return size hint (QSize)
+        """
+        return QSize(18, 18)
+
+
+class E5ClickableLed(E5Led):
+    """
+    Class implementing a clickable LED widget.
+    
+    @signal clicked(QPoint) emitted upon a click on the LED with the
+        left button
+    @signal middleClicked(QPoint) emitted upon a click on the LED with
+        the middle button or CTRL and left button
+    """
+    clicked = pyqtSignal(QPoint)
+    middleClicked = pyqtSignal(QPoint)
+    
+    def __init__(self, parent=None, color=None, shape=E5LedType.CIRCULAR,
+                 rectRatio=1):
+        """
+        Constructor
+        
+        @param parent reference to parent widget
+        @type QWidget
+        @param color color of the LED
+        @type QColor
+        @param shape shape of the LED
+        @type E5LedType
+        @param rectRatio ratio width to height, if shape is rectangular
+        @type float
+        """
+        super().__init__(parent, color, shape, rectRatio)
+        
+        self.setCursor(Qt.CursorShape.PointingHandCursor)
+    
+    def mouseReleaseEvent(self, evt):
+        """
+        Protected method handling mouse release events.
+        
+        @param evt mouse event (QMouseEvent)
+        """
+        if (
+            evt.button() == Qt.MouseButton.LeftButton and
+            self.rect().contains(evt.pos())
+        ):
+            if evt.modifiers() == Qt.KeyboardModifier.ControlModifier:
+                self.middleClicked.emit(evt.globalPos())
+            else:
+                self.clicked.emit(evt.globalPos())
+        elif (
+            evt.button() == Qt.MouseButton.MidButton and
+            self.rect().contains(evt.pos())
+        ):
+            self.middleClicked.emit(evt.globalPos())
+        else:
+            super().mouseReleaseEvent(evt)

eric ide

mercurial