Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
11KB

  1. #!/usr/bin/env python3
  2. # SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
  3. # SPDX-License-Identifier: GPL-2.0-or-later
  4. # ---------------------------------------------------------------------------------------------------------------------
  5. # Imports (Global)
  6. from math import cos, floor, pi, sin
  7. from qt_compat import qt_config
  8. if qt_config == 5:
  9. from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize
  10. from PyQt5.QtGui import QColor, QConicalGradient, QFontMetrics, QPainterPath, QPen, QPixmap
  11. from PyQt5.QtWidgets import QDial
  12. elif qt_config == 6:
  13. from PyQt6.QtCore import pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize
  14. from PyQt6.QtGui import QColor, QConicalGradient, QFontMetrics, QPainterPath, QPen, QPixmap
  15. from PyQt6.QtWidgets import QDial
  16. from .commondial import CommonDial
  17. from carla_shared import fontMetricsHorizontalAdvance
  18. # ---------------------------------------------------------------------------------------------------------------------
  19. # Widget Class
  20. class PixmapDial(CommonDial):
  21. def __init__(self, parent, index=0):
  22. CommonDial.__init__(self, parent, index)
  23. self.fPixmap = QPixmap(":/bitmaps/dial_01d.png")
  24. self.fPixmapNum = "01"
  25. if self.fPixmap.width() > self.fPixmap.height():
  26. self.fPixmapOrientation = self.HORIZONTAL
  27. else:
  28. self.fPixmapOrientation = self.VERTICAL
  29. self.updateSizes()
  30. def getBaseSize(self):
  31. return self.fPixmapBaseSize
  32. def updateSizes(self):
  33. self.fPixmapWidth = self.fPixmap.width()
  34. self.fPixmapHeight = self.fPixmap.height()
  35. if self.fPixmapWidth < 1:
  36. self.fPixmapWidth = 1
  37. if self.fPixmapHeight < 1:
  38. self.fPixmapHeight = 1
  39. if self.fPixmapOrientation == self.HORIZONTAL:
  40. self.fPixmapBaseSize = self.fPixmapHeight
  41. self.fPixmapLayersCount = self.fPixmapWidth / self.fPixmapHeight
  42. else:
  43. self.fPixmapBaseSize = self.fPixmapWidth
  44. self.fPixmapLayersCount = self.fPixmapHeight / self.fPixmapWidth
  45. self.setMinimumSize(self.fPixmapBaseSize, self.fPixmapBaseSize + self.fLabelHeight + 5)
  46. self.setMaximumSize(self.fPixmapBaseSize, self.fPixmapBaseSize + self.fLabelHeight + 5)
  47. if not self.fLabel:
  48. self.fLabelHeight = 0
  49. self.fLabelWidth = 0
  50. return
  51. metrics = QFontMetrics(self.fLabelFont)
  52. self.fLabelWidth = fontMetricsHorizontalAdvance(metrics, self.fLabel)
  53. self.fLabelHeight = metrics.height()
  54. self.fLabelPos.setX(float(self.fPixmapBaseSize)/2.0 - float(self.fLabelWidth)/2.0)
  55. if self.fPixmapNum in ("01", "02", "07", "08", "09", "10"):
  56. self.fLabelPos.setY(self.fPixmapBaseSize + self.fLabelHeight)
  57. elif self.fPixmapNum in ("11",):
  58. self.fLabelPos.setY(self.fPixmapBaseSize + self.fLabelHeight*2/3)
  59. else:
  60. self.fLabelPos.setY(self.fPixmapBaseSize + self.fLabelHeight/2)
  61. self.fLabelGradient.setStart(0, float(self.fPixmapBaseSize)/2.0)
  62. self.fLabelGradient.setFinalStop(0, self.fPixmapBaseSize + self.fLabelHeight + 5)
  63. self.fLabelGradientRect = QRectF(float(self.fPixmapBaseSize)/8.0, float(self.fPixmapBaseSize)/2.0, float(self.fPixmapBaseSize*3)/4.0, self.fPixmapBaseSize+self.fLabelHeight+5)
  64. def setPixmap(self, pixmapId):
  65. self.fPixmapNum = "%02i" % pixmapId
  66. self.fPixmap.load(":/bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if self.isEnabled() else "d"))
  67. if self.fPixmap.width() > self.fPixmap.height():
  68. self.fPixmapOrientation = self.HORIZONTAL
  69. else:
  70. self.fPixmapOrientation = self.VERTICAL
  71. # special pixmaps
  72. if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
  73. # reserved for carla-wet, carla-vol, carla-pan and color
  74. if self.fPixmapNum == "03":
  75. self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_COLOR
  76. # reserved for carla-L and carla-R
  77. elif self.fPixmapNum == "04":
  78. self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_CARLA_L
  79. # reserved for zita
  80. elif self.fPixmapNum == "06":
  81. self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_ZITA
  82. self.updateSizes()
  83. self.update()
  84. @pyqtSlot()
  85. def slot_updatePixmap(self):
  86. self.setPixmap(int(self.fPixmapNum))
  87. def minimumSizeHint(self):
  88. return QSize(self.fPixmapBaseSize, self.fPixmapBaseSize)
  89. def sizeHint(self):
  90. return QSize(self.fPixmapBaseSize, self.fPixmapBaseSize)
  91. def changeEvent(self, event):
  92. CommonDial.changeEvent(self, event)
  93. # Force pixmap update if enabled state changes
  94. if event.type() == QEvent.EnabledChange:
  95. self.setPixmap(int(self.fPixmapNum))
  96. def paintDial(self, painter):
  97. if self.isEnabled():
  98. normValue = float(self.fRealValue - self.fMinimum) / float(self.fMaximum - self.fMinimum)
  99. target = QRectF(0.0, 0.0, self.fPixmapBaseSize, self.fPixmapBaseSize)
  100. curLayer = int((self.fPixmapLayersCount - 1) * normValue)
  101. if self.fPixmapOrientation == self.HORIZONTAL:
  102. xpos = self.fPixmapBaseSize * curLayer
  103. ypos = 0.0
  104. else:
  105. xpos = 0.0
  106. ypos = self.fPixmapBaseSize * curLayer
  107. source = QRectF(xpos, ypos, self.fPixmapBaseSize, self.fPixmapBaseSize)
  108. painter.drawPixmap(target, self.fPixmap, source)
  109. # Custom knobs (Dry/Wet and Volume)
  110. if self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_WET, self.CUSTOM_PAINT_MODE_CARLA_VOL):
  111. # knob color
  112. colorGreen = QColor(0x5D, 0xE7, 0x3D).lighter(100 + self.fHoverStep*6)
  113. colorBlue = QColor(0x3E, 0xB8, 0xBE).lighter(100 + self.fHoverStep*6)
  114. # draw small circle
  115. ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
  116. ballPath = QPainterPath()
  117. ballPath.addEllipse(ballRect)
  118. #painter.drawRect(ballRect)
  119. tmpValue = (0.375 + 0.75*normValue)
  120. ballValue = tmpValue - floor(tmpValue)
  121. ballPoint = ballPath.pointAtPercent(ballValue)
  122. # draw arc
  123. startAngle = 216*16
  124. spanAngle = -252*16*normValue
  125. if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_WET:
  126. painter.setBrush(colorBlue)
  127. painter.setPen(QPen(colorBlue, 0))
  128. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  129. gradient = QConicalGradient(15.5, 15.5, -45)
  130. gradient.setColorAt(0.0, colorBlue)
  131. gradient.setColorAt(0.125, colorBlue)
  132. gradient.setColorAt(0.625, colorGreen)
  133. gradient.setColorAt(0.75, colorGreen)
  134. gradient.setColorAt(0.76, colorGreen)
  135. gradient.setColorAt(1.0, colorGreen)
  136. painter.setBrush(gradient)
  137. painter.setPen(QPen(gradient, 3))
  138. else:
  139. painter.setBrush(colorBlue)
  140. painter.setPen(QPen(colorBlue, 0))
  141. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  142. painter.setBrush(colorBlue)
  143. painter.setPen(QPen(colorBlue, 3))
  144. painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)
  145. # Custom knobs (L and R)
  146. elif self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_L, self.CUSTOM_PAINT_MODE_CARLA_R):
  147. # knob color
  148. color = QColor(0xAD, 0xD5, 0x48).lighter(100 + self.fHoverStep*6)
  149. # draw small circle
  150. ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
  151. ballPath = QPainterPath()
  152. ballPath.addEllipse(ballRect)
  153. #painter.drawRect(ballRect)
  154. tmpValue = (0.375 + 0.75*normValue)
  155. ballValue = tmpValue - floor(tmpValue)
  156. ballPoint = ballPath.pointAtPercent(ballValue)
  157. painter.setBrush(color)
  158. painter.setPen(QPen(color, 0))
  159. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0))
  160. # draw arc
  161. if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_L:
  162. startAngle = 216*16
  163. spanAngle = -252.0*16*normValue
  164. else:
  165. startAngle = 324.0*16
  166. spanAngle = 252.0*16*(1.0-normValue)
  167. painter.setPen(QPen(color, 2))
  168. painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle)
  169. # Custom knobs (Color)
  170. elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_COLOR:
  171. # knob color
  172. color = self.fCustomPaintColor.lighter(100 + self.fHoverStep*6)
  173. # draw small circle
  174. ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
  175. ballPath = QPainterPath()
  176. ballPath.addEllipse(ballRect)
  177. tmpValue = (0.375 + 0.75*normValue)
  178. ballValue = tmpValue - floor(tmpValue)
  179. ballPoint = ballPath.pointAtPercent(ballValue)
  180. # draw arc
  181. startAngle = 216*16
  182. spanAngle = -252*16*normValue
  183. painter.setBrush(color)
  184. painter.setPen(QPen(color, 0))
  185. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  186. painter.setBrush(color)
  187. painter.setPen(QPen(color, 3))
  188. painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)
  189. # Custom knobs (Zita)
  190. elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_ZITA:
  191. a = normValue * pi * 1.5 - 2.35
  192. r = 10.0
  193. x = 10.5
  194. y = 10.5
  195. x += r * sin(a)
  196. y -= r * cos(a)
  197. painter.setBrush(Qt.black)
  198. painter.setPen(QPen(Qt.black, 2))
  199. painter.drawLine(QPointF(11.0, 11.0), QPointF(x, y))
  200. # Custom knobs
  201. else:
  202. painter.restore()
  203. return
  204. if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
  205. self.fHoverStep += 1 if self.fIsHovered else -1
  206. QTimer.singleShot(20, self.update)
  207. else: # isEnabled()
  208. target = QRectF(0.0, 0.0, self.fPixmapBaseSize, self.fPixmapBaseSize)
  209. painter.drawPixmap(target, self.fPixmap, target)
  210. # ---------------------------------------------------------------------------------------------------------------------