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.

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