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.

284 lines
10KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Pixmap Dial, a custom Qt4 widget
  4. # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. from math import floor
  20. from PyQt4.QtCore import Qt, QPointF, QRectF, QTimer, QSize, SLOT
  21. from PyQt4.QtGui import QColor, QConicalGradient, QDial, QFontMetrics, QLinearGradient, QPainter, QPainterPath, QPen, QPixmap
  22. # ------------------------------------------------------------------------------------------------------------
  23. # Widget Class
  24. class PixmapDial(QDial):
  25. # enum Orientation
  26. HORIZONTAL = 0
  27. VERTICAL = 1
  28. # enum CustomPaint
  29. CUSTOM_PAINT_NULL = 0
  30. CUSTOM_PAINT_CARLA_WET = 1
  31. CUSTOM_PAINT_CARLA_VOL = 2
  32. CUSTOM_PAINT_CARLA_L = 3
  33. CUSTOM_PAINT_CARLA_R = 4
  34. HOVER_MIN = 0
  35. HOVER_MAX = 9
  36. def __init__(self, parent):
  37. QDial.__init__(self, parent)
  38. self.m_pixmap = QPixmap(":/bitmaps/dial_01d.png")
  39. self.m_pixmapNum = "01"
  40. self.m_customPaint = self.CUSTOM_PAINT_NULL
  41. self.m_hovered = False
  42. self.m_hoverStep = self.HOVER_MIN
  43. if self.m_pixmap.width() > self.m_pixmap.height():
  44. self.m_orientation = self.HORIZONTAL
  45. else:
  46. self.m_orientation = self.VERTICAL
  47. self.m_label = ""
  48. self.m_labelPos = QPointF(0.0, 0.0)
  49. self.m_labelWidth = 0
  50. self.m_labelHeight = 0
  51. self.m_labelGradient = QLinearGradient(0, 0, 0, 1)
  52. if self.palette().window().color().lightness() > 100:
  53. # Light background
  54. c = self.palette().dark().color()
  55. self.m_color1 = c
  56. self.m_color2 = QColor(c.red(), c.green(), c.blue(), 0)
  57. self.m_colorT = [self.palette().buttonText().color(), self.palette().mid().color()]
  58. else:
  59. # Dark background
  60. self.m_color1 = QColor(0, 0, 0, 255)
  61. self.m_color2 = QColor(0, 0, 0, 0)
  62. self.m_colorT = [Qt.white, Qt.darkGray]
  63. self.updateSizes()
  64. def getSize(self):
  65. return self.p_size
  66. def setCustomPaint(self, paint):
  67. self.m_customPaint = paint
  68. self.update()
  69. def setEnabled(self, enabled):
  70. if self.isEnabled() != enabled:
  71. self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmapNum, "" if enabled else "d"))
  72. self.updateSizes()
  73. self.update()
  74. QDial.setEnabled(self, enabled)
  75. def setLabel(self, label):
  76. self.m_label = label
  77. self.m_labelWidth = QFontMetrics(self.font()).width(label)
  78. self.m_labelHeight = QFontMetrics(self.font()).height()
  79. self.m_labelPos.setX(float(self.p_size)/2 - float(self.m_labelWidth)/2)
  80. self.m_labelPos.setY(self.p_size + self.m_labelHeight)
  81. self.m_labelGradient.setColorAt(0.0, self.m_color1)
  82. self.m_labelGradient.setColorAt(0.6, self.m_color1)
  83. self.m_labelGradient.setColorAt(1.0, self.m_color2)
  84. self.m_labelGradient.setStart(0, float(self.p_size)/2)
  85. self.m_labelGradient.setFinalStop(0, self.p_size + self.m_labelHeight + 5)
  86. self.m_labelGradient_rect = QRectF(float(self.p_size)/8, float(self.p_size)/2, float(self.p_size)*6/8, self.p_size+self.m_labelHeight+5)
  87. self.update()
  88. def setPixmap(self, pixmapId):
  89. self.m_pixmapNum = "%02i" % pixmapId
  90. self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmapNum, "" if self.isEnabled() else "d"))
  91. if self.m_pixmap.width() > self.m_pixmap.height():
  92. self.m_orientation = self.HORIZONTAL
  93. else:
  94. self.m_orientation = self.VERTICAL
  95. self.updateSizes()
  96. self.update()
  97. def minimumSizeHint(self):
  98. return QSize(self.p_size, self.p_size)
  99. def sizeHint(self):
  100. return QSize(self.p_size, self.p_size)
  101. def updateSizes(self):
  102. self.p_width = self.m_pixmap.width()
  103. self.p_height = self.m_pixmap.height()
  104. if self.p_width < 1:
  105. self.p_width = 1
  106. if self.p_height < 1:
  107. self.p_height = 1
  108. if self.m_orientation == self.HORIZONTAL:
  109. self.p_size = self.p_height
  110. self.p_count = self.p_width / self.p_height
  111. else:
  112. self.p_size = self.p_width
  113. self.p_count = self.p_height / self.p_width
  114. self.setMinimumSize(self.p_size, self.p_size + self.m_labelHeight + 5)
  115. self.setMaximumSize(self.p_size, self.p_size + self.m_labelHeight + 5)
  116. def enterEvent(self, event):
  117. self.m_hovered = True
  118. if self.m_hoverStep == self.HOVER_MIN:
  119. self.m_hoverStep += 1
  120. QDial.enterEvent(self, event)
  121. def leaveEvent(self, event):
  122. self.m_hovered = False
  123. if self.m_hoverStep == self.HOVER_MAX:
  124. self.m_hoverStep -= 1
  125. QDial.leaveEvent(self, event)
  126. def paintEvent(self, event):
  127. painter = QPainter(self)
  128. painter.setRenderHint(QPainter.Antialiasing, True)
  129. if self.m_label:
  130. painter.setPen(self.m_color2)
  131. painter.setBrush(self.m_labelGradient)
  132. painter.drawRect(self.m_labelGradient_rect)
  133. painter.setPen(self.m_colorT[0 if self.isEnabled() else 1])
  134. painter.drawText(self.m_labelPos, self.m_label)
  135. if self.isEnabled():
  136. current = float(self.value() - self.minimum())
  137. divider = float(self.maximum() - self.minimum())
  138. if divider == 0.0:
  139. return
  140. value = current / divider
  141. target = QRectF(0.0, 0.0, self.p_size, self.p_size)
  142. per = int((self.p_count - 1) * value)
  143. if self.m_orientation == self.HORIZONTAL:
  144. xpos = self.p_size * per
  145. ypos = 0.0
  146. else:
  147. xpos = 0.0
  148. ypos = self.p_size * per
  149. source = QRectF(xpos, ypos, self.p_size, self.p_size)
  150. painter.drawPixmap(target, self.m_pixmap, source)
  151. # Custom knobs (Dry/Wet and Volume)
  152. if self.m_customPaint in (self.CUSTOM_PAINT_CARLA_WET, self.CUSTOM_PAINT_CARLA_VOL):
  153. # knob color
  154. colorGreen = QColor(0x5D, 0xE7, 0x3D, 191 + self.m_hoverStep*7)
  155. colorBlue = QColor(0x3E, 0xB8, 0xBE, 191 + self.m_hoverStep*7)
  156. # draw small circle
  157. ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
  158. ballPath = QPainterPath()
  159. ballPath.addEllipse(ballRect)
  160. #painter.drawRect(ballRect)
  161. tmpValue = (0.375 + 0.75*value)
  162. ballValue = tmpValue - floor(tmpValue)
  163. ballPoint = ballPath.pointAtPercent(ballValue)
  164. # draw arc
  165. startAngle = 216*16
  166. spanAngle = -252*16*value
  167. if self.m_customPaint == self.CUSTOM_PAINT_CARLA_WET:
  168. painter.setBrush(colorBlue)
  169. painter.setPen(QPen(colorBlue, 0))
  170. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  171. gradient = QConicalGradient(15.5, 15.5, -45)
  172. gradient.setColorAt(0.0, colorBlue)
  173. gradient.setColorAt(0.125, colorBlue)
  174. gradient.setColorAt(0.625, colorGreen)
  175. gradient.setColorAt(0.75, colorGreen)
  176. gradient.setColorAt(0.76, colorGreen)
  177. gradient.setColorAt(1.0, colorGreen)
  178. painter.setBrush(gradient)
  179. painter.setPen(QPen(gradient, 3))
  180. else:
  181. painter.setBrush(colorBlue)
  182. painter.setPen(QPen(colorBlue, 0))
  183. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  184. painter.setBrush(colorBlue)
  185. painter.setPen(QPen(colorBlue, 3))
  186. painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)
  187. # Custom knobs (L and R)
  188. elif self.m_customPaint in (self.CUSTOM_PAINT_CARLA_L, self.CUSTOM_PAINT_CARLA_R):
  189. # knob color
  190. color = QColor(0xAD + self.m_hoverStep*5, 0xD5 + self.m_hoverStep*4, 0x4B + self.m_hoverStep*5)
  191. # draw small circle
  192. ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
  193. ballPath = QPainterPath()
  194. ballPath.addEllipse(ballRect)
  195. #painter.drawRect(ballRect)
  196. tmpValue = (0.375 + 0.75*value)
  197. ballValue = tmpValue - floor(tmpValue)
  198. ballPoint = ballPath.pointAtPercent(ballValue)
  199. painter.setBrush(color)
  200. painter.setPen(QPen(color, 0))
  201. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0))
  202. # draw arc
  203. if self.m_customPaint == self.CUSTOM_PAINT_CARLA_L:
  204. startAngle = 216*16
  205. spanAngle = -252.0*16*value
  206. elif self.m_customPaint == self.CUSTOM_PAINT_CARLA_R:
  207. startAngle = 324.0*16
  208. spanAngle = 252.0*16*(1.0-value)
  209. else:
  210. return
  211. painter.setPen(QPen(color, 2))
  212. painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle)
  213. if self.HOVER_MIN < self.m_hoverStep < self.HOVER_MAX:
  214. self.m_hoverStep += 1 if self.m_hovered else -1
  215. QTimer.singleShot(20, self, SLOT("update()"))
  216. else:
  217. target = QRectF(0.0, 0.0, self.p_size, self.p_size)
  218. painter.drawPixmap(target, self.m_pixmap, target)
  219. event.accept()
  220. def resizeEvent(self, event):
  221. self.updateSizes()
  222. QDial.resizeEvent(self, event)