2 # SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ---------------------------------------------------------------------------------------------------------------------
8 from math
import cos
, floor
, pi
, sin
10 from qt_compat
import qt_config
13 from PyQt5
.QtCore
import pyqtSlot
, Qt
, QEvent
, QPointF
, QRectF
, QTimer
, QSize
14 from PyQt5
.QtGui
import QColor
, QConicalGradient
, QFontMetrics
, QPainterPath
, QPen
, QPixmap
15 from PyQt5
.QtSvg
import QSvgWidget
17 from PyQt6
.QtCore
import pyqtSlot
, Qt
, QEvent
, QPointF
, QRectF
, QTimer
, QSize
18 from PyQt6
.QtGui
import QColor
, QConicalGradient
, QFontMetrics
, QPainterPath
, QPen
, QPixmap
19 from PyQt6
.QtSvgWidgets
import QSvgWidget
21 from .commondial
import CommonDial
22 from carla_shared
import fontMetricsHorizontalAdvance
24 # ---------------------------------------------------------------------------------------------------------------------
27 class ScalableDial(CommonDial
):
28 def __init__(self
, parent
, index
=0):
29 CommonDial
.__init
__(self
, parent
, index
)
31 self
.fImage
= QSvgWidget(":/scalable/dial_03.svg")
34 if self
.fImage
.sizeHint().width() > self
.fImage
.sizeHint().height():
35 self
.fImageOrientation
= self
.HORIZONTAL
37 self
.fImageOrientation
= self
.VERTICAL
41 def getBaseSize(self
):
42 return self
.fImageBaseSize
44 def updateSizes(self
):
45 if isinstance(self
.fImage
, QPixmap
):
46 self
.fImageWidth
= self
.fImage
.width()
47 self
.fImageHeight
= self
.fImage
.height()
49 self
.fImageWidth
= self
.fImage
.sizeHint().width()
50 self
.fImageHeight
= self
.fImage
.sizeHint().height()
52 if self
.fImageWidth
< 1:
55 if self
.fImageHeight
< 1:
58 if self
.fImageOrientation
== self
.HORIZONTAL
:
59 self
.fImageBaseSize
= self
.fImageHeight
60 self
.fImageLayersCount
= self
.fImageWidth
/ self
.fImageHeight
62 self
.fImageBaseSize
= self
.fImageWidth
63 self
.fImageLayersCount
= self
.fImageHeight
/ self
.fImageWidth
65 self
.setMinimumSize(self
.fImageBaseSize
, self
.fImageBaseSize
+ self
.fLabelHeight
+ 5)
66 self
.setMaximumSize(self
.fImageBaseSize
, self
.fImageBaseSize
+ self
.fLabelHeight
+ 5)
73 metrics
= QFontMetrics(self
.fLabelFont
)
74 self
.fLabelWidth
= fontMetricsHorizontalAdvance(metrics
, self
.fLabel
)
75 self
.fLabelHeight
= metrics
.height()
77 self
.fLabelPos
.setX(float(self
.fImageBaseSize
)/2.0 - float(self
.fLabelWidth
)/2.0)
79 if self
.fImageNum
in ("01", "02", "07", "08", "09", "10"):
80 self
.fLabelPos
.setY(self
.fImageBaseSize
+ self
.fLabelHeight
)
81 elif self
.fImageNum
in ("11",):
82 self
.fLabelPos
.setY(self
.fImageBaseSize
+ self
.fLabelHeight
*2/3)
84 self
.fLabelPos
.setY(self
.fImageBaseSize
+ self
.fLabelHeight
/2)
86 self
.fLabelGradient
.setStart(0, float(self
.fImageBaseSize
)/2.0)
87 self
.fLabelGradient
.setFinalStop(0, self
.fImageBaseSize
+ self
.fLabelHeight
+ 5)
89 self
.fLabelGradientRect
= QRectF(float(self
.fImageBaseSize
)/8.0, float(self
.fImageBaseSize
)/2.0,
90 float(self
.fImageBaseSize
*3)/4.0, self
.fImageBaseSize
+self
.fLabelHeight
+5)
92 def setImage(self
, imageId
):
93 self
.fImageNum
= "%02i" % imageId
94 if imageId
in (2,6,7,8,9,10,11,12,13):
95 img
= ":/bitmaps/dial_%s%s.png" % (self
.fImageNum
, "" if self
.isEnabled() else "d")
97 img
= ":/scalable/dial_%s%s.svg" % (self
.fImageNum
, "" if self
.isEnabled() else "d")
99 if img
.endswith(".png"):
100 if not isinstance(self
.fImage
, QPixmap
):
101 self
.fImage
= QPixmap()
103 if not isinstance(self
.fImage
, QSvgWidget
):
104 self
.fImage
= QSvgWidget()
106 self
.fImage
.load(img
)
108 if self
.fImage
.width() > self
.fImage
.height():
109 self
.fImageOrientation
= self
.HORIZONTAL
111 self
.fImageOrientation
= self
.VERTICAL
114 if self
.fCustomPaintMode
== self
.CUSTOM_PAINT_MODE_NULL
:
115 # reserved for carla-wet, carla-vol, carla-pan and color
116 if self
.fImageNum
== "03":
117 self
.fCustomPaintMode
= self
.CUSTOM_PAINT_MODE_COLOR
119 # reserved for carla-L and carla-R
120 elif self
.fImageNum
== "04":
121 self
.fCustomPaintMode
= self
.CUSTOM_PAINT_MODE_CARLA_L
124 elif self
.fImageNum
== "06":
125 self
.fCustomPaintMode
= self
.CUSTOM_PAINT_MODE_ZITA
131 def slot_updateImage(self
):
132 self
.setImage(int(self
.fImageNum
))
134 def minimumSizeHint(self
):
135 return QSize(self
.fImageBaseSize
, self
.fImageBaseSize
)
138 return QSize(self
.fImageBaseSize
, self
.fImageBaseSize
)
140 def changeEvent(self
, event
):
141 CommonDial
.changeEvent(self
, event
)
143 # Force svg update if enabled state changes
144 if event
.type() == QEvent
.EnabledChange
:
145 self
.slot_updateImage()
147 def paintDial(self
, painter
):
149 normValue
= float(self
.fRealValue
- self
.fMinimum
) / float(self
.fMaximum
- self
.fMinimum
)
150 curLayer
= int((self
.fImageLayersCount
- 1) * normValue
)
152 if self
.fImageOrientation
== self
.HORIZONTAL
:
153 xpos
= self
.fImageBaseSize
* curLayer
157 ypos
= self
.fImageBaseSize
* curLayer
159 source
= QRectF(xpos
, ypos
, self
.fImageBaseSize
, self
.fImageBaseSize
)
161 if isinstance(self
.fImage
, QPixmap
):
162 target
= QRectF(0.0, 0.0, self
.fImageBaseSize
, self
.fImageBaseSize
)
163 painter
.drawPixmap(target
, self
.fImage
, source
)
165 self
.fImage
.renderer().render(painter
, source
)
167 # Custom knobs (Dry/Wet and Volume)
168 if self
.fCustomPaintMode
in (self
.CUSTOM_PAINT_MODE_CARLA_WET
, self
.CUSTOM_PAINT_MODE_CARLA_VOL
):
170 colorGreen
= QColor(0x5D, 0xE7, 0x3D).lighter(100 + self
.fHoverStep
*6)
171 colorBlue
= QColor(0x3E, 0xB8, 0xBE).lighter(100 + self
.fHoverStep
*6)
174 ballRect
= QRectF(8.0, 8.0, 15.0, 15.0)
175 ballPath
= QPainterPath()
176 ballPath
.addEllipse(ballRect
)
177 #painter.drawRect(ballRect)
178 tmpValue
= (0.375 + 0.75*normValue
)
179 ballValue
= tmpValue
- floor(tmpValue
)
180 ballPoint
= ballPath
.pointAtPercent(ballValue
)
184 spanAngle
= -255*16*normValue
186 if self
.fCustomPaintMode
== self
.CUSTOM_PAINT_MODE_CARLA_WET
:
187 painter
.setBrush(colorBlue
)
188 painter
.setPen(QPen(colorBlue
, 0))
189 painter
.drawEllipse(QRectF(ballPoint
.x(), ballPoint
.y(), 2.2, 2.2))
191 gradient
= QConicalGradient(15.5, 15.5, -45)
192 gradient
.setColorAt(0.0, colorBlue
)
193 gradient
.setColorAt(0.125, colorBlue
)
194 gradient
.setColorAt(0.625, colorGreen
)
195 gradient
.setColorAt(0.75, colorGreen
)
196 gradient
.setColorAt(0.76, colorGreen
)
197 gradient
.setColorAt(1.0, colorGreen
)
198 painter
.setBrush(gradient
)
199 painter
.setPen(QPen(gradient
, 3))
202 painter
.setBrush(colorBlue
)
203 painter
.setPen(QPen(colorBlue
, 0))
204 painter
.drawEllipse(QRectF(ballPoint
.x(), ballPoint
.y(), 2.2, 2.2))
206 painter
.setBrush(colorBlue
)
207 painter
.setPen(QPen(colorBlue
, 3))
209 painter
.drawArc(QRectF(4.0, 4.0, 26.0, 26.0), int(startAngle
), int(spanAngle
))
211 # Custom knobs (L and R)
212 elif self
.fCustomPaintMode
in (self
.CUSTOM_PAINT_MODE_CARLA_L
, self
.CUSTOM_PAINT_MODE_CARLA_R
):
214 color
= QColor(0xAD, 0xD5, 0x48).lighter(100 + self
.fHoverStep
*6)
217 ballRect
= QRectF(7.0, 8.0, 11.0, 12.0)
218 ballPath
= QPainterPath()
219 ballPath
.addEllipse(ballRect
)
220 #painter.drawRect(ballRect)
221 tmpValue
= (0.375 + 0.75*normValue
)
222 ballValue
= tmpValue
- floor(tmpValue
)
223 ballPoint
= ballPath
.pointAtPercent(ballValue
)
225 painter
.setBrush(color
)
226 painter
.setPen(QPen(color
, 0))
227 painter
.drawEllipse(QRectF(ballPoint
.x(), ballPoint
.y(), 2.0, 2.0))
230 if self
.fCustomPaintMode
== self
.CUSTOM_PAINT_MODE_CARLA_L
:
232 spanAngle
= -255*16*normValue
234 startAngle
= 322.0*16
235 spanAngle
= 255.0*16*(1.0-normValue
)
237 painter
.setPen(QPen(color
, 2.5))
238 painter
.drawArc(QRectF(3.5, 3.5, 22.0, 22.0), int(startAngle
), int(spanAngle
))
240 # Custom knobs (Color)
241 elif self
.fCustomPaintMode
== self
.CUSTOM_PAINT_MODE_COLOR
:
243 color
= self
.fCustomPaintColor
.lighter(100 + self
.fHoverStep
*6)
246 ballRect
= QRectF(8.0, 8.0, 15.0, 15.0)
247 ballPath
= QPainterPath()
248 ballPath
.addEllipse(ballRect
)
249 tmpValue
= (0.375 + 0.75*normValue
)
250 ballValue
= tmpValue
- floor(tmpValue
)
251 ballPoint
= ballPath
.pointAtPercent(ballValue
)
255 spanAngle
= -255*16*normValue
257 painter
.setBrush(color
)
258 painter
.setPen(QPen(color
, 0))
259 painter
.drawEllipse(QRectF(ballPoint
.x(), ballPoint
.y(), 2.2, 2.2))
261 painter
.setBrush(color
)
262 painter
.setPen(QPen(color
, 3))
263 painter
.drawArc(QRectF(4.0, 4.8, 26.0, 26.0), int(startAngle
), int(spanAngle
))
265 # Custom knobs (Zita)
266 elif self
.fCustomPaintMode
== self
.CUSTOM_PAINT_MODE_ZITA
:
267 a
= normValue
* pi
* 1.5 - 2.35
273 painter
.setBrush(Qt
.black
)
274 painter
.setPen(QPen(Qt
.black
, 2))
275 painter
.drawLine(QPointF(11.0, 11.0), QPointF(x
, y
))
281 if self
.HOVER_MIN
< self
.fHoverStep
< self
.HOVER_MAX
:
282 self
.fHoverStep
+= 1 if self
.fIsHovered
else -1
283 QTimer
.singleShot(20, self
.update
)
286 target
= QRectF(0.0, 0.0, self
.fImageBaseSize
, self
.fImageBaseSize
)
287 if isinstance(self
.fImage
, QPixmap
):
288 painter
.drawPixmap(target
, self
.fImage
, target
)
290 self
.fImage
.renderer().render(painter
, target
)
292 # ---------------------------------------------------------------------------------------------------------------------