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.

320 lines
11KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Pixmap Dial, a custom Qt4 widget
  4. # Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or 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 doc/GPL.txt file.
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. from PyQt4.QtCore import Qt, QPointF, QRectF, QTimer, QSize
  20. from PyQt4.QtGui import QColor, QConicalGradient, QFont, QFontMetrics
  21. from PyQt4.QtGui import QDial, QLinearGradient, QPainter, QPainterPath, QPen, QPixmap
  22. from math import cos, floor, pi, sin
  23. # ------------------------------------------------------------------------------------------------------------
  24. # Widget Class
  25. class PixmapDial(QDial):
  26. # enum CustomPaint
  27. CUSTOM_PAINT_NULL = 0
  28. CUSTOM_PAINT_CARLA_WET = 1
  29. CUSTOM_PAINT_CARLA_VOL = 2
  30. CUSTOM_PAINT_CARLA_L = 3
  31. CUSTOM_PAINT_CARLA_R = 4
  32. CUSTOM_PAINT_ZITA = 5
  33. CUSTOM_PAINT_NO_GRADIENT = 6
  34. # enum Orientation
  35. HORIZONTAL = 0
  36. VERTICAL = 1
  37. HOVER_MIN = 0
  38. HOVER_MAX = 9
  39. def __init__(self, parent, index=0):
  40. QDial.__init__(self, parent)
  41. self.fIndex = index
  42. self.fPixmap = QPixmap(":/bitmaps/dial_01d.png")
  43. self.fPixmapNum = "01"
  44. self.fCustomPaint = self.CUSTOM_PAINT_NULL
  45. self.fIsHovered = False
  46. self.fHoverStep = self.HOVER_MIN
  47. if self.fPixmap.width() > self.fPixmap.height():
  48. self.fOrientation = self.HORIZONTAL
  49. else:
  50. self.fOrientation = self.VERTICAL
  51. self.fLabel = ""
  52. self.fLabelPos = QPointF(0.0, 0.0)
  53. self.fLabelFont = QFont()
  54. self.fLabelFont.setPointSize(6)
  55. self.fLabelWidth = 0
  56. self.fLabelHeight = 0
  57. self.fLabelGradient = QLinearGradient(0, 0, 0, 1)
  58. if self.palette().window().color().lightness() > 100:
  59. # Light background
  60. c = self.palette().dark().color()
  61. self.fColor1 = c
  62. self.fColor2 = QColor(c.red(), c.green(), c.blue(), 0)
  63. self.fColorT = [self.palette().buttonText().color(), self.palette().mid().color()]
  64. else:
  65. # Dark background
  66. self.fColor1 = QColor(0, 0, 0, 255)
  67. self.fColor2 = QColor(0, 0, 0, 0)
  68. self.fColorT = [Qt.white, Qt.darkGray]
  69. self.updateSizes()
  70. def getIndex(self):
  71. return self.fIndex
  72. def getSize(self):
  73. return self.fSize
  74. def setCustomPaint(self, paint):
  75. self.fCustomPaint = paint
  76. self.fLabelPos.setY(self.fSize + self.fLabelHeight/2)
  77. self.update()
  78. def setEnabled(self, enabled):
  79. if self.isEnabled() != enabled:
  80. self.fPixmap.load(":/bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if enabled else "d"))
  81. self.updateSizes()
  82. self.update()
  83. QDial.setEnabled(self, enabled)
  84. def setIndex(self, index):
  85. self.fIndex = index
  86. def setLabel(self, label):
  87. self.fLabel = label
  88. self.fLabelWidth = QFontMetrics(self.fLabelFont).width(label)
  89. self.fLabelHeight = QFontMetrics(self.fLabelFont).height()
  90. self.fLabelPos.setX(float(self.fSize)/2.0 - float(self.fLabelWidth)/2.0)
  91. self.fLabelPos.setY(self.fSize + self.fLabelHeight)
  92. self.fLabelGradient.setColorAt(0.0, self.fColor1)
  93. self.fLabelGradient.setColorAt(0.6, self.fColor1)
  94. self.fLabelGradient.setColorAt(1.0, self.fColor2)
  95. self.fLabelGradient.setStart(0, float(self.fSize)/2.0)
  96. self.fLabelGradient.setFinalStop(0, self.fSize + self.fLabelHeight + 5)
  97. self.fLabelGradientRect = QRectF(float(self.fSize)/8.0, float(self.fSize)/2.0, float(self.fSize*6)/8.0, self.fSize+self.fLabelHeight+5)
  98. self.update()
  99. def setPixmap(self, pixmapId):
  100. self.fPixmapNum = "%02i" % pixmapId
  101. self.fPixmap.load(":/bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if self.isEnabled() else "d"))
  102. if self.fPixmap.width() > self.fPixmap.height():
  103. self.fOrientation = self.HORIZONTAL
  104. else:
  105. self.fOrientation = self.VERTICAL
  106. self.updateSizes()
  107. self.update()
  108. def minimumSizeHint(self):
  109. return QSize(self.fSize, self.fSize)
  110. def sizeHint(self):
  111. return QSize(self.fSize, self.fSize)
  112. def updateSizes(self):
  113. self.fWidth = self.fPixmap.width()
  114. self.fHeight = self.fPixmap.height()
  115. if self.fWidth < 1:
  116. self.fWidth = 1
  117. if self.fHeight < 1:
  118. self.fHeight = 1
  119. if self.fOrientation == self.HORIZONTAL:
  120. self.fSize = self.fHeight
  121. self.fCount = self.fWidth / self.fHeight
  122. else:
  123. self.fSize = self.fWidth
  124. self.fCount = self.fHeight / self.fWidth
  125. self.setMinimumSize(self.fSize, self.fSize + self.fLabelHeight + 5)
  126. self.setMaximumSize(self.fSize, self.fSize + self.fLabelHeight + 5)
  127. def enterEvent(self, event):
  128. self.fIsHovered = True
  129. if self.fHoverStep == self.HOVER_MIN:
  130. self.fHoverStep = self.HOVER_MIN + 1
  131. QDial.enterEvent(self, event)
  132. def leaveEvent(self, event):
  133. self.fIsHovered = False
  134. if self.fHoverStep == self.HOVER_MAX:
  135. self.fHoverStep = self.HOVER_MAX - 1
  136. QDial.leaveEvent(self, event)
  137. def paintEvent(self, event):
  138. painter = QPainter(self)
  139. event.accept()
  140. painter.save()
  141. painter.setRenderHint(QPainter.Antialiasing, True)
  142. if self.fLabel:
  143. if self.fCustomPaint == self.CUSTOM_PAINT_NULL:
  144. painter.setPen(self.fColor2)
  145. painter.setBrush(self.fLabelGradient)
  146. painter.drawRect(self.fLabelGradientRect)
  147. painter.setFont(self.fLabelFont)
  148. painter.setPen(self.fColorT[0 if self.isEnabled() else 1])
  149. painter.drawText(self.fLabelPos, self.fLabel)
  150. if self.isEnabled():
  151. current = float(self.value() - self.minimum())
  152. divider = float(self.maximum() - self.minimum())
  153. if divider == 0.0:
  154. return
  155. value = current / divider
  156. target = QRectF(0.0, 0.0, self.fSize, self.fSize)
  157. per = int((self.fCount - 1) * value)
  158. if self.fOrientation == self.HORIZONTAL:
  159. xpos = self.fSize * per
  160. ypos = 0.0
  161. else:
  162. xpos = 0.0
  163. ypos = self.fSize * per
  164. source = QRectF(xpos, ypos, self.fSize, self.fSize)
  165. painter.drawPixmap(target, self.fPixmap, source)
  166. # Custom knobs (Dry/Wet and Volume)
  167. if self.fCustomPaint in (self.CUSTOM_PAINT_CARLA_WET, self.CUSTOM_PAINT_CARLA_VOL):
  168. # knob color
  169. colorGreen = QColor(0x5D, 0xE7, 0x3D, 191 + self.fHoverStep*7)
  170. colorBlue = QColor(0x3E, 0xB8, 0xBE, 191 + self.fHoverStep*7)
  171. # draw small circle
  172. ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
  173. ballPath = QPainterPath()
  174. ballPath.addEllipse(ballRect)
  175. #painter.drawRect(ballRect)
  176. tmpValue = (0.375 + 0.75*value)
  177. ballValue = tmpValue - floor(tmpValue)
  178. ballPoint = ballPath.pointAtPercent(ballValue)
  179. # draw arc
  180. startAngle = 216*16
  181. spanAngle = -252*16*value
  182. if self.fCustomPaint == self.CUSTOM_PAINT_CARLA_WET:
  183. painter.setBrush(colorBlue)
  184. painter.setPen(QPen(colorBlue, 0))
  185. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  186. gradient = QConicalGradient(15.5, 15.5, -45)
  187. gradient.setColorAt(0.0, colorBlue)
  188. gradient.setColorAt(0.125, colorBlue)
  189. gradient.setColorAt(0.625, colorGreen)
  190. gradient.setColorAt(0.75, colorGreen)
  191. gradient.setColorAt(0.76, colorGreen)
  192. gradient.setColorAt(1.0, colorGreen)
  193. painter.setBrush(gradient)
  194. painter.setPen(QPen(gradient, 3))
  195. else:
  196. painter.setBrush(colorBlue)
  197. painter.setPen(QPen(colorBlue, 0))
  198. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  199. painter.setBrush(colorBlue)
  200. painter.setPen(QPen(colorBlue, 3))
  201. painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)
  202. # Custom knobs (L and R)
  203. elif self.fCustomPaint in (self.CUSTOM_PAINT_CARLA_L, self.CUSTOM_PAINT_CARLA_R):
  204. # knob color
  205. color = QColor(0xAD + self.fHoverStep*5, 0xD5 + self.fHoverStep*4, 0x4B + self.fHoverStep*5)
  206. # draw small circle
  207. ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
  208. ballPath = QPainterPath()
  209. ballPath.addEllipse(ballRect)
  210. #painter.drawRect(ballRect)
  211. tmpValue = (0.375 + 0.75*value)
  212. ballValue = tmpValue - floor(tmpValue)
  213. ballPoint = ballPath.pointAtPercent(ballValue)
  214. painter.setBrush(color)
  215. painter.setPen(QPen(color, 0))
  216. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0))
  217. # draw arc
  218. if self.fCustomPaint == self.CUSTOM_PAINT_CARLA_L:
  219. startAngle = 216*16
  220. spanAngle = -252.0*16*value
  221. elif self.fCustomPaint == self.CUSTOM_PAINT_CARLA_R:
  222. startAngle = 324.0*16
  223. spanAngle = 252.0*16*(1.0-value)
  224. else:
  225. return
  226. painter.setPen(QPen(color, 2))
  227. painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle)
  228. # Custom knobs (Zita)
  229. elif self.fCustomPaint == self.CUSTOM_PAINT_ZITA:
  230. a = value * pi * 1.5 - 2.35
  231. r = 10.0
  232. x = 10.5
  233. y = 10.5
  234. x += r * sin(a)
  235. y -= r * cos(a)
  236. painter.setBrush(Qt.black)
  237. painter.setPen(QPen(Qt.black, 2))
  238. painter.drawLine(QPointF(11.0, 11.0), QPointF(x, y))
  239. # Custom knobs
  240. else:
  241. painter.restore()
  242. return
  243. if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
  244. self.fHoverStep += 1 if self.fIsHovered else -1
  245. QTimer.singleShot(20, self.update)
  246. else: # isEnabled()
  247. target = QRectF(0.0, 0.0, self.fSize, self.fSize)
  248. painter.drawPixmap(target, self.fPixmap, target)
  249. painter.restore()
  250. def resizeEvent(self, event):
  251. self.updateSizes()
  252. QDial.resizeEvent(self, event)