Browse Source

create-Qt-pushbuttons

pull/1970/head
jpka- 1 year ago
parent
commit
1c35114467
3 changed files with 414 additions and 206 deletions
  1. +26
    -6
      source/frontend/carla_skin.py
  2. +79
    -5
      source/frontend/widgets/commondial.py
  3. +309
    -195
      source/frontend/widgets/scalabledial.py

+ 26
- 6
source/frontend/carla_skin.py View File

@@ -6,6 +6,7 @@
# Imports (Global)

from qt_compat import qt_config
import math

if qt_config == 5:
from PyQt5.QtCore import Qt, QRectF, QLineF, QTimer
@@ -573,19 +574,20 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
paramInfo = self.host.get_parameter_info(self.fPluginId, i)
paramData = self.host.get_parameter_data(self.fPluginId, i)
paramRanges = self.host.get_parameter_ranges(self.fPluginId, i)
isBoolean = (paramData['hints'] & PARAMETER_IS_BOOLEAN) != 0
isInteger = (paramData['hints'] & PARAMETER_IS_INTEGER) != 0

if paramData['type'] != PARAMETER_INPUT:
continue
if paramData['hints'] & PARAMETER_IS_BOOLEAN:
continue
# if paramData['hints'] & PARAMETER_IS_BOOLEAN:
# continue
if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0:
continue
if (paramData['hints'] & PARAMETER_USES_SCALEPOINTS) != 0 and not isInteger:
# NOTE: we assume integer scalepoints are continuous
continue
if isInteger and paramRanges['max']-paramRanges['min'] <= 3:
continue
# if isInteger and paramRanges['max']-paramRanges['min'] <= 3:
# continue
if paramInfo['name'].startswith("unused"):
continue

@@ -597,8 +599,26 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
widget.setMaximum(paramRanges['max'])
widget.hide()

if isInteger:
widget.setPrecision(paramRanges['max']-paramRanges['min'], True)
delta = paramRanges['max']-paramRanges['min']
if delta <= 0:
print("ERROR: Parameter "+str(i)+": Max and Min are same or wrong.")
return

if isBoolean: # Mimic as [0 or 1] integer
widget.setPrecision(1, True)

elif isInteger:
while delta > 50:
delta = int(math.ceil(delta / 2))
widget.setPrecision(delta, True)

else: # Floats are need to be more fine-step smoothed
delta = paramRanges['max']-paramRanges['min']
while delta > 500:
delta = delta / 2.0
while delta < 250:
delta = delta * 2.0
widget.setPrecision(math.ceil(delta), False)

setScalableDialStyle(widget, i, parameterCount, whiteLabels, self.fSkinStyle)



+ 79
- 5
source/frontend/widgets/commondial.py View File

@@ -61,6 +61,7 @@ class CommonDial(QDial):
self.fRealValue = 0.0
self.fPrecision = 10000
self.fIsInteger = False
self.fIsButton = False

self.fIsHovered = False
self.fIsPressed = False
@@ -126,7 +127,11 @@ class CommonDial(QDial):
def setPrecision(self, value, isInteger):
self.fPrecision = value
self.fIsInteger = isInteger
# NOTE: Booleans are mimic as isInteger with range [0 or 1].
if self.fIsInteger and (self.fMinimum == 0) and (self.fMaximum in (1, 2)):
self.fIsButton = True
QDial.setMaximum(self, int(value))
# print("setPrecision "+str(value)+" "+str(isInteger)+" "+str(self.fIsButton))

def setMinimum(self, value):
self.fMinimum = value
@@ -189,6 +194,9 @@ class CommonDial(QDial):
self.realValueChanged.emit(self.fRealValue)

def enterEvent(self, event):

self.setFocus(Qt.MouseFocusReason)

self.fIsHovered = True
if self.fHoverStep == self.HOVER_MIN:
self.fHoverStep = self.HOVER_MIN + 1
@@ -206,10 +214,16 @@ class CommonDial(QDial):
return

if event.button() == Qt.LeftButton:
self.fIsPressed = True
self.fLastDragPos = event.pos()
self.fLastDragValue = self.fRealValue
self.dragStateChanged.emit(True)
if self.fIsButton:
value = self.value() + 1;
if (value > self.fMaximum):
value = 0;
self.setValue(value, True)
else:
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:
@@ -243,6 +257,62 @@ class CommonDial(QDial):
self.fIsPressed = False
self.dragStateChanged.emit(False)

def wheelEvent(self, event):
direction = event.angleDelta().y()
mod = int(event.modifiers())
if direction < 0:
delta = -1.0
elif direction > 0:
delta = 1.0
else:
return

if self.fIsButton:
self.setValue(self.rvalue() + delta, True)
return

if self.fIsInteger: # max. 50 ticks per revolution
if (mod & Qt.ShiftModifier):
delta = delta * 5
else: # Floats are 250 to 500 ticks per revolution
if (mod & Qt.ControlModifier):
delta = delta * 2
elif (mod & Qt.ShiftModifier):
delta = delta * 50
else:
delta = delta * 10
self.setValue(self.rvalue() + float(self.fMaximum-self.fMinimum)*(float(delta)/float(self.fPrecision)), True)

return

def keyPressEvent(self, event):
key = event.key()
mod = int(event.modifiers())
# print(str(self.value())+" "+str(self.rvalue())+" "+str(self.fMinimum)+" "+str(self.fMaximum))

match key:
case key if Qt.Key_0 <= key <= Qt.Key_9:
if self.fIsButton:
self.setValue(key-Qt.Key_0, True)
else:
self.setValue(self.fMinimum + float(self.fMaximum-self.fMinimum)/10.0*(key-Qt.Key_0), True)
case Qt.Key_Home: # NOTE: interferes with Canvas control hotkey
self.setValue(self.fMinimum, True)
case Qt.Key_End:
self.setValue(self.fMaximum, True)
case Qt.Key_PageDown:
if self.fIsButton:
self.setValue(self.rvalue() - 1, True)
else:
self.setValue(self.rvalue() - float(self.fMaximum-self.fMinimum)/10.0, True)
case Qt.Key_PageUp:
if self.fIsButton:
self.setValue(self.rvalue() + 1, True)
else:
self.setValue(self.rvalue() + float(self.fMaximum-self.fMinimum)/10.0, True)

return

def paintEvent(self, event):
painter = QPainter(self)
event.accept()
@@ -260,7 +330,11 @@ class CommonDial(QDial):
painter.setPen(self.fLabelGradientColorT[0 if self.isEnabled() else 1])
painter.drawText(self.fLabelPos, self.fLabel)

self.paintDial(painter)
if self.fIsButton:
# Only 0 or 1 values (normal 2-pos. switch) or 0, 1 and 2 (3-pos. one).
self.paintButton(painter, self.fMaximum)
else:
self.paintDial(painter)

painter.restore()



+ 309
- 195
source/frontend/widgets/scalabledial.py View File

@@ -5,18 +5,17 @@
# ---------------------------------------------------------------------------------------------------------------------
# Imports (Global)

from math import cos, floor, pi, sin
from math import cos, floor, pi, sin, copysign
import numpy as np

from qt_compat import qt_config

if qt_config == 5:
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.QtGui import QColor, QLinearGradient, QRadialGradient, QConicalGradient, QFontMetrics, QPen
elif qt_config == 6:
from PyQt6.QtCore import pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize
from PyQt6.QtGui import QColor, QConicalGradient, QFontMetrics, QPainterPath, QPen, QPixmap
from PyQt6.QtSvgWidgets import QSvgWidget
from PyQt6.QtGui import QColor, QLinearGradient, QRadialGradient, QConicalGradient, QFontMetrics, QPen

from .commondial import CommonDial
from carla_shared import fontMetricsHorizontalAdvance
@@ -27,44 +26,14 @@ from carla_shared import fontMetricsHorizontalAdvance
class ScalableDial(CommonDial):
def __init__(self, parent, index=0):
CommonDial.__init__(self, parent, index)

self.fImage = QSvgWidget(":/scalable/dial_03.svg")
self.fImageNum = "01"

if self.fImage.sizeHint().width() > self.fImage.sizeHint().height():
self.fImageOrientation = self.HORIZONTAL
else:
self.fImageOrientation = self.VERTICAL

self.updateSizes()
self.setImage(0)

def getBaseSize(self):
return self.fImageBaseSize

def updateSizes(self):
if isinstance(self.fImage, QPixmap):
self.fImageWidth = self.fImage.width()
self.fImageHeight = self.fImage.height()
else:
self.fImageWidth = self.fImage.sizeHint().width()
self.fImageHeight = self.fImage.sizeHint().height()

if self.fImageWidth < 1:
self.fImageWidth = 1

if self.fImageHeight < 1:
self.fImageHeight = 1

if self.fImageOrientation == self.HORIZONTAL:
self.fImageBaseSize = self.fImageHeight
self.fImageLayersCount = self.fImageWidth / self.fImageHeight
else:
self.fImageBaseSize = self.fImageWidth
self.fImageLayersCount = self.fImageHeight / self.fImageWidth

self.setMinimumSize(self.fImageBaseSize, self.fImageBaseSize + self.fLabelHeight + 5)
self.setMaximumSize(self.fImageBaseSize, self.fImageBaseSize + self.fLabelHeight + 5)

if not self.fLabel:
self.fLabelHeight = 0
self.fLabelWidth = 0
@@ -76,9 +45,9 @@ class ScalableDial(CommonDial):

self.fLabelPos.setX(float(self.fImageBaseSize)/2.0 - float(self.fLabelWidth)/2.0)

if self.fImageNum in ("01", "02", "07", "08", "09", "10"):
if self.fImageId in (1, 2, 7, 8, 9, 10):
self.fLabelPos.setY(self.fImageBaseSize + self.fLabelHeight)
elif self.fImageNum in ("11",):
elif self.fImageId in (11,):
self.fLabelPos.setY(self.fImageBaseSize + self.fLabelHeight*2/3)
else:
self.fLabelPos.setY(self.fImageBaseSize + self.fLabelHeight/2)
@@ -90,46 +59,33 @@ class ScalableDial(CommonDial):
float(self.fImageBaseSize*3)/4.0, self.fImageBaseSize+self.fLabelHeight+5)

def setImage(self, imageId):
self.fImageNum = "%02i" % imageId
if imageId in (2,6,7,8,9,10,11,12,13):
img = ":/bitmaps/dial_%s%s.png" % (self.fImageNum, "" if self.isEnabled() else "d")
else:
img = ":/scalable/dial_%s%s.svg" % (self.fImageNum, "" if self.isEnabled() else "d")

if img.endswith(".png"):
if not isinstance(self.fImage, QPixmap):
self.fImage = QPixmap()
else:
if not isinstance(self.fImage, QSvgWidget):
self.fImage = QSvgWidget()

self.fImage.load(img)
self.fImageId = imageId
self.fImageBaseSize = 30 # internal
if (imageId == 0):
return

if self.fImage.width() > self.fImage.height():
self.fImageOrientation = self.HORIZONTAL
else:
self.fImageOrientation = self.VERTICAL
if imageId in (7, 8, 9, 10): # calf
self.fImageBaseSize = 40
elif imageId in (11, 12, 13): # openav
self.fImageBaseSize = 32

# special svgs
if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
# reserved for carla-wet, carla-vol, carla-pan and color
if self.fImageNum == "03":
if self.fImageId == 3:
self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_COLOR

# reserved for carla-L and carla-R
elif self.fImageNum == "04":
elif self.fImageId == 4:
self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_CARLA_L

# reserved for zita
elif self.fImageNum == "06":
self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_ZITA
self.fImageBaseSize = 26

self.updateSizes()
self.update()

@pyqtSlot()
def slot_updateImage(self):
self.setImage(int(self.fImageNum))
self.setImage(int(self.fImageId))

def minimumSizeHint(self):
return QSize(self.fImageBaseSize, self.fImageBaseSize)
@@ -144,149 +100,307 @@ class ScalableDial(CommonDial):
if event.type() == QEvent.EnabledChange:
self.slot_updateImage()

def paintDial(self, painter):
def checkEnabled(self):
if self.isEnabled():
normValue = float(self.fRealValue - self.fMinimum) / float(self.fMaximum - self.fMinimum)
curLayer = int((self.fImageLayersCount - 1) * normValue)
if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
self.fHoverStep += 1 if self.fIsHovered else -1
QTimer.singleShot(20, self.update)
return 1
else:
return 0

def normValue(self):
return float(self.fRealValue - self.fMinimum) / float(self.fMaximum - self.fMinimum)

def drawMark(self, painter, X, Y, r1, r2, angle, width, color):
x = X + r1 * cos(angle)
y = Y - r1 * sin(angle)
painter.setPen(QPen(color, width, cap=Qt.RoundCap))
if not (r1 == r2): # line
x1 = X + r2 * cos(angle)
y1 = Y - r2 * sin(angle)
painter.drawLine(QPointF(x, y), QPointF(x1, y1))
else: # ball
painter.drawEllipse(QRectF(x-width/2, y-width/2, width, width))

def gradMachined(self):
return {5.9, 10.7, 15.7, 20.8, 25.8, 30.6, 40.6, 45.9,
55.9, 60.7, 65.7, 70.8, 75.8, 80.6, 90.6, 95.9}

def grayGrad(self, painter, X, Y, a, b, gradPairs):
if b == -1:
grad = QConicalGradient(X, Y, a)
elif b == -2:
grad = QRadialGradient (X, Y, a)
else:
grad = QLinearGradient (X, Y, a, b)

for i in gradPairs:
grad.setColorAt(int(i)/100.0, QColor.fromHslF(0, 0, (i % 1.0), 1))

return grad


def paintDial(self, painter):

if self.fImageOrientation == self.HORIZONTAL:
xpos = self.fImageBaseSize * curLayer
ypos = 0.0
# Replace Qt draw over substrate bitmap or svg to
# all-in-one widget generated from stratch using Qt only,
# make it highly tuneable, and uniformly look like
# using HSL color model to make same brightness of colored things.
# We can also easily have color tinted (themed) knobs.
# Some things were simplified a little, to gain more speed.
# R: knob nib (cap) radius
def createDial(R, hue1, hue2, barWidth, angleSpan, ticks, dialType, value):

def rectBorder(w):
return QRectF(X-R-w, Y-R-w, (R+w)*2, (R+w)*2)

def gray(luma):
return QColor.fromHslF(0, 0, luma, 1)

X = Y = self.fImageBaseSize / 2 # center

ang0 = int((angleSpan/2+90)*16)
ang1 = -angleSpan*16

enabled = self.checkEnabled()
E = enabled * self.fHoverStep / 40 # enlight
S = enabled * 0.9 # saturation
color1 = QColor.fromHslF(hue1, S, 0.5+E, 1)
color2 = QColor.fromHslF(hue2, S, 0.5+E, 1)

if dialType == 1: # mimic svg dial
# light arc substrate: near black, 0.5 px exposed
painter.setPen(QPen(gray(0.10), barWidth+1, cap=Qt.FlatCap))
painter.drawArc(rectBorder(barWidth), ang0, ang1)

# light arc: gray bar
# should be combined with light (value) arc to be a bit faster ?
painter.setPen(QPen(self.grayGrad(painter, X, Y, 270, -1, {0.20, 100.15}), barWidth, cap=Qt.FlatCap))
painter.drawArc(rectBorder(barWidth), ang0, ang1)

# cap
painter.setBrush(self.grayGrad(painter, X-R, Y-R, R*2, -2, {0.45+E, 100.15+E}))
painter.setPen(QPen(gray(0.10), 0.5))
painter.drawEllipse(rectBorder(1))

elif dialType == 2: # calf
# outer chamfer & leds substrate
painter.setPen(QPen(self.grayGrad(painter, X, Y, 135, -1, {0.15, 50.50, 100.15}), 1.5, cap=Qt.FlatCap))
painter.setBrush(QColor.fromHslF(hue1, S, 0.05+E/2, 1))
painter.drawEllipse(rectBorder(barWidth*2-1))

# machined shiny cap with chamfer
painter.setPen(QPen(self.grayGrad(painter, X, Y, -45, -1, {0.15, 50.50, 100.15}), 1, cap=Qt.FlatCap))
painter.setBrush(self.grayGrad(painter, X, Y, 0, -1, self.gradMachined()))
painter.drawEllipse(rectBorder(1))

elif dialType == 3: # openav
# light arc substrate
painter.setPen(QPen(gray(0.20+E), barWidth))
painter.drawArc(rectBorder(barWidth), ang0, ang1)


# draw arc: forward, or reverse (for 'R' ch knob)
startAngle = int((copysign(angleSpan/2, value) + 90)*16)
gradient = QConicalGradient(X, Y, 270)

if (ticks == 0):
spanAngle = int(-angleSpan*16 * value)
gradient.setColorAt(0.25, color1)
gradient.setColorAt(0.75, color2)
else:
xpos = 0.0
ypos = self.fImageBaseSize * curLayer
# discretize scale: for 10 points, first will lit at 5%,
# then 15%, and last at 95% of normalized value,
# i.e. treshold is: center of point exactly matches knob mark angle
spanAngle = int(-int(angleSpan*value/(360/ticks)+0.5)*(360/ticks)*16)
for i in range(2, ticks-2, 1):
gradient.setColorAt((i+0.5-0.35)/ticks, color1.lighter(100))
gradient.setColorAt((i+0.5) /ticks, Qt.black)
gradient.setColorAt((i+0.5+0.35)/ticks, color1.lighter(100))

painter.setPen(QPen(gradient, barWidth, cap=Qt.RoundCap if dialType == 3 else Qt.FlatCap))
painter.drawArc(QRectF(rectBorder(barWidth)), startAngle, spanAngle)

# do not draw marks on disabled items
if enabled == 0:
return

# Forward or reverse (for 'R' ch knob)
angle = ((0.5-abs(value)) * copysign(angleSpan, value) + 90) * pi/180

match dialType:
case 1: # ball
self.drawMark(painter,X,Y, R*0.8, R*0.8, angle, barWidth/2, color1)
case 2: # line for calf
self.drawMark(painter,X,Y, R*0.6, R*0.9, angle, barWidth/2, Qt.black)
case 3: # line for openav
self.drawMark(painter,X,Y, 0, R+barWidth, angle, barWidth, color1)


# Custom knobs (Dry/Wet and Volume)
if self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_WET, self.CUSTOM_PAINT_MODE_CARLA_VOL):
hue2 = 0.5 # Blue
hue1 = hue2 if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_VOL else 0.3 # Green

createDial(10, hue1, hue2, 3, 260, 0, 1, self.normValue())

# Custom knobs (L and R)
elif self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_L, self.CUSTOM_PAINT_MODE_CARLA_R):
hue = 0.21 # Lime

# Shift to full negative range (incl. 0) for reversed knob
createDial(8, hue, hue, 2.5, 260, 0, 1, self.normValue()-1.0-np.nextafter(0, 1) if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_R else self.normValue())

# Custom knobs (Color) # internal
elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_COLOR:
# NOTE: here all incoming color data, except hue, is lost.
hue = (self.fCustomPaintColor.hueF() - 0.05) % 1.0

source = QRectF(xpos, ypos, self.fImageBaseSize, self.fImageBaseSize)
createDial(10, hue, hue, 3, 260, 0, 1, self.normValue())

if isinstance(self.fImage, QPixmap):
target = QRectF(0.0, 0.0, self.fImageBaseSize, self.fImageBaseSize)
painter.drawPixmap(target, self.fImage, source)
# Custom knobs
elif self.fImageId in (11, 12, 13): # openav
if self.fImageId == 11:
hue1 = hue2 = 0.05 # Orange
else:
self.fImage.renderer().render(painter, source)

# Custom knobs (Dry/Wet and Volume)
if self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_WET, self.CUSTOM_PAINT_MODE_CARLA_VOL):
# knob color
colorGreen = QColor(0x5D, 0xE7, 0x3D).lighter(100 + self.fHoverStep*6)
colorBlue = QColor(0x3E, 0xB8, 0xBE).lighter(100 + self.fHoverStep*6)

# draw small circle
ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
ballPath = QPainterPath()
ballPath.addEllipse(ballRect)
#painter.drawRect(ballRect)
tmpValue = (0.375 + 0.75*normValue)
ballValue = tmpValue - floor(tmpValue)
ballPoint = ballPath.pointAtPercent(ballValue)

# draw arc
startAngle = 218*16
spanAngle = -255*16*normValue

if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_WET:
painter.setBrush(colorBlue)
painter.setPen(QPen(colorBlue, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

gradient = QConicalGradient(15.5, 15.5, -45)
gradient.setColorAt(0.0, colorBlue)
gradient.setColorAt(0.125, colorBlue)
gradient.setColorAt(0.625, colorGreen)
gradient.setColorAt(0.75, colorGreen)
gradient.setColorAt(0.76, colorGreen)
gradient.setColorAt(1.0, colorGreen)
painter.setBrush(gradient)
painter.setPen(QPen(gradient, 3))
hue2 = 0.5 # Blue
hue1 = hue2 if self.fImageId == 12 else 0.3 # Green

createDial(12, hue1, hue2, 2.5, 270, 0, 3, self.normValue())

elif self.fImageId in (1, 2, 7, 8, 9, 10): # calf
hue = 0.52 # Aqua

createDial(12, hue, hue, 4, (360/36)*29, 36, 2, self.normValue())

else:
print("Unknown type "+ str(self.fImageId) + " knob.")
return


def paintButton(self, painter, range_):

# W: button cap half-size ; w: bar width
# positions: can be 2 or 3
def createButton(W, hue, w, positions, btnType, value):

def rectBorder(w):
return QRectF(X-W-w, Y-W-w, (W+w)*2, (W+w)*2)

def gray(luma):
return QColor.fromHslF(0, 0, luma, 1)

X = Y = self.fImageBaseSize / 2 # center

enabled = self.checkEnabled()
E = enabled * self.fHoverStep / 40 # enlight
S = enabled * 0.9 # saturation
color = QColor.fromHslF(hue, S, 0.5+E, 1)

if btnType == 1: # internal
# light bar substrate: near black, 0.5 px exposed
painter.setPen(QPen(gray(0.10), w+1))
painter.drawLine(QPointF(X-W/2, Y-W-w), QPointF(X+W/2, Y-W-w))

# light bar: gray bar
painter.setPen(QPen(gray(0.20), w))
painter.drawLine(QPointF(X-W/2, Y-W-w), QPointF(X+W/2, Y-W-w))

# cap
painter.setBrush(self.grayGrad(painter, X-W/2, Y-W/2, W*2, -2, {0.15+E, 100.28+E}))
painter.setPen(QPen(gray(0.10), 0.5))
painter.drawRoundedRect(rectBorder(-2), 3, 3)

elif btnType == 2: # calf
# outer chamfer & leds substrate
painter.setPen(QPen(self.grayGrad(painter, X, Y, 135, -1, {24.25, 26.50, 76.50, 78.25}), 1.5, cap=Qt.FlatCap))
painter.setBrush(QColor.fromHslF(hue, S, 0.05+E/2, 1))
painter.drawRoundedRect(QRectF(X-W-1, Y-W-w-0-1, W*2+2, W*2+w+0+2), 4, 4)

# machined shiny cap with chamfer
painter.setPen(QPen(self.grayGrad(painter, X, Y, -45, -1, {24.25, 26.50, 74.50, 76.25}), 1, cap=Qt.FlatCap))
painter.setBrush(self.grayGrad(painter, X, Y, -30, -1, self.gradMachined( )))
painter.drawRoundedRect(rectBorder(-1), 3, 3)

elif btnType == 3: # openav
# light substrate
pen = QPen(gray(0.20+E), w)
painter.setPen(pen)
painter.drawRoundedRect(rectBorder(0), 3, 3)


# draw active lights
if (value > (1/2-(positions-2)*(2/3-1/2))):
if (1/3 < value < 2/3) and (positions == 3):
pos = 1 # Middle
else:
painter.setBrush(colorBlue)
painter.setPen(QPen(colorBlue, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

painter.setBrush(colorBlue)
painter.setPen(QPen(colorBlue, 3))

painter.drawArc(QRectF(4.0, 4.0, 26.0, 26.0), int(startAngle), int(spanAngle))

# Custom knobs (L and R)
elif self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_L, self.CUSTOM_PAINT_MODE_CARLA_R):
# knob color
color = QColor(0xAD, 0xD5, 0x48).lighter(100 + self.fHoverStep*6)

# draw small circle
ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
ballPath = QPainterPath()
ballPath.addEllipse(ballRect)
#painter.drawRect(ballRect)
tmpValue = (0.375 + 0.75*normValue)
ballValue = tmpValue - floor(tmpValue)
ballPoint = ballPath.pointAtPercent(ballValue)

painter.setBrush(color)
painter.setPen(QPen(color, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0))

# draw arc
if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_L:
startAngle = 218*16
spanAngle = -255*16*normValue
else:
startAngle = 322.0*16
spanAngle = 255.0*16*(1.0-normValue)

painter.setPen(QPen(color, 2.5))
painter.drawArc(QRectF(3.5, 3.5, 22.0, 22.0), int(startAngle), int(spanAngle))

# Custom knobs (Color)
elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_COLOR:
# knob color
color = self.fCustomPaintColor.lighter(100 + self.fHoverStep*6)

# draw small circle
ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
ballPath = QPainterPath()
ballPath.addEllipse(ballRect)
tmpValue = (0.375 + 0.75*normValue)
ballValue = tmpValue - floor(tmpValue)
ballPoint = ballPath.pointAtPercent(ballValue)

# draw arc
startAngle = 218*16
spanAngle = -255*16*normValue

painter.setBrush(color)
painter.setPen(QPen(color, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

painter.setBrush(color)
painter.setPen(QPen(color, 3))
painter.drawArc(QRectF(4.0, 4.8, 26.0, 26.0), int(startAngle), int(spanAngle))

# Custom knobs (Zita)
elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_ZITA:
a = normValue * pi * 1.5 - 2.35
r = 10.0
x = 10.5
y = 10.5
x += r * sin(a)
y -= r * cos(a)
painter.setBrush(Qt.black)
painter.setPen(QPen(Qt.black, 2))
painter.drawLine(QPointF(11.0, 11.0), QPointF(x, y))

# Custom knobs
pos = 2 # Max
else:
pos = 0

if btnType == 1: # internal
if (pos > 0):
painter.setPen(QPen(color, w))
if (pos == 1):
painter.drawLine(QPointF(X-W/2, Y-W-w), QPointF(X-w/2, Y-W-w))
else:
painter.drawLine(QPointF(X-W/2, Y-W-w), QPointF(X+W/2, Y-W-w))

elif btnType == 2: # calf
if (pos > 0):
grad = QLinearGradient(X-W, Y, X+W, Y)
for i in ({0.0, 30.6, 40.5, 45.7, 55.7, 60.5, 70.6, 100.0} if (pos>1)
else {20.0, 45.6, 55.6, 80.0}):
grad.setColorAt(int(i)/100.0, QColor.fromHslF(hue, S, (i % 1)+E, 1))
painter.setPen(QPen(grad, w-0.5, cap=Qt.FlatCap))
painter.drawLine(QPointF(X-W/4*(pos-1)*3, Y-W-w/2), QPointF(X+W/4*(pos-1)*3, Y-W-w/2))

elif btnType == 3: # openav
painter.setPen(QPen(color, w, cap=Qt.RoundCap))
if (pos > 0):
if (pos == 1):
painter.drawRoundedRect(rectBorder(-W/2), 3, 3)
else:
painter.drawRoundedRect(rectBorder(0), 3, 3)
else:
painter.drawLine(QPointF(X-0.1, Y), QPointF(X+0.1, Y))


# do not draw marks on disabled items
if enabled == 0:
return

if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
self.fHoverStep += 1 if self.fIsHovered else -1
QTimer.singleShot(20, self.update)
match btnType:
case 1: # ball at center
self.drawMark(painter,X,Y, 0, 0, 0, w/2, color)
# case 3: # openav
# painter.setPen(QPen(color, w, cap=Qt.RoundCap))
# painter.drawLine(QPointF(X-0.1, Y), QPointF(X+0.1, Y))

else: # isEnabled()
target = QRectF(0.0, 0.0, self.fImageBaseSize, self.fImageBaseSize)
if isinstance(self.fImage, QPixmap):
painter.drawPixmap(target, self.fImage, target)
else:
self.fImage.renderer().render(painter, target)

positions = range_ + 1;

# Custom knobs (Color) # internal
if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_COLOR:
# NOTE: here all incoming color data, except hue, is lost.
hue = self.fCustomPaintColor.hueF()

createButton(10, hue, 3, positions, 1, self.normValue())

# Custom knobs
elif self.fImageId in (1, 2, 7, 8, 9, 10): # calf
hue = 0.55 # Sky

createButton(12, hue, 4, positions, 2, self.normValue())

elif self.fImageId in (11, 12, 13): # openav
hue = 0.05 # Orange

createButton(12, hue, 2.5, positions, 3, self.normValue())

else:
print("Unknown type "+ str(self.fImageId) + " button.")
return

# ---------------------------------------------------------------------------------------------------------------------

Loading…
Cancel
Save