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.

359 lines
13KB

  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_COLOR = 5
  33. CUSTOM_PAINT_ZITA = 6
  34. CUSTOM_PAINT_NO_GRADIENT = 7
  35. # enum Orientation
  36. HORIZONTAL = 0
  37. VERTICAL = 1
  38. HOVER_MIN = 0
  39. HOVER_MAX = 9
  40. def __init__(self, parent, index=0):
  41. QDial.__init__(self, parent)
  42. self.fIndex = index
  43. self.fPixmap = QPixmap(":/bitmaps/dial_01d.png")
  44. self.fPixmapNum = "01"
  45. self.fCustomColor = QColor(0, 0, 0)
  46. self.fCustomPaint = self.CUSTOM_PAINT_NULL
  47. self.fIsHovered = False
  48. self.fHoverStep = self.HOVER_MIN
  49. if self.fPixmap.width() > self.fPixmap.height():
  50. self.fOrientation = self.HORIZONTAL
  51. else:
  52. self.fOrientation = self.VERTICAL
  53. self.fLabel = ""
  54. self.fLabelPos = QPointF(0.0, 0.0)
  55. self.fLabelFont = QFont() #"DejaVu Sans [Book]", 6, QFont.Normal, False)
  56. #self.fLabelFont.setPixelSize(8)
  57. #self.fLabelFont.setWeight(100)
  58. self.fLabelFont.setPointSize(6)
  59. self.fLabelWidth = 0
  60. self.fLabelHeight = 0
  61. self.fLabelGradient = QLinearGradient(0, 0, 0, 1)
  62. if self.palette().window().color().lightness() > 100:
  63. # Light background
  64. c = self.palette().dark().color()
  65. self.fColor1 = c
  66. self.fColor2 = QColor(c.red(), c.green(), c.blue(), 0)
  67. self.fColorT = [self.palette().buttonText().color(), self.palette().mid().color()]
  68. else:
  69. # Dark background
  70. self.fColor1 = QColor(0, 0, 0, 255)
  71. self.fColor2 = QColor(0, 0, 0, 0)
  72. self.fColorT = [Qt.white, Qt.darkGray]
  73. self.updateSizes()
  74. def getIndex(self):
  75. return self.fIndex
  76. def getSize(self):
  77. return self.fSize
  78. def setCustomColor(self, color):
  79. self.fCustomColor = color
  80. #self.update()
  81. def setCustomPaint(self, paint):
  82. self.fCustomPaint = paint
  83. self.fLabelPos.setY(self.fSize + self.fLabelHeight/2)
  84. #self.update()
  85. def setEnabled(self, enabled):
  86. if self.isEnabled() != enabled:
  87. self.fPixmap.load(":/bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if enabled else "d"))
  88. self.updateSizes()
  89. self.update()
  90. QDial.setEnabled(self, enabled)
  91. def setIndex(self, index):
  92. self.fIndex = index
  93. def setLabel(self, label):
  94. self.fLabel = label
  95. self.fLabelWidth = QFontMetrics(self.fLabelFont).width(label)
  96. self.fLabelHeight = QFontMetrics(self.fLabelFont).height()
  97. self.fLabelPos.setX(float(self.fSize)/2.0 - float(self.fLabelWidth)/2.0)
  98. self.fLabelPos.setY(self.fSize + self.fLabelHeight)
  99. self.fLabelGradient.setColorAt(0.0, self.fColor1)
  100. self.fLabelGradient.setColorAt(0.6, self.fColor1)
  101. self.fLabelGradient.setColorAt(1.0, self.fColor2)
  102. self.fLabelGradient.setStart(0, float(self.fSize)/2.0)
  103. self.fLabelGradient.setFinalStop(0, self.fSize + self.fLabelHeight + 5)
  104. self.fLabelGradientRect = QRectF(float(self.fSize)/8.0, float(self.fSize)/2.0, float(self.fSize*6)/8.0, self.fSize+self.fLabelHeight+5)
  105. #self.update()
  106. def setPixmap(self, pixmapId):
  107. self.fPixmapNum = "%02i" % pixmapId
  108. self.fPixmap.load(":/bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if self.isEnabled() else "d"))
  109. if self.fPixmap.width() > self.fPixmap.height():
  110. self.fOrientation = self.HORIZONTAL
  111. else:
  112. self.fOrientation = self.VERTICAL
  113. self.updateSizes()
  114. #self.update()
  115. def setWhiteText(self):
  116. self.fColor1 = QColor(0, 0, 0, 255)
  117. self.fColor2 = QColor(0, 0, 0, 0)
  118. self.fColorT = [Qt.white, Qt.darkGray]
  119. def minimumSizeHint(self):
  120. return QSize(self.fSize, self.fSize)
  121. def sizeHint(self):
  122. return QSize(self.fSize, self.fSize)
  123. def updateSizes(self):
  124. self.fWidth = self.fPixmap.width()
  125. self.fHeight = self.fPixmap.height()
  126. if self.fWidth < 1:
  127. self.fWidth = 1
  128. if self.fHeight < 1:
  129. self.fHeight = 1
  130. if self.fOrientation == self.HORIZONTAL:
  131. self.fSize = self.fHeight
  132. self.fCount = self.fWidth / self.fHeight
  133. else:
  134. self.fSize = self.fWidth
  135. self.fCount = self.fHeight / self.fWidth
  136. self.setMinimumSize(self.fSize, self.fSize + self.fLabelHeight + 5)
  137. self.setMaximumSize(self.fSize, self.fSize + self.fLabelHeight + 5)
  138. def enterEvent(self, event):
  139. self.fIsHovered = True
  140. if self.fHoverStep == self.HOVER_MIN:
  141. self.fHoverStep = self.HOVER_MIN + 1
  142. QDial.enterEvent(self, event)
  143. def leaveEvent(self, event):
  144. self.fIsHovered = False
  145. if self.fHoverStep == self.HOVER_MAX:
  146. self.fHoverStep = self.HOVER_MAX - 1
  147. QDial.leaveEvent(self, event)
  148. def paintEvent(self, event):
  149. painter = QPainter(self)
  150. event.accept()
  151. painter.save()
  152. painter.setRenderHint(QPainter.Antialiasing, True)
  153. if self.fLabel:
  154. if self.fCustomPaint == self.CUSTOM_PAINT_NULL:
  155. painter.setPen(self.fColor2)
  156. painter.setBrush(self.fLabelGradient)
  157. painter.drawRect(self.fLabelGradientRect)
  158. painter.setFont(self.fLabelFont)
  159. painter.setPen(self.fColorT[0 if self.isEnabled() else 1])
  160. painter.drawText(self.fLabelPos, self.fLabel)
  161. if self.isEnabled():
  162. current = float(self.value() - self.minimum())
  163. divider = float(self.maximum() - self.minimum())
  164. if divider == 0.0:
  165. return
  166. value = current / divider
  167. target = QRectF(0.0, 0.0, self.fSize, self.fSize)
  168. per = int((self.fCount - 1) * value)
  169. if self.fOrientation == self.HORIZONTAL:
  170. xpos = self.fSize * per
  171. ypos = 0.0
  172. else:
  173. xpos = 0.0
  174. ypos = self.fSize * per
  175. source = QRectF(xpos, ypos, self.fSize, self.fSize)
  176. painter.drawPixmap(target, self.fPixmap, source)
  177. # Custom knobs (Dry/Wet and Volume)
  178. if self.fCustomPaint in (self.CUSTOM_PAINT_CARLA_WET, self.CUSTOM_PAINT_CARLA_VOL):
  179. # knob color
  180. colorGreen = QColor(0x5D, 0xE7, 0x3D).lighter(100 + self.fHoverStep*6)
  181. colorBlue = QColor(0x3E, 0xB8, 0xBE).lighter(100 + self.fHoverStep*6)
  182. # draw small circle
  183. ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
  184. ballPath = QPainterPath()
  185. ballPath.addEllipse(ballRect)
  186. #painter.drawRect(ballRect)
  187. tmpValue = (0.375 + 0.75*value)
  188. ballValue = tmpValue - floor(tmpValue)
  189. ballPoint = ballPath.pointAtPercent(ballValue)
  190. # draw arc
  191. startAngle = 216*16
  192. spanAngle = -252*16*value
  193. if self.fCustomPaint == self.CUSTOM_PAINT_CARLA_WET:
  194. painter.setBrush(colorBlue)
  195. painter.setPen(QPen(colorBlue, 0))
  196. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  197. gradient = QConicalGradient(15.5, 15.5, -45)
  198. gradient.setColorAt(0.0, colorBlue)
  199. gradient.setColorAt(0.125, colorBlue)
  200. gradient.setColorAt(0.625, colorGreen)
  201. gradient.setColorAt(0.75, colorGreen)
  202. gradient.setColorAt(0.76, colorGreen)
  203. gradient.setColorAt(1.0, colorGreen)
  204. painter.setBrush(gradient)
  205. painter.setPen(QPen(gradient, 3))
  206. else:
  207. painter.setBrush(colorBlue)
  208. painter.setPen(QPen(colorBlue, 0))
  209. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  210. painter.setBrush(colorBlue)
  211. painter.setPen(QPen(colorBlue, 3))
  212. painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)
  213. # Custom knobs (L and R)
  214. elif self.fCustomPaint in (self.CUSTOM_PAINT_CARLA_L, self.CUSTOM_PAINT_CARLA_R):
  215. # knob color
  216. color = QColor(0xAD, 0xD5, 0x48).lighter(100 + self.fHoverStep*6)
  217. # draw small circle
  218. ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
  219. ballPath = QPainterPath()
  220. ballPath.addEllipse(ballRect)
  221. #painter.drawRect(ballRect)
  222. tmpValue = (0.375 + 0.75*value)
  223. ballValue = tmpValue - floor(tmpValue)
  224. 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))
  228. # draw arc
  229. if self.fCustomPaint == self.CUSTOM_PAINT_CARLA_L:
  230. startAngle = 216*16
  231. spanAngle = -252.0*16*value
  232. elif self.fCustomPaint == self.CUSTOM_PAINT_CARLA_R:
  233. startAngle = 324.0*16
  234. spanAngle = 252.0*16*(1.0-value)
  235. else:
  236. return
  237. painter.setPen(QPen(color, 2))
  238. painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle)
  239. # Custom knobs (Color)
  240. elif self.fCustomPaint == self.CUSTOM_PAINT_COLOR:
  241. # knob color
  242. color = self.fCustomColor.lighter(100 + self.fHoverStep*6)
  243. # draw small circle
  244. ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
  245. ballPath = QPainterPath()
  246. ballPath.addEllipse(ballRect)
  247. tmpValue = (0.375 + 0.75*value)
  248. ballValue = tmpValue - floor(tmpValue)
  249. ballPoint = ballPath.pointAtPercent(ballValue)
  250. # draw arc
  251. startAngle = 216*16
  252. spanAngle = -252*16*value
  253. painter.setBrush(color)
  254. painter.setPen(QPen(color, 0))
  255. painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))
  256. painter.setBrush(color)
  257. painter.setPen(QPen(color, 3))
  258. painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)
  259. # Custom knobs (Zita)
  260. elif self.fCustomPaint == self.CUSTOM_PAINT_ZITA:
  261. a = value * pi * 1.5 - 2.35
  262. r = 10.0
  263. x = 10.5
  264. y = 10.5
  265. x += r * sin(a)
  266. y -= r * cos(a)
  267. painter.setBrush(Qt.black)
  268. painter.setPen(QPen(Qt.black, 2))
  269. painter.drawLine(QPointF(11.0, 11.0), QPointF(x, y))
  270. # Custom knobs
  271. else:
  272. painter.restore()
  273. return
  274. if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
  275. self.fHoverStep += 1 if self.fIsHovered else -1
  276. QTimer.singleShot(20, self.update)
  277. else: # isEnabled()
  278. target = QRectF(0.0, 0.0, self.fSize, self.fSize)
  279. painter.drawPixmap(target, self.fPixmap, target)
  280. painter.restore()
  281. def resizeEvent(self, event):
  282. self.updateSizes()
  283. QDial.resizeEvent(self, event)