Signed-off-by: falkTX <falktx@falktx.com>tags/v2.5.0
| @@ -132,6 +132,17 @@ debug: | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| lint: | |||
| pylint \ | |||
| --extension-pkg-whitelist=PyQt5 \ | |||
| --max-line-length=120 \ | |||
| --max-locals=25 \ | |||
| --max-statements=100 \ | |||
| --disable=bare-except,duplicate-code,invalid-name,missing-docstring,too-many-branches,too-many-instance-attributes,too-many-statements \ | |||
| $(wildcard widgets/*.py) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| i18n_update: $(TSs) | |||
| i18n_release: $(QMs) | |||
| @@ -162,9 +162,9 @@ class CanvasPreviewFrame(QFrame): | |||
| if self.fZoomCursors[self._kCursorName] != cursorName: | |||
| prefix = ":/cursors/zoom" | |||
| self.fZoomCursors[self._kCursorName] = cursorName | |||
| self.fZoomCursors[self._kCursorZoom] = QCursor(QPixmap("{}_{}.png".format(prefix, cursorName)), 8, 7) | |||
| self.fZoomCursors[self._kCursorZoomIn] = QCursor(QPixmap("{}-in_{}.png".format(prefix, cursorName)), 8, 7) | |||
| self.fZoomCursors[self._kCursorZoomOut] = QCursor(QPixmap("{}-out_{}.png".format(prefix, cursorName)), 8, 7) | |||
| self.fZoomCursors[self._kCursorZoom] = QCursor(QPixmap(f"{prefix}_{cursorName}.png"), 8, 7) | |||
| self.fZoomCursors[self._kCursorZoomIn] = QCursor(QPixmap(f"{prefix}-in_{cursorName}.png"), 8, 7) | |||
| self.fZoomCursors[self._kCursorZoomOut] = QCursor(QPixmap(f"{prefix}-out_{cursorName}.png"), 8, 7) | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| @@ -406,19 +406,3 @@ class CanvasPreviewFrame(QFrame): | |||
| self.fFrameWidth = 1 if self.fUseCustomPaint else self.frameWidth() | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| if __name__ == '__main__': | |||
| # pylint: disable=unused-import | |||
| # pylint: disable=ungrouped-imports | |||
| import sys | |||
| import resources_rc | |||
| from PyQt5.QtWidgets import QApplication | |||
| # pylint: enable=unused-import | |||
| # pylint: enable=ungrouped-imports | |||
| app = QApplication(sys.argv) | |||
| gui = CanvasPreviewFrame(None) | |||
| gui.show() | |||
| sys.exit(app.exec_()) | |||
| @@ -2,7 +2,7 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # Collapsible Box, a custom Qt widget | |||
| # Copyright (C) 2019 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2019-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| @@ -20,7 +20,6 @@ | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import pyqtSlot, Qt | |||
| from PyQt5.QtGui import QCursor, QFont | |||
| from PyQt5.QtWidgets import QFrame, QSizePolicy, QToolButton, QVBoxLayout, QWidget | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| @@ -75,3 +74,5 @@ class CollapsibleBox(QFrame): | |||
| def getContentLayout(self): | |||
| return self.content_layout | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| @@ -0,0 +1,278 @@ | |||
| #!/usr/bin/env python3 | |||
| # -*- coding: utf-8 -*- | |||
| # Common Dial, a custom Qt widget | |||
| # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| # published by the Free Software Foundation; either version 2 of | |||
| # the License, or any later version. | |||
| # | |||
| # This program is distributed in the hope that it will be useful, | |||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| # GNU General Public License for more details. | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from math import isnan | |||
| from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QPointF, QRectF | |||
| from PyQt5.QtGui import QColor, QFont, QLinearGradient, QPainter | |||
| from PyQt5.QtWidgets import QDial | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Widget Class | |||
| # to be implemented by subclasses | |||
| #def updateSizes(self): | |||
| #def paintDial(self, painter): | |||
| class CommonDial(QDial): | |||
| # enum CustomPaintMode | |||
| CUSTOM_PAINT_MODE_NULL = 0 # default (NOTE: only this mode has label gradient) | |||
| CUSTOM_PAINT_MODE_CARLA_WET = 1 # color blue-green gradient (reserved #3) | |||
| CUSTOM_PAINT_MODE_CARLA_VOL = 2 # color blue (reserved #3) | |||
| CUSTOM_PAINT_MODE_CARLA_L = 3 # color yellow (reserved #4) | |||
| CUSTOM_PAINT_MODE_CARLA_R = 4 # color yellow (reserved #4) | |||
| CUSTOM_PAINT_MODE_CARLA_PAN = 5 # color yellow (reserved #3) | |||
| CUSTOM_PAINT_MODE_COLOR = 6 # color, selectable (reserved #3) | |||
| CUSTOM_PAINT_MODE_ZITA = 7 # custom zita knob (reserved #6) | |||
| CUSTOM_PAINT_MODE_NO_GRADIENT = 8 # skip label gradient | |||
| # enum Orientation | |||
| HORIZONTAL = 0 | |||
| VERTICAL = 1 | |||
| HOVER_MIN = 0 | |||
| HOVER_MAX = 9 | |||
| MODE_DEFAULT = 0 | |||
| MODE_LINEAR = 1 | |||
| # signals | |||
| dragStateChanged = pyqtSignal(bool) | |||
| realValueChanged = pyqtSignal(float) | |||
| def __init__(self, parent, index): | |||
| QDial.__init__(self, parent) | |||
| self.fDialMode = self.MODE_LINEAR | |||
| self.fMinimum = 0.0 | |||
| self.fMaximum = 1.0 | |||
| self.fRealValue = 0.0 | |||
| self.fPrecision = 10000 | |||
| self.fIsInteger = False | |||
| self.fIsHovered = False | |||
| self.fIsPressed = False | |||
| self.fHoverStep = self.HOVER_MIN | |||
| self.fLastDragPos = None | |||
| self.fLastDragValue = 0.0 | |||
| self.fIndex = index | |||
| self.fLabel = "" | |||
| self.fLabelPos = QPointF(0.0, 0.0) | |||
| self.fLabelFont = QFont(self.font()) | |||
| self.fLabelFont.setPixelSize(8) | |||
| self.fLabelWidth = 0 | |||
| self.fLabelHeight = 0 | |||
| if self.palette().window().color().lightness() > 100: | |||
| # Light background | |||
| c = self.palette().dark().color() | |||
| self.fLabelGradientColor1 = c | |||
| self.fLabelGradientColor2 = QColor(c.red(), c.green(), c.blue(), 0) | |||
| self.fLabelGradientColorT = [self.palette().buttonText().color(), self.palette().mid().color()] | |||
| else: | |||
| # Dark background | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [Qt.white, Qt.darkGray] | |||
| self.fLabelGradient = QLinearGradient(0, 0, 0, 1) | |||
| self.fLabelGradient.setColorAt(0.0, self.fLabelGradientColor1) | |||
| self.fLabelGradient.setColorAt(0.6, self.fLabelGradientColor1) | |||
| self.fLabelGradient.setColorAt(1.0, self.fLabelGradientColor2) | |||
| self.fLabelGradientRect = QRectF(0.0, 0.0, 0.0, 0.0) | |||
| self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_NULL | |||
| self.fCustomPaintColor = QColor(0xff, 0xff, 0xff) | |||
| # Fake internal value, custom precision | |||
| QDial.setMinimum(self, 0) | |||
| QDial.setMaximum(self, self.fPrecision) | |||
| QDial.setValue(self, 0) | |||
| self.valueChanged.connect(self.slot_valueChanged) | |||
| def forceWhiteLabelGradientText(self): | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [Qt.white, Qt.darkGray] | |||
| def setLabelColor(self, enabled, disabled): | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [enabled, disabled] | |||
| def getIndex(self): | |||
| return self.fIndex | |||
| def setIndex(self, index): | |||
| self.fIndex = index | |||
| def setPrecision(self, value, isInteger): | |||
| self.fPrecision = value | |||
| self.fIsInteger = isInteger | |||
| QDial.setMaximum(self, int(value)) | |||
| def setMinimum(self, value): | |||
| self.fMinimum = value | |||
| def setMaximum(self, value): | |||
| self.fMaximum = value | |||
| def rvalue(self): | |||
| return self.fRealValue | |||
| def setValue(self, value, emitSignal=False): | |||
| if self.fRealValue == value or isnan(value): | |||
| return | |||
| if value <= self.fMinimum: | |||
| qtValue = 0 | |||
| self.fRealValue = self.fMinimum | |||
| elif value >= self.fMaximum: | |||
| qtValue = int(self.fPrecision) | |||
| self.fRealValue = self.fMaximum | |||
| else: | |||
| qtValue = round(float(value - self.fMinimum) / float(self.fMaximum - self.fMinimum) * self.fPrecision) | |||
| self.fRealValue = value | |||
| # Block change signal, we'll handle it ourselves | |||
| self.blockSignals(True) | |||
| QDial.setValue(self, qtValue) | |||
| self.blockSignals(False) | |||
| if emitSignal: | |||
| self.realValueChanged.emit(self.fRealValue) | |||
| def setCustomPaintMode(self, paintMode): | |||
| if self.fCustomPaintMode == paintMode: | |||
| return | |||
| self.fCustomPaintMode = paintMode | |||
| self.update() | |||
| def setCustomPaintColor(self, color): | |||
| if self.fCustomPaintColor == color: | |||
| return | |||
| self.fCustomPaintColor = color | |||
| self.update() | |||
| def setLabel(self, label): | |||
| if self.fLabel == label: | |||
| return | |||
| self.fLabel = label | |||
| self.updateSizes() | |||
| self.update() | |||
| @pyqtSlot(int) | |||
| def slot_valueChanged(self, value): | |||
| self.fRealValue = float(value)/self.fPrecision * (self.fMaximum - self.fMinimum) + self.fMinimum | |||
| self.realValueChanged.emit(self.fRealValue) | |||
| def enterEvent(self, event): | |||
| self.fIsHovered = True | |||
| if self.fHoverStep == self.HOVER_MIN: | |||
| self.fHoverStep = self.HOVER_MIN + 1 | |||
| QDial.enterEvent(self, event) | |||
| def leaveEvent(self, event): | |||
| self.fIsHovered = False | |||
| if self.fHoverStep == self.HOVER_MAX: | |||
| self.fHoverStep = self.HOVER_MAX - 1 | |||
| QDial.leaveEvent(self, event) | |||
| def mousePressEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| QDial.mousePressEvent(self, event) | |||
| return | |||
| if event.button() == Qt.LeftButton: | |||
| self.fIsPressed = True | |||
| self.fLastDragPos = event.pos() | |||
| self.fLastDragValue = self.fRealValue | |||
| self.dragStateChanged.emit(True) | |||
| def mouseMoveEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| QDial.mouseMoveEvent(self, event) | |||
| return | |||
| if not self.fIsPressed: | |||
| return | |||
| diff = (self.fMaximum - self.fMinimum) / 4.0 | |||
| pos = event.pos() | |||
| dx = diff * float(pos.x() - self.fLastDragPos.x()) / self.width() | |||
| dy = diff * float(pos.y() - self.fLastDragPos.y()) / self.height() | |||
| value = self.fLastDragValue + dx - dy | |||
| if value < self.fMinimum: | |||
| value = self.fMinimum | |||
| elif value > self.fMaximum: | |||
| value = self.fMaximum | |||
| elif self.fIsInteger: | |||
| value = float(round(value)) | |||
| self.setValue(value, True) | |||
| def mouseReleaseEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| QDial.mouseReleaseEvent(self, event) | |||
| return | |||
| if self.fIsPressed: | |||
| self.fIsPressed = False | |||
| self.dragStateChanged.emit(False) | |||
| def paintEvent(self, event): | |||
| painter = QPainter(self) | |||
| event.accept() | |||
| painter.save() | |||
| painter.setRenderHint(QPainter.Antialiasing, True) | |||
| if self.fLabel: | |||
| if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL: | |||
| painter.setPen(self.fLabelGradientColor2) | |||
| painter.setBrush(self.fLabelGradient) | |||
| painter.drawRect(self.fLabelGradientRect) | |||
| painter.setFont(self.fLabelFont) | |||
| painter.setPen(self.fLabelGradientColorT[0 if self.isEnabled() else 1]) | |||
| painter.drawText(self.fLabelPos, self.fLabel) | |||
| self.paintDial(painter) | |||
| painter.restore() | |||
| def resizeEvent(self, event): | |||
| QDial.resizeEvent(self, event) | |||
| self.updateSizes() | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -2,7 +2,7 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # Digital Peak Meter, a custom Qt widget | |||
| # Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| @@ -16,16 +16,16 @@ | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from math import sqrt | |||
| from PyQt5.QtCore import qCritical, Qt, QTimer, QSize, QLineF, QRectF | |||
| from PyQt5.QtCore import qCritical, Qt, QSize, QLineF, QRectF | |||
| from PyQt5.QtGui import QColor, QLinearGradient, QPainter, QPen, QPixmap | |||
| from PyQt5.QtWidgets import QWidget | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Widget Class | |||
| class DigitalPeakMeter(QWidget): | |||
| @@ -43,7 +43,7 @@ class DigitalPeakMeter(QWidget): | |||
| STYLE_RNCBC = 3 | |||
| STYLE_CALF = 4 | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def __init__(self, parent): | |||
| QWidget.__init__(self, parent) | |||
| @@ -71,7 +71,7 @@ class DigitalPeakMeter(QWidget): | |||
| self.updateGrandient() | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def channelCount(self): | |||
| return self.fChannelCount | |||
| @@ -81,13 +81,14 @@ class DigitalPeakMeter(QWidget): | |||
| return | |||
| if count < 0: | |||
| return qCritical("DigitalPeakMeter::setChannelCount(%i) - channel count must be a positive integer or zero" % count) | |||
| qCritical(f"DigitalPeakMeter::setChannelCount({count}) - channel count must be a positive integer or zero") | |||
| return | |||
| self.fChannelCount = count | |||
| self.fChannelData = [] | |||
| self.fLastChannelData = [] | |||
| for x in range(count): | |||
| for _ in range(count): | |||
| self.fChannelData.append(0.0) | |||
| self.fLastChannelData.append(0.0) | |||
| @@ -98,7 +99,7 @@ class DigitalPeakMeter(QWidget): | |||
| self.setMinimumSize(0, 0) | |||
| self.setMaximumSize(9999, 9999) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def meterColor(self): | |||
| return self.fMeterColor | |||
| @@ -108,7 +109,8 @@ class DigitalPeakMeter(QWidget): | |||
| return | |||
| if color not in (self.COLOR_GREEN, self.COLOR_BLUE): | |||
| return qCritical("DigitalPeakMeter::setMeterColor(%i) - invalid color" % color) | |||
| qCritical(f"DigitalPeakMeter::setMeterColor({color}) - invalid color") | |||
| return | |||
| if color == self.COLOR_GREEN: | |||
| self.fMeterColorBase = QColor(93, 231, 61) | |||
| @@ -121,7 +123,7 @@ class DigitalPeakMeter(QWidget): | |||
| self.updateGrandient() | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def meterLinesEnabled(self): | |||
| return self.fMeterLinesEnabled | |||
| @@ -132,7 +134,7 @@ class DigitalPeakMeter(QWidget): | |||
| self.fMeterLinesEnabled = yesNo | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def meterOrientation(self): | |||
| return self.fMeterOrientation | |||
| @@ -142,13 +144,14 @@ class DigitalPeakMeter(QWidget): | |||
| return | |||
| if orientation not in (self.HORIZONTAL, self.VERTICAL): | |||
| return qCritical("DigitalPeakMeter::setMeterOrientation(%i) - invalid orientation" % orientation) | |||
| qCritical(f"DigitalPeakMeter::setMeterOrientation({orientation}) - invalid orientation") | |||
| return | |||
| self.fMeterOrientation = orientation | |||
| self.updateGrandient() | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def meterStyle(self): | |||
| return self.fMeterStyle | |||
| @@ -158,7 +161,8 @@ class DigitalPeakMeter(QWidget): | |||
| return | |||
| if style not in (self.STYLE_DEFAULT, self.STYLE_OPENAV, self.STYLE_RNCBC, self.STYLE_CALF): | |||
| return qCritical("DigitalPeakMeter::setMeterStyle(%i) - invalid style" % style) | |||
| qCritical(f"DigitalPeakMeter::setMeterStyle({style}) - invalid style") | |||
| return | |||
| if style == self.STYLE_DEFAULT: | |||
| self.fMeterBackground = QColor("#070707") | |||
| @@ -182,7 +186,7 @@ class DigitalPeakMeter(QWidget): | |||
| self.updateGrandient() | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def smoothMultiplier(self): | |||
| return self.fSmoothMultiplier | |||
| @@ -192,28 +196,37 @@ class DigitalPeakMeter(QWidget): | |||
| return | |||
| if not isinstance(value, int): | |||
| return qCritical("DigitalPeakMeter::setSmoothMultiplier() - value must be an integer") | |||
| qCritical("DigitalPeakMeter::setSmoothMultiplier() - value must be an integer") | |||
| return | |||
| if value < 0: | |||
| return qCritical("DigitalPeakMeter::setSmoothMultiplier(%i) - value must be >= 0" % value) | |||
| qCritical(f"DigitalPeakMeter::setSmoothMultiplier({value}) - value must be >= 0") | |||
| return | |||
| if value > 5: | |||
| return qCritical("DigitalPeakMeter::setSmoothMultiplier(%i) - value must be < 5" % value) | |||
| qCritical(f"DigitalPeakMeter::setSmoothMultiplier({value}) - value must be < 5") | |||
| return | |||
| self.fSmoothMultiplier = value | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def displayMeter(self, meter, level, forced = False): | |||
| if not isinstance(meter, int): | |||
| return qCritical("DigitalPeakMeter::displayMeter(,) - meter value must be an integer") | |||
| qCritical("DigitalPeakMeter::displayMeter(,) - meter value must be an integer") | |||
| return | |||
| if not isinstance(level, float): | |||
| return qCritical("DigitalPeakMeter::displayMeter(%i,) - level value must be a float" % (meter,)) | |||
| qCritical(f"DigitalPeakMeter::displayMeter({meter},) - level value must be a float") | |||
| return | |||
| if meter <= 0 or meter > self.fChannelCount: | |||
| return qCritical("DigitalPeakMeter::displayMeter(%i, %f) - invalid meter number" % (meter, level)) | |||
| qCritical(f"DigitalPeakMeter::displayMeter({meter}, {level}) - invalid meter number") | |||
| return | |||
| i = meter - 1 | |||
| if self.fSmoothMultiplier > 0 and not forced: | |||
| level = (self.fLastChannelData[i] * float(self.fSmoothMultiplier) + level) / float(self.fSmoothMultiplier + 1) | |||
| level = ( | |||
| (self.fLastChannelData[i] * float(self.fSmoothMultiplier) + level) | |||
| / float(self.fSmoothMultiplier + 1) | |||
| ) | |||
| if level < 0.001: | |||
| level = 0.0 | |||
| @@ -226,7 +239,7 @@ class DigitalPeakMeter(QWidget): | |||
| self.fLastChannelData[i] = level | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def updateGrandient(self): | |||
| self.fMeterGradient = QLinearGradient(0, 0, 1, 1) | |||
| @@ -287,15 +300,15 @@ class DigitalPeakMeter(QWidget): | |||
| elif self.fMeterOrientation == self.VERTICAL: | |||
| self.fMeterGradient.setFinalStop(0, self.height()) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def minimumSizeHint(self): | |||
| return QSize(10, 10) | |||
| return QSize(20, 10) if self.fMeterOrientation == self.HORIZONTAL else QSize(10, 20) | |||
| def sizeHint(self): | |||
| return QSize(self.width(), self.height()) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def drawCalf(self, event): | |||
| painter = QPainter(self) | |||
| @@ -323,7 +336,8 @@ class DigitalPeakMeter(QWidget): | |||
| def paintEvent(self, event): | |||
| if self.fMeterStyle == self.STYLE_CALF: | |||
| return self.drawCalf(event) | |||
| self.drawCalf(event) | |||
| return | |||
| painter = QPainter(self) | |||
| event.accept() | |||
| @@ -440,30 +454,10 @@ class DigitalPeakMeter(QWidget): | |||
| painter.setPen(QColor(110, 15, 15, 100)) | |||
| painter.drawLine(QLineF(2, lsmall - (lsmall * 0.96), lfull-2.0, lsmall - (lsmall * 0.96))) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def resizeEvent(self, event): | |||
| QWidget.resizeEvent(self, event) | |||
| self.updateGrandientFinalStop() | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Main Testing | |||
| if __name__ == '__main__': | |||
| import sys | |||
| import resources_rc | |||
| from PyQt5.QtWidgets import QApplication | |||
| app = QApplication(sys.argv) | |||
| gui = DigitalPeakMeter(None) | |||
| gui.setChannelCount(2) | |||
| #gui.setMeterOrientation(DigitalPeakMeter.HORIZONTAL) | |||
| gui.setMeterStyle(DigitalPeakMeter.STYLE_RNCBC) | |||
| gui.displayMeter(1, 0.5) | |||
| gui.displayMeter(2, 0.8) | |||
| gui.show() | |||
| sys.exit(app.exec_()) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -2,7 +2,7 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # Middle-click draggable QGraphicsView | |||
| # Copyright (C) 2016-2020 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2016-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| @@ -16,19 +16,20 @@ | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import Qt, QEvent, QTimer | |||
| import os | |||
| from PyQt5.QtCore import Qt, QEvent | |||
| from PyQt5.QtGui import QCursor, QMouseEvent | |||
| from PyQt5.QtWidgets import QGraphicsView | |||
| from PyQt5.QtWidgets import QGraphicsView, QMessageBox | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Custom Stuff) | |||
| from carla_shared import * | |||
| from carla_shared import MACOS, CustomMessageBox, gCarla | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Widget Class | |||
| class DraggableGraphicsView(QGraphicsView): | |||
| @@ -49,7 +50,7 @@ class DraggableGraphicsView(QGraphicsView): | |||
| self.setAcceptDrops(True) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def isDragUrlValid(self, filename): | |||
| lfilename = filename.lower() | |||
| @@ -59,7 +60,7 @@ class DraggableGraphicsView(QGraphicsView): | |||
| #return True | |||
| if MACOS and lfilename.endswith(".vst"): | |||
| return True | |||
| elif lfilename.endswith(".vst3") and ".vst3" in self.fSupportedExtensions: | |||
| if lfilename.endswith(".vst3") and ".vst3" in self.fSupportedExtensions: | |||
| return True | |||
| elif os.path.isfile(filename): | |||
| @@ -68,7 +69,7 @@ class DraggableGraphicsView(QGraphicsView): | |||
| return False | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def dragEnterEvent(self, event): | |||
| urls = event.mimeData().urls() | |||
| @@ -93,7 +94,7 @@ class DraggableGraphicsView(QGraphicsView): | |||
| self.fWasLastDragValid = False | |||
| QGraphicsView.dragLeaveEvent(self, event) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def dropEvent(self, event): | |||
| event.acceptProposedAction() | |||
| @@ -111,7 +112,7 @@ class DraggableGraphicsView(QGraphicsView): | |||
| self.tr("Failed to load file"), | |||
| gCarla.gui.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| def mousePressEvent(self, event): | |||
| if event.button() == self.fMiddleButton and not (event.modifiers() & Qt.ControlModifier): | |||
| @@ -151,4 +152,4 @@ class DraggableGraphicsView(QGraphicsView): | |||
| return | |||
| QGraphicsView.wheelEvent(self, event) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -16,7 +16,7 @@ | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import QRectF | |||
| @@ -24,7 +24,7 @@ from PyQt5.QtGui import QPainter, QPixmap | |||
| from PyQt5.QtSvg import QSvgWidget | |||
| from PyQt5.QtWidgets import QPushButton | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Widget Class | |||
| class LEDButton(QPushButton): | |||
| @@ -61,10 +61,10 @@ class LEDButton(QPushButton): | |||
| self.fLastColor = self.UNSET | |||
| if self._loadImageNowIfNeeded(): | |||
| if isinstance(self.fImage, QPixmap): | |||
| size = self.fImage.width() | |||
| else: | |||
| size = self.fImage.sizeHint().width() | |||
| #if isinstance(self.fImage, QPixmap): | |||
| #size = self.fImage.width() | |||
| #else: | |||
| #size = self.fImage.sizeHint().width() | |||
| self.fRect = QRectF(self.fImage.rect()) | |||
| self.setFixedSize(self.fImage.size()) | |||
| @@ -87,7 +87,7 @@ class LEDButton(QPushButton): | |||
| def _loadImageNowIfNeeded(self): | |||
| if self.isChecked(): | |||
| if self.fLastColor == self.fColor: | |||
| return | |||
| return False | |||
| if self.fColor == self.OFF: | |||
| img = ":/scalable/led_off.svg" | |||
| elif self.fColor == self.BLUE: | |||
| @@ -122,3 +122,5 @@ class LEDButton(QPushButton): | |||
| self.update() | |||
| return True | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -76,7 +76,9 @@ class CustomInputDialog(QDialog): | |||
| text = "<table>" | |||
| for scalePoint in scalePoints: | |||
| valuestr = ("%i" if decimals == 0 else "%f") % scalePoint['value'] | |||
| text += "<tr><td align='right'>%s</td><td align='left'> - %s</td></tr>" % (valuestr, scalePoint['label']) | |||
| text += "<tr>" | |||
| text += f"<td align='right'>{valuestr}</td><td align='left'> - {scalePoint['label']}</td>" | |||
| text += "</tr>" | |||
| text += "</table>" | |||
| self.ui.textBrowser.setText(text) | |||
| self.resize(200, 300) | |||
| @@ -341,10 +343,8 @@ class ParamSpinBox(QAbstractSpinBox): | |||
| else: | |||
| self.fStep = value | |||
| if self.fStepSmall > value: | |||
| self.fStepSmall = value | |||
| if self.fStepLarge < value: | |||
| self.fStepLarge = value | |||
| self.fStepSmall = min(self.fStepSmall, value) | |||
| self.fStepLarge = max(self.fStepLarge, value) | |||
| self.fBar.fIsInteger = bool(self.fStepSmall == 1.0) | |||
| @@ -2,7 +2,7 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # A piano roll viewer/editor | |||
| # Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2014-2015 Perry Nguyen | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| @@ -21,15 +21,15 @@ | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import Qt, QRectF, QPointF, pyqtSignal | |||
| from PyQt5.QtGui import QColor, QCursor, QFont, QPen, QPainter, QTransform | |||
| from PyQt5.QtWidgets import QGraphicsItem, QGraphicsLineItem, QGraphicsOpacityEffect, QGraphicsRectItem, QGraphicsSimpleTextItem | |||
| from PyQt5.QtGui import QColor, QCursor, QFont, QPen, QPainter | |||
| from PyQt5.QtWidgets import QGraphicsItem, QGraphicsLineItem, QGraphicsRectItem, QGraphicsSimpleTextItem | |||
| from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView | |||
| from PyQt5.QtWidgets import QApplication, QComboBox, QHBoxLayout, QLabel, QStyle, QVBoxLayout, QWidget | |||
| from PyQt5.QtWidgets import QApplication, QStyle, QWidget | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Imports (Custom) | |||
| from carla_shared import * | |||
| #from carla_shared import * | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # MIDI definitions, copied from CarlaMIDI.h | |||
| @@ -57,17 +57,26 @@ def MIDI_IS_SYSTEM_MESSAGE(status): return status >= MIDI_STATUS_BIT and s | |||
| def MIDI_IS_OSC_MESSAGE(status): return status == '/' or status == '#' | |||
| # MIDI Channel message type | |||
| def MIDI_IS_STATUS_NOTE_OFF(status): return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF | |||
| def MIDI_IS_STATUS_NOTE_ON(status): return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON | |||
| def MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status): return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH | |||
| def MIDI_IS_STATUS_CONTROL_CHANGE(status): return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE | |||
| def MIDI_IS_STATUS_PROGRAM_CHANGE(status): return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE | |||
| def MIDI_IS_STATUS_CHANNEL_PRESSURE(status): return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE | |||
| def MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status): return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL | |||
| def MIDI_IS_STATUS_NOTE_OFF(status): | |||
| return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF | |||
| def MIDI_IS_STATUS_NOTE_ON(status): | |||
| return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON | |||
| def MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status): | |||
| return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH | |||
| def MIDI_IS_STATUS_CONTROL_CHANGE(status): | |||
| return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE | |||
| def MIDI_IS_STATUS_PROGRAM_CHANGE(status): | |||
| return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE | |||
| def MIDI_IS_STATUS_CHANNEL_PRESSURE(status): | |||
| return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE | |||
| def MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status): | |||
| return MIDI_IS_CHANNEL_MESSAGE(status) and (status & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL | |||
| # MIDI Utils | |||
| def MIDI_GET_STATUS_FROM_DATA(data): return data[0] & MIDI_STATUS_BIT if MIDI_IS_CHANNEL_MESSAGE(data[0]) else data[0] | |||
| def MIDI_GET_CHANNEL_FROM_DATA(data): return data[0] & MIDI_CHANNEL_BIT if MIDI_IS_CHANNEL_MESSAGE(data[0]) else 0 | |||
| def MIDI_GET_STATUS_FROM_DATA(data): | |||
| return data[0] & MIDI_STATUS_BIT if MIDI_IS_CHANNEL_MESSAGE(data[0]) else data[0] | |||
| def MIDI_GET_CHANNEL_FROM_DATA(data): | |||
| return data[0] & MIDI_CHANNEL_BIT if MIDI_IS_CHANNEL_MESSAGE(data[0]) else 0 | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Graphics Items | |||
| @@ -1,99 +0,0 @@ | |||
| #!/usr/bin/env python3 | |||
| # -*- coding: utf-8 -*- | |||
| # Pixmap Button, a custom Qt widget | |||
| # Copyright (C) 2013-2019 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| # published by the Free Software Foundation; either version 2 of | |||
| # the License, or any later version. | |||
| # | |||
| # This program is distributed in the hope that it will be useful, | |||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| # GNU General Public License for more details. | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import QPointF, QRectF | |||
| from PyQt5.QtGui import QColor, QFont, QPainter, QPixmap | |||
| from PyQt5.QtWidgets import QPushButton | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Widget Class | |||
| class PixmapButton(QPushButton): | |||
| def __init__(self, parent): | |||
| QPushButton.__init__(self, parent) | |||
| self.fPixmapNormal = QPixmap() | |||
| self.fPixmapDown = QPixmap() | |||
| self.fPixmapHover = QPixmap() | |||
| self.fPixmapRect = QRectF(0, 0, 0, 0) | |||
| self.fIsHovered = False | |||
| self.fTopText = "" | |||
| self.fTopTextColor = QColor() | |||
| self.fTopTextFont = QFont() | |||
| self.setText("") | |||
| def setPixmaps(self, normal, down, hover): | |||
| self.fPixmapNormal.load(normal) | |||
| self.fPixmapDown.load(down) | |||
| self.fPixmapHover.load(hover) | |||
| width = self.fPixmapNormal.width() | |||
| height = self.fPixmapNormal.height() | |||
| self.fPixmapRect = QRectF(0, 0, width, height) | |||
| self.setMinimumSize(width, height) | |||
| self.setMaximumSize(width, height) | |||
| def setTopText(self, text, color, font): | |||
| self.fTopText = text | |||
| self.fTopTextColor = color | |||
| self.fTopTextFont = font | |||
| def enterEvent(self, event): | |||
| self.fIsHovered = True | |||
| QPushButton.enterEvent(self, event) | |||
| def leaveEvent(self, event): | |||
| self.fIsHovered = False | |||
| QPushButton.leaveEvent(self, event) | |||
| def paintEvent(self, event): | |||
| painter = QPainter(self) | |||
| event.accept() | |||
| if not self.isEnabled(): | |||
| painter.save() | |||
| painter.setOpacity(0.2) | |||
| painter.drawPixmap(self.fPixmapRect, self.fPixmapNormal, self.fPixmapRect) | |||
| painter.restore() | |||
| elif self.isChecked() or self.isDown(): | |||
| painter.drawPixmap(self.fPixmapRect, self.fPixmapDown, self.fPixmapRect) | |||
| elif self.fIsHovered: | |||
| painter.drawPixmap(self.fPixmapRect, self.fPixmapHover, self.fPixmapRect) | |||
| else: | |||
| painter.drawPixmap(self.fPixmapRect, self.fPixmapNormal, self.fPixmapRect) | |||
| if not self.fTopText: | |||
| return | |||
| painter.save() | |||
| painter.setPen(self.fTopTextColor) | |||
| painter.setBrush(self.fTopTextColor) | |||
| painter.setFont(self.fTopTextFont) | |||
| painter.drawText(QPointF(10, 16), self.fTopText) | |||
| painter.restore() | |||
| @@ -2,7 +2,7 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # Pixmap Dial, a custom Qt widget | |||
| # Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| @@ -16,64 +16,24 @@ | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from math import cos, floor, pi, sin, isnan | |||
| from math import cos, floor, pi, sin | |||
| from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize | |||
| from PyQt5.QtGui import QColor, QConicalGradient, QFont, QFontMetrics | |||
| from PyQt5.QtGui import QLinearGradient, QPainter, QPainterPath, QPen, QPixmap | |||
| from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize | |||
| from PyQt5.QtGui import QColor, QConicalGradient, QFontMetrics, QPainterPath, QPen, QPixmap | |||
| from PyQt5.QtWidgets import QDial | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Widget Class | |||
| class PixmapDial(QDial): | |||
| # enum CustomPaintMode | |||
| CUSTOM_PAINT_MODE_NULL = 0 # default (NOTE: only this mode has label gradient) | |||
| CUSTOM_PAINT_MODE_CARLA_WET = 1 # color blue-green gradient (reserved #3) | |||
| CUSTOM_PAINT_MODE_CARLA_VOL = 2 # color blue (reserved #3) | |||
| CUSTOM_PAINT_MODE_CARLA_L = 3 # color yellow (reserved #4) | |||
| CUSTOM_PAINT_MODE_CARLA_R = 4 # color yellow (reserved #4) | |||
| CUSTOM_PAINT_MODE_CARLA_PAN = 5 # color yellow (reserved #3) | |||
| CUSTOM_PAINT_MODE_COLOR = 6 # color, selectable (reserved #3) | |||
| CUSTOM_PAINT_MODE_ZITA = 7 # custom zita knob (reserved #6) | |||
| CUSTOM_PAINT_MODE_NO_GRADIENT = 8 # skip label gradient | |||
| # enum Orientation | |||
| HORIZONTAL = 0 | |||
| VERTICAL = 1 | |||
| HOVER_MIN = 0 | |||
| HOVER_MAX = 9 | |||
| from .commondial import CommonDial | |||
| MODE_DEFAULT = 0 | |||
| MODE_LINEAR = 1 | |||
| # signals | |||
| dragStateChanged = pyqtSignal(bool) | |||
| realValueChanged = pyqtSignal(float) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Widget Class | |||
| class PixmapDial(CommonDial): | |||
| def __init__(self, parent, index=0): | |||
| QDial.__init__(self, parent) | |||
| self.fDialMode = self.MODE_LINEAR | |||
| self.fMinimum = 0.0 | |||
| self.fMaximum = 1.0 | |||
| self.fRealValue = 0.0 | |||
| self.fPrecision = 10000 | |||
| self.fIsInteger = False | |||
| CommonDial.__init__(self, parent, index) | |||
| self.fIsHovered = False | |||
| self.fIsPressed = False | |||
| self.fHoverStep = self.HOVER_MIN | |||
| self.fLastDragPos = None | |||
| self.fLastDragValue = 0.0 | |||
| self.fIndex = index | |||
| self.fPixmap = QPixmap(":/bitmaps/dial_01d.png") | |||
| self.fPixmapNum = "01" | |||
| @@ -82,60 +42,11 @@ class PixmapDial(QDial): | |||
| else: | |||
| self.fPixmapOrientation = self.VERTICAL | |||
| self.fLabel = "" | |||
| self.fLabelPos = QPointF(0.0, 0.0) | |||
| self.fLabelFont = QFont(self.font()) | |||
| self.fLabelFont.setPixelSize(8) | |||
| self.fLabelWidth = 0 | |||
| self.fLabelHeight = 0 | |||
| if self.palette().window().color().lightness() > 100: | |||
| # Light background | |||
| c = self.palette().dark().color() | |||
| self.fLabelGradientColor1 = c | |||
| self.fLabelGradientColor2 = QColor(c.red(), c.green(), c.blue(), 0) | |||
| self.fLabelGradientColorT = [self.palette().buttonText().color(), self.palette().mid().color()] | |||
| else: | |||
| # Dark background | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [Qt.white, Qt.darkGray] | |||
| self.fLabelGradient = QLinearGradient(0, 0, 0, 1) | |||
| self.fLabelGradient.setColorAt(0.0, self.fLabelGradientColor1) | |||
| self.fLabelGradient.setColorAt(0.6, self.fLabelGradientColor1) | |||
| self.fLabelGradient.setColorAt(1.0, self.fLabelGradientColor2) | |||
| self.fLabelGradientRect = QRectF(0.0, 0.0, 0.0, 0.0) | |||
| self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_NULL | |||
| self.fCustomPaintColor = QColor(0xff, 0xff, 0xff) | |||
| self.updateSizes() | |||
| # Fake internal value, custom precision | |||
| QDial.setMinimum(self, 0) | |||
| QDial.setMaximum(self, self.fPrecision) | |||
| QDial.setValue(self, 0) | |||
| self.valueChanged.connect(self.slot_valueChanged) | |||
| def getIndex(self): | |||
| return self.fIndex | |||
| def getBaseSize(self): | |||
| return self.fPixmapBaseSize | |||
| def forceWhiteLabelGradientText(self): | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [Qt.white, Qt.darkGray] | |||
| def setLabelColor(self, enabled, disabled): | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [enabled, disabled] | |||
| def updateSizes(self): | |||
| self.fPixmapWidth = self.fPixmap.width() | |||
| self.fPixmapHeight = self.fPixmap.height() | |||
| @@ -178,31 +89,6 @@ class PixmapDial(QDial): | |||
| self.fLabelGradientRect = QRectF(float(self.fPixmapBaseSize)/8.0, float(self.fPixmapBaseSize)/2.0, float(self.fPixmapBaseSize*3)/4.0, self.fPixmapBaseSize+self.fLabelHeight+5) | |||
| def setCustomPaintMode(self, paintMode): | |||
| if self.fCustomPaintMode == paintMode: | |||
| return | |||
| self.fCustomPaintMode = paintMode | |||
| self.update() | |||
| def setCustomPaintColor(self, color): | |||
| if self.fCustomPaintColor == color: | |||
| return | |||
| self.fCustomPaintColor = color | |||
| self.update() | |||
| def setLabel(self, label): | |||
| if self.fLabel == label: | |||
| return | |||
| self.fLabel = label | |||
| self.updateSizes() | |||
| self.update() | |||
| def setIndex(self, index): | |||
| self.fIndex = index | |||
| def setPixmap(self, pixmapId): | |||
| self.fPixmapNum = "%02i" % pixmapId | |||
| self.fPixmap.load(":/bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if self.isEnabled() else "d")) | |||
| @@ -229,46 +115,6 @@ class PixmapDial(QDial): | |||
| self.updateSizes() | |||
| self.update() | |||
| def setPrecision(self, value, isInteger): | |||
| self.fPrecision = value | |||
| self.fIsInteger = isInteger | |||
| QDial.setMaximum(self, value) | |||
| def setMinimum(self, value): | |||
| self.fMinimum = value | |||
| def setMaximum(self, value): | |||
| self.fMaximum = value | |||
| def setValue(self, value, emitSignal=False): | |||
| if self.fRealValue == value or isnan(value): | |||
| return | |||
| if value <= self.fMinimum: | |||
| qtValue = 0 | |||
| self.fRealValue = self.fMinimum | |||
| elif value >= self.fMaximum: | |||
| qtValue = self.fPrecision | |||
| self.fRealValue = self.fMaximum | |||
| else: | |||
| qtValue = round(float(value - self.fMinimum) / float(self.fMaximum - self.fMinimum) * self.fPrecision) | |||
| self.fRealValue = value | |||
| # Block change signal, we'll handle it ourselves | |||
| self.blockSignals(True) | |||
| QDial.setValue(self, qtValue) | |||
| self.blockSignals(False) | |||
| if emitSignal: | |||
| self.realValueChanged.emit(self.fRealValue) | |||
| @pyqtSlot(int) | |||
| def slot_valueChanged(self, value): | |||
| self.fRealValue = float(value)/self.fPrecision * (self.fMaximum - self.fMinimum) + self.fMinimum | |||
| self.realValueChanged.emit(self.fRealValue) | |||
| @pyqtSlot() | |||
| def slot_updatePixmap(self): | |||
| self.setPixmap(int(self.fPixmapNum)) | |||
| @@ -280,81 +126,13 @@ class PixmapDial(QDial): | |||
| return QSize(self.fPixmapBaseSize, self.fPixmapBaseSize) | |||
| def changeEvent(self, event): | |||
| QDial.changeEvent(self, event) | |||
| CommonDial.changeEvent(self, event) | |||
| # Force pixmap update if enabled state changes | |||
| if event.type() == QEvent.EnabledChange: | |||
| self.setPixmap(int(self.fPixmapNum)) | |||
| def enterEvent(self, event): | |||
| self.fIsHovered = True | |||
| if self.fHoverStep == self.HOVER_MIN: | |||
| self.fHoverStep = self.HOVER_MIN + 1 | |||
| QDial.enterEvent(self, event) | |||
| def leaveEvent(self, event): | |||
| self.fIsHovered = False | |||
| if self.fHoverStep == self.HOVER_MAX: | |||
| self.fHoverStep = self.HOVER_MAX - 1 | |||
| QDial.leaveEvent(self, event) | |||
| def mousePressEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| return QDial.mousePressEvent(self, event) | |||
| if event.button() == Qt.LeftButton: | |||
| self.fIsPressed = True | |||
| self.fLastDragPos = event.pos() | |||
| self.fLastDragValue = self.fRealValue | |||
| self.dragStateChanged.emit(True) | |||
| def mouseMoveEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| return QDial.mouseMoveEvent(self, event) | |||
| if not self.fIsPressed: | |||
| return | |||
| range = (self.fMaximum - self.fMinimum) / 4.0 | |||
| pos = event.pos() | |||
| dx = range * float(pos.x() - self.fLastDragPos.x()) / self.width() | |||
| dy = range * float(pos.y() - self.fLastDragPos.y()) / self.height() | |||
| value = self.fLastDragValue + dx - dy | |||
| if value < self.fMinimum: | |||
| value = self.fMinimum | |||
| elif value > self.fMaximum: | |||
| value = self.fMaximum | |||
| elif self.fIsInteger: | |||
| value = float(round(value)) | |||
| self.setValue(value, True) | |||
| def mouseReleaseEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| return QDial.mouseReleaseEvent(self, event) | |||
| if self.fIsPressed: | |||
| self.fIsPressed = False | |||
| self.dragStateChanged.emit(False) | |||
| def paintEvent(self, event): | |||
| painter = QPainter(self) | |||
| event.accept() | |||
| painter.save() | |||
| painter.setRenderHint(QPainter.Antialiasing, True) | |||
| if self.fLabel: | |||
| if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL: | |||
| painter.setPen(self.fLabelGradientColor2) | |||
| painter.setBrush(self.fLabelGradient) | |||
| painter.drawRect(self.fLabelGradientRect) | |||
| painter.setFont(self.fLabelFont) | |||
| painter.setPen(self.fLabelGradientColorT[0 if self.isEnabled() else 1]) | |||
| painter.drawText(self.fLabelPos, self.fLabel) | |||
| def paintDial(self, painter): | |||
| if self.isEnabled(): | |||
| normValue = float(self.fRealValue - self.fMinimum) / float(self.fMaximum - self.fMinimum) | |||
| target = QRectF(0.0, 0.0, self.fPixmapBaseSize, self.fPixmapBaseSize) | |||
| @@ -494,26 +272,4 @@ class PixmapDial(QDial): | |||
| target = QRectF(0.0, 0.0, self.fPixmapBaseSize, self.fPixmapBaseSize) | |||
| painter.drawPixmap(target, self.fPixmap, target) | |||
| painter.restore() | |||
| def resizeEvent(self, event): | |||
| QDial.resizeEvent(self, event) | |||
| self.updateSizes() | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Main Testing | |||
| if __name__ == '__main__': | |||
| import sys | |||
| from PyQt5.QtWidgets import QApplication | |||
| import resources_rc | |||
| app = QApplication(sys.argv) | |||
| gui = PixmapDial(None) | |||
| #gui.setEnabled(True) | |||
| #gui.setEnabled(False) | |||
| gui.setPixmap(3) | |||
| gui.setLabel("hahaha") | |||
| gui.show() | |||
| sys.exit(app.exec_()) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -2,7 +2,7 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # Pixmap Keyboard, a custom Qt widget | |||
| # Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| @@ -16,19 +16,19 @@ | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import pyqtSignal, pyqtSlot, qCritical, Qt, QPointF, QRectF, QTimer, QSize | |||
| from PyQt5.QtGui import QColor, QFont, QPainter, QPixmap | |||
| from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QPointF, QRectF, QTimer, QSize | |||
| from PyQt5.QtGui import QColor, QPainter, QPixmap | |||
| from PyQt5.QtWidgets import QActionGroup, QMenu, QScrollArea, QWidget | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Custom) | |||
| from carla_shared import QSafeSettings | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| kMidiKey2RectMapHorizontal = [ | |||
| QRectF(0, 0, 24, 57), # C | |||
| @@ -175,6 +175,12 @@ kValidColors = ("Blue", "Green", "Orange", "Red") | |||
| kBlackNotes = (1, 3, 6, 8, 10) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| def _isNoteBlack(note): | |||
| baseNote = note % 12 | |||
| return bool(baseNote in kBlackNotes) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # MIDI Keyboard, using a pixmap for painting | |||
| @@ -502,7 +508,7 @@ class PixmapKeyboard(QWidget): | |||
| for note in self.fEnabledKeys: | |||
| pos = self._getRectFromMidiNote(note) | |||
| if self._isNoteBlack(note): | |||
| if _isNoteBlack(note): | |||
| continue | |||
| if note < 12: | |||
| @@ -558,7 +564,7 @@ class PixmapKeyboard(QWidget): | |||
| for note in self.fEnabledKeys: | |||
| pos = self._getRectFromMidiNote(note) | |||
| if not self._isNoteBlack(note): | |||
| if not _isNoteBlack(note): | |||
| continue | |||
| if note < 12: | |||
| @@ -605,15 +611,11 @@ class PixmapKeyboard(QWidget): | |||
| Qt.AlignCenter, | |||
| "C{}".format(octave)) | |||
| def _isNoteBlack(self, note): | |||
| baseNote = note % 12 | |||
| return bool(baseNote in kBlackNotes) | |||
| def _getRectFromMidiNote(self, note): | |||
| baseNote = note % 12 | |||
| return self.fKey2RectMap[baseNote] | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Horizontal scroll area for keyboard | |||
| class PixmapKeyboardHArea(QScrollArea): | |||
| @@ -641,18 +643,4 @@ class PixmapKeyboardHArea(QScrollArea): | |||
| def slot_initScrollbarValue(self): | |||
| self.horizontalScrollBar().setValue(int(self.horizontalScrollBar().maximum()/2)) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Main Testing | |||
| if __name__ == '__main__': | |||
| import sys | |||
| from PyQt5.QtWidgets import QApplication | |||
| import resources_rc | |||
| app = QApplication(sys.argv) | |||
| gui = PixmapKeyboard(None) | |||
| gui.setEnabled(True) | |||
| gui.show() | |||
| sys.exit(app.exec_()) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -16,7 +16,7 @@ | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import QPointF, QRectF | |||
| @@ -24,7 +24,7 @@ from PyQt5.QtGui import QColor, QFont, QPainter, QPixmap | |||
| from PyQt5.QtSvg import QSvgWidget | |||
| from PyQt5.QtWidgets import QPushButton | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Widget Class | |||
| class ScalableButton(QPushButton): | |||
| @@ -136,3 +136,5 @@ class ScalableButton(QPushButton): | |||
| else: | |||
| self.fImageNormal.renderer().render(painter, self.fImageRect) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -2,7 +2,7 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # Scalable Dial, a custom Qt widget | |||
| # Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License as | |||
| @@ -16,65 +16,24 @@ | |||
| # | |||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Global) | |||
| from math import cos, floor, pi, sin, isnan | |||
| from math import cos, floor, pi, sin | |||
| from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize | |||
| from PyQt5.QtGui import QColor, QConicalGradient, QFont, QFontMetrics | |||
| from PyQt5.QtGui import QLinearGradient, QPainter, QPainterPath, QPen, QPixmap | |||
| from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize | |||
| from PyQt5.QtGui import QColor, QConicalGradient, QFontMetrics, QPainterPath, QPen, QPixmap | |||
| from PyQt5.QtSvg import QSvgWidget | |||
| from PyQt5.QtWidgets import QDial | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Widget Class | |||
| class ScalableDial(QDial): | |||
| # enum CustomPaintMode | |||
| CUSTOM_PAINT_MODE_NULL = 0 # default (NOTE: only this mode has label gradient) | |||
| CUSTOM_PAINT_MODE_CARLA_WET = 1 # color blue-green gradient (reserved #3) | |||
| CUSTOM_PAINT_MODE_CARLA_VOL = 2 # color blue (reserved #3) | |||
| CUSTOM_PAINT_MODE_CARLA_L = 3 # color yellow (reserved #4) | |||
| CUSTOM_PAINT_MODE_CARLA_R = 4 # color yellow (reserved #4) | |||
| CUSTOM_PAINT_MODE_CARLA_PAN = 5 # color yellow (reserved #3) | |||
| CUSTOM_PAINT_MODE_COLOR = 6 # color, selectable (reserved #3) | |||
| CUSTOM_PAINT_MODE_ZITA = 7 # custom zita knob (reserved #6) | |||
| CUSTOM_PAINT_MODE_NO_GRADIENT = 8 # skip label gradient | |||
| # enum Orientation | |||
| HORIZONTAL = 0 | |||
| VERTICAL = 1 | |||
| HOVER_MIN = 0 | |||
| HOVER_MAX = 9 | |||
| from .commondial import CommonDial | |||
| MODE_DEFAULT = 0 | |||
| MODE_LINEAR = 1 | |||
| # signals | |||
| dragStateChanged = pyqtSignal(bool) | |||
| realValueChanged = pyqtSignal(float) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Widget Class | |||
| class ScalableDial(CommonDial): | |||
| def __init__(self, parent, index=0): | |||
| QDial.__init__(self, parent) | |||
| self.fDialMode = self.MODE_LINEAR | |||
| self.fMinimum = 0.0 | |||
| self.fMaximum = 1.0 | |||
| self.fRealValue = 0.0 | |||
| self.fPrecision = 10000 | |||
| self.fIsInteger = False | |||
| CommonDial.__init__(self, parent, index) | |||
| self.fIsHovered = False | |||
| self.fIsPressed = False | |||
| self.fHoverStep = self.HOVER_MIN | |||
| self.fLastDragPos = None | |||
| self.fLastDragValue = 0.0 | |||
| self.fIndex = index | |||
| self.fImage = QSvgWidget(":/scalable/dial_03.svg") | |||
| self.fImageNum = "01" | |||
| @@ -83,60 +42,11 @@ class ScalableDial(QDial): | |||
| else: | |||
| self.fImageOrientation = self.VERTICAL | |||
| self.fLabel = "" | |||
| self.fLabelPos = QPointF(0.0, 0.0) | |||
| self.fLabelFont = QFont(self.font()) | |||
| self.fLabelFont.setPixelSize(8) | |||
| self.fLabelWidth = 0 | |||
| self.fLabelHeight = 0 | |||
| if self.palette().window().color().lightness() > 100: | |||
| # Light background | |||
| c = self.palette().dark().color() | |||
| self.fLabelGradientColor1 = c | |||
| self.fLabelGradientColor2 = QColor(c.red(), c.green(), c.blue(), 0) | |||
| self.fLabelGradientColorT = [self.palette().buttonText().color(), self.palette().mid().color()] | |||
| else: | |||
| # Dark background | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [Qt.white, Qt.darkGray] | |||
| self.fLabelGradient = QLinearGradient(0, 0, 0, 1) | |||
| self.fLabelGradient.setColorAt(0.0, self.fLabelGradientColor1) | |||
| self.fLabelGradient.setColorAt(0.6, self.fLabelGradientColor1) | |||
| self.fLabelGradient.setColorAt(1.0, self.fLabelGradientColor2) | |||
| self.fLabelGradientRect = QRectF(0.0, 0.0, 0.0, 0.0) | |||
| self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_NULL | |||
| self.fCustomPaintColor = QColor(0xff, 0xff, 0xff) | |||
| self.updateSizes() | |||
| # Fake internal value, custom precision | |||
| QDial.setMinimum(self, 0) | |||
| QDial.setMaximum(self, self.fPrecision) | |||
| QDial.setValue(self, 0) | |||
| self.valueChanged.connect(self.slot_valueChanged) | |||
| def getIndex(self): | |||
| return self.fIndex | |||
| def getBaseSize(self): | |||
| return self.fImageBaseSize | |||
| def forceWhiteLabelGradientText(self): | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [Qt.white, Qt.darkGray] | |||
| def setLabelColor(self, enabled, disabled): | |||
| self.fLabelGradientColor1 = QColor(0, 0, 0, 255) | |||
| self.fLabelGradientColor2 = QColor(0, 0, 0, 0) | |||
| self.fLabelGradientColorT = [enabled, disabled] | |||
| def updateSizes(self): | |||
| if isinstance(self.fImage, QPixmap): | |||
| self.fImageWidth = self.fImage.width() | |||
| @@ -184,31 +94,6 @@ class ScalableDial(QDial): | |||
| self.fLabelGradientRect = QRectF(float(self.fImageBaseSize)/8.0, float(self.fImageBaseSize)/2.0, | |||
| float(self.fImageBaseSize*3)/4.0, self.fImageBaseSize+self.fLabelHeight+5) | |||
| def setCustomPaintMode(self, paintMode): | |||
| if self.fCustomPaintMode == paintMode: | |||
| return | |||
| self.fCustomPaintMode = paintMode | |||
| self.update() | |||
| def setCustomPaintColor(self, color): | |||
| if self.fCustomPaintColor == color: | |||
| return | |||
| self.fCustomPaintColor = color | |||
| self.update() | |||
| def setLabel(self, label): | |||
| if self.fLabel == label: | |||
| return | |||
| self.fLabel = label | |||
| self.updateSizes() | |||
| self.update() | |||
| def setIndex(self, index): | |||
| self.fIndex = index | |||
| def setImage(self, imageId): | |||
| self.fImageNum = "%02i" % imageId | |||
| if imageId in (2,6,7,8,9,10,11,12,13): | |||
| @@ -247,49 +132,6 @@ class ScalableDial(QDial): | |||
| self.updateSizes() | |||
| self.update() | |||
| def setPrecision(self, value, isInteger): | |||
| self.fPrecision = value | |||
| self.fIsInteger = isInteger | |||
| QDial.setMaximum(self, int(value)) | |||
| def setMinimum(self, value): | |||
| self.fMinimum = value | |||
| def setMaximum(self, value): | |||
| self.fMaximum = value | |||
| def rvalue(self): | |||
| return self.fRealValue | |||
| def setValue(self, value, emitSignal=False): | |||
| if self.fRealValue == value or isnan(value): | |||
| return | |||
| if value <= self.fMinimum: | |||
| qtValue = 0 | |||
| self.fRealValue = self.fMinimum | |||
| elif value >= self.fMaximum: | |||
| qtValue = int(self.fPrecision) | |||
| self.fRealValue = self.fMaximum | |||
| else: | |||
| qtValue = round(float(value - self.fMinimum) / float(self.fMaximum - self.fMinimum) * self.fPrecision) | |||
| self.fRealValue = value | |||
| # Block change signal, we'll handle it ourselves | |||
| self.blockSignals(True) | |||
| QDial.setValue(self, qtValue) | |||
| self.blockSignals(False) | |||
| if emitSignal: | |||
| self.realValueChanged.emit(self.fRealValue) | |||
| @pyqtSlot(int) | |||
| def slot_valueChanged(self, value): | |||
| self.fRealValue = float(value)/self.fPrecision * (self.fMaximum - self.fMinimum) + self.fMinimum | |||
| self.realValueChanged.emit(self.fRealValue) | |||
| @pyqtSlot() | |||
| def slot_updateImage(self): | |||
| self.setImage(int(self.fImageNum)) | |||
| @@ -301,81 +143,13 @@ class ScalableDial(QDial): | |||
| return QSize(self.fImageBaseSize, self.fImageBaseSize) | |||
| def changeEvent(self, event): | |||
| QDial.changeEvent(self, event) | |||
| CommonDial.changeEvent(self, event) | |||
| # Force svg update if enabled state changes | |||
| if event.type() == QEvent.EnabledChange: | |||
| self.slot_updateImage() | |||
| def enterEvent(self, event): | |||
| self.fIsHovered = True | |||
| if self.fHoverStep == self.HOVER_MIN: | |||
| self.fHoverStep = self.HOVER_MIN + 1 | |||
| QDial.enterEvent(self, event) | |||
| def leaveEvent(self, event): | |||
| self.fIsHovered = False | |||
| if self.fHoverStep == self.HOVER_MAX: | |||
| self.fHoverStep = self.HOVER_MAX - 1 | |||
| QDial.leaveEvent(self, event) | |||
| def mousePressEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| return QDial.mousePressEvent(self, event) | |||
| if event.button() == Qt.LeftButton: | |||
| self.fIsPressed = True | |||
| self.fLastDragPos = event.pos() | |||
| self.fLastDragValue = self.fRealValue | |||
| self.dragStateChanged.emit(True) | |||
| def mouseMoveEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| return QDial.mouseMoveEvent(self, event) | |||
| if not self.fIsPressed: | |||
| return | |||
| range = (self.fMaximum - self.fMinimum) / 4.0 | |||
| pos = event.pos() | |||
| dx = range * float(pos.x() - self.fLastDragPos.x()) / self.width() | |||
| dy = range * float(pos.y() - self.fLastDragPos.y()) / self.height() | |||
| value = self.fLastDragValue + dx - dy | |||
| if value < self.fMinimum: | |||
| value = self.fMinimum | |||
| elif value > self.fMaximum: | |||
| value = self.fMaximum | |||
| elif self.fIsInteger: | |||
| value = float(round(value)) | |||
| self.setValue(value, True) | |||
| def mouseReleaseEvent(self, event): | |||
| if self.fDialMode == self.MODE_DEFAULT: | |||
| return QDial.mouseReleaseEvent(self, event) | |||
| if self.fIsPressed: | |||
| self.fIsPressed = False | |||
| self.dragStateChanged.emit(False) | |||
| def paintEvent(self, event): | |||
| painter = QPainter(self) | |||
| event.accept() | |||
| painter.save() | |||
| painter.setRenderHint(QPainter.Antialiasing, True) | |||
| if self.fLabel: | |||
| if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL: | |||
| painter.setPen(self.fLabelGradientColor2) | |||
| painter.setBrush(self.fLabelGradient) | |||
| painter.drawRect(self.fLabelGradientRect) | |||
| painter.setFont(self.fLabelFont) | |||
| painter.setPen(self.fLabelGradientColorT[0 if self.isEnabled() else 1]) | |||
| painter.drawText(self.fLabelPos, self.fLabel) | |||
| def paintDial(self, painter): | |||
| if self.isEnabled(): | |||
| normValue = float(self.fRealValue - self.fMinimum) / float(self.fMaximum - self.fMinimum) | |||
| curLayer = int((self.fImageLayersCount - 1) * normValue) | |||
| @@ -521,26 +295,4 @@ class ScalableDial(QDial): | |||
| else: | |||
| self.fImage.renderer().render(painter, target) | |||
| painter.restore() | |||
| def resizeEvent(self, event): | |||
| QDial.resizeEvent(self, event) | |||
| self.updateSizes() | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Main Testing | |||
| if __name__ == '__main__': | |||
| import sys | |||
| from PyQt5.QtWidgets import QApplication | |||
| import resources_rc | |||
| app = QApplication(sys.argv) | |||
| gui = ScalableDial(None) | |||
| #gui.setEnabled(True) | |||
| #gui.setEnabled(False) | |||
| gui.setSvg(3) | |||
| gui.setLabel("hahaha") | |||
| gui.show() | |||
| sys.exit(app.exec_()) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||