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.

272 lines
8.7KB

  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 isnan
  7. from qt_compat import qt_config
  8. if qt_config == 5:
  9. from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QPointF, QRectF
  10. from PyQt5.QtGui import QColor, QFont, QLinearGradient, QPainter
  11. from PyQt5.QtWidgets import QDial
  12. elif qt_config == 6:
  13. from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QPointF, QRectF
  14. from PyQt6.QtGui import QColor, QFont, QLinearGradient, QPainter
  15. from PyQt6.QtWidgets import QDial
  16. # ---------------------------------------------------------------------------------------------------------------------
  17. # Widget Class
  18. # to be implemented by subclasses
  19. #def updateSizes(self):
  20. #def paintDial(self, painter):
  21. class CommonDial(QDial):
  22. # enum CustomPaintMode
  23. CUSTOM_PAINT_MODE_NULL = 0 # default (NOTE: only this mode has label gradient)
  24. CUSTOM_PAINT_MODE_CARLA_WET = 1 # color blue-green gradient (reserved #3)
  25. CUSTOM_PAINT_MODE_CARLA_VOL = 2 # color blue (reserved #3)
  26. CUSTOM_PAINT_MODE_CARLA_L = 3 # color yellow (reserved #4)
  27. CUSTOM_PAINT_MODE_CARLA_R = 4 # color yellow (reserved #4)
  28. CUSTOM_PAINT_MODE_CARLA_PAN = 5 # color yellow (reserved #3)
  29. CUSTOM_PAINT_MODE_COLOR = 6 # color, selectable (reserved #3)
  30. CUSTOM_PAINT_MODE_ZITA = 7 # custom zita knob (reserved #6)
  31. CUSTOM_PAINT_MODE_NO_GRADIENT = 8 # skip label gradient
  32. # enum Orientation
  33. HORIZONTAL = 0
  34. VERTICAL = 1
  35. HOVER_MIN = 0
  36. HOVER_MAX = 9
  37. MODE_DEFAULT = 0
  38. MODE_LINEAR = 1
  39. # signals
  40. dragStateChanged = pyqtSignal(bool)
  41. realValueChanged = pyqtSignal(float)
  42. def __init__(self, parent, index):
  43. QDial.__init__(self, parent)
  44. self.fDialMode = self.MODE_LINEAR
  45. self.fMinimum = 0.0
  46. self.fMaximum = 1.0
  47. self.fRealValue = 0.0
  48. self.fPrecision = 10000
  49. self.fIsInteger = False
  50. self.fIsHovered = False
  51. self.fIsPressed = False
  52. self.fHoverStep = self.HOVER_MIN
  53. self.fLastDragPos = None
  54. self.fLastDragValue = 0.0
  55. self.fIndex = index
  56. self.fLabel = ""
  57. self.fLabelPos = QPointF(0.0, 0.0)
  58. self.fLabelFont = QFont(self.font())
  59. self.fLabelFont.setPixelSize(8)
  60. self.fLabelWidth = 0
  61. self.fLabelHeight = 0
  62. if self.palette().window().color().lightness() > 100:
  63. # Light background
  64. c = self.palette().dark().color()
  65. self.fLabelGradientColor1 = c
  66. self.fLabelGradientColor2 = QColor(c.red(), c.green(), c.blue(), 0)
  67. self.fLabelGradientColorT = [self.palette().buttonText().color(), self.palette().mid().color()]
  68. else:
  69. # Dark background
  70. self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
  71. self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
  72. self.fLabelGradientColorT = [Qt.white, Qt.darkGray]
  73. self.fLabelGradient = QLinearGradient(0, 0, 0, 1)
  74. self.fLabelGradient.setColorAt(0.0, self.fLabelGradientColor1)
  75. self.fLabelGradient.setColorAt(0.6, self.fLabelGradientColor1)
  76. self.fLabelGradient.setColorAt(1.0, self.fLabelGradientColor2)
  77. self.fLabelGradientRect = QRectF(0.0, 0.0, 0.0, 0.0)
  78. self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_NULL
  79. self.fCustomPaintColor = QColor(0xff, 0xff, 0xff)
  80. # Fake internal value, custom precision
  81. QDial.setMinimum(self, 0)
  82. QDial.setMaximum(self, self.fPrecision)
  83. QDial.setValue(self, 0)
  84. self.valueChanged.connect(self.slot_valueChanged)
  85. def forceWhiteLabelGradientText(self):
  86. self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
  87. self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
  88. self.fLabelGradientColorT = [Qt.white, Qt.darkGray]
  89. def setLabelColor(self, enabled, disabled):
  90. self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
  91. self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
  92. self.fLabelGradientColorT = [enabled, disabled]
  93. def getIndex(self):
  94. return self.fIndex
  95. def setIndex(self, index):
  96. self.fIndex = index
  97. def setPrecision(self, value, isInteger):
  98. self.fPrecision = value
  99. self.fIsInteger = isInteger
  100. QDial.setMaximum(self, int(value))
  101. def setMinimum(self, value):
  102. self.fMinimum = value
  103. def setMaximum(self, value):
  104. self.fMaximum = value
  105. def rvalue(self):
  106. return self.fRealValue
  107. def setValue(self, value, emitSignal=False):
  108. if self.fRealValue == value or isnan(value):
  109. return
  110. if value <= self.fMinimum:
  111. qtValue = 0
  112. self.fRealValue = self.fMinimum
  113. elif value >= self.fMaximum:
  114. qtValue = int(self.fPrecision)
  115. self.fRealValue = self.fMaximum
  116. else:
  117. qtValue = round(float(value - self.fMinimum) / float(self.fMaximum - self.fMinimum) * self.fPrecision)
  118. self.fRealValue = value
  119. # Block change signal, we'll handle it ourselves
  120. self.blockSignals(True)
  121. QDial.setValue(self, qtValue)
  122. self.blockSignals(False)
  123. if emitSignal:
  124. self.realValueChanged.emit(self.fRealValue)
  125. def setCustomPaintMode(self, paintMode):
  126. if self.fCustomPaintMode == paintMode:
  127. return
  128. self.fCustomPaintMode = paintMode
  129. self.update()
  130. def setCustomPaintColor(self, color):
  131. if self.fCustomPaintColor == color:
  132. return
  133. self.fCustomPaintColor = color
  134. self.update()
  135. def setLabel(self, label):
  136. if self.fLabel == label:
  137. return
  138. self.fLabel = label
  139. self.updateSizes()
  140. self.update()
  141. @pyqtSlot(int)
  142. def slot_valueChanged(self, value):
  143. self.fRealValue = float(value)/self.fPrecision * (self.fMaximum - self.fMinimum) + self.fMinimum
  144. self.realValueChanged.emit(self.fRealValue)
  145. def enterEvent(self, event):
  146. self.fIsHovered = True
  147. if self.fHoverStep == self.HOVER_MIN:
  148. self.fHoverStep = self.HOVER_MIN + 1
  149. QDial.enterEvent(self, event)
  150. def leaveEvent(self, event):
  151. self.fIsHovered = False
  152. if self.fHoverStep == self.HOVER_MAX:
  153. self.fHoverStep = self.HOVER_MAX - 1
  154. QDial.leaveEvent(self, event)
  155. def mousePressEvent(self, event):
  156. if self.fDialMode == self.MODE_DEFAULT:
  157. QDial.mousePressEvent(self, event)
  158. return
  159. if event.button() == Qt.LeftButton:
  160. self.fIsPressed = True
  161. self.fLastDragPos = event.pos()
  162. self.fLastDragValue = self.fRealValue
  163. self.dragStateChanged.emit(True)
  164. def mouseMoveEvent(self, event):
  165. if self.fDialMode == self.MODE_DEFAULT:
  166. QDial.mouseMoveEvent(self, event)
  167. return
  168. if not self.fIsPressed:
  169. return
  170. diff = (self.fMaximum - self.fMinimum) / 4.0
  171. pos = event.pos()
  172. dx = diff * float(pos.x() - self.fLastDragPos.x()) / self.width()
  173. dy = diff * float(pos.y() - self.fLastDragPos.y()) / self.height()
  174. value = self.fLastDragValue + dx - dy
  175. if value < self.fMinimum:
  176. value = self.fMinimum
  177. elif value > self.fMaximum:
  178. value = self.fMaximum
  179. elif self.fIsInteger:
  180. value = float(round(value))
  181. self.setValue(value, True)
  182. def mouseReleaseEvent(self, event):
  183. if self.fDialMode == self.MODE_DEFAULT:
  184. QDial.mouseReleaseEvent(self, event)
  185. return
  186. if self.fIsPressed:
  187. self.fIsPressed = False
  188. self.dragStateChanged.emit(False)
  189. def paintEvent(self, event):
  190. painter = QPainter(self)
  191. event.accept()
  192. painter.save()
  193. painter.setRenderHint(QPainter.Antialiasing, True)
  194. if self.fLabel:
  195. if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
  196. painter.setPen(self.fLabelGradientColor2)
  197. painter.setBrush(self.fLabelGradient)
  198. painter.drawRect(self.fLabelGradientRect)
  199. painter.setFont(self.fLabelFont)
  200. painter.setPen(self.fLabelGradientColorT[0 if self.isEnabled() else 1])
  201. painter.drawText(self.fLabelPos, self.fLabel)
  202. self.paintDial(painter)
  203. painter.restore()
  204. def resizeEvent(self, event):
  205. QDial.resizeEvent(self, event)
  206. self.updateSizes()
  207. # ---------------------------------------------------------------------------------------------------------------------