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.

384 lines
12KB

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Imports (Global)
  4. from PyQt4.QtCore import pyqtSlot, Qt, QTimer, SIGNAL, SLOT
  5. from PyQt4.QtGui import QAbstractSpinBox, QComboBox, QCursor, QDialog, QInputDialog, QMenu, QPainter, QProgressBar, QValidator
  6. from PyQt4.QtGui import QStyleFactory
  7. from math import isnan
  8. # Imports (Custom)
  9. import ui_inputdialog_value
  10. def fix_value(value, minimum, maximum):
  11. if isnan(value):
  12. print("Parameter is NaN! - %f" % value)
  13. return minimum
  14. elif value < minimum:
  15. print("Parameter too low! - %f/%f" % (value, minimum))
  16. return minimum
  17. elif value > maximum:
  18. print("Parameter too high! - %f/%f" % (value, maximum))
  19. return maximum
  20. else:
  21. return value
  22. #QPlastiqueStyle = QStyleFactory.create("Plastique")
  23. # Custom InputDialog with Scale Points support
  24. class CustomInputDialog(QDialog, ui_inputdialog_value.Ui_Dialog):
  25. def __init__(self, parent, label, current, minimum, maximum, step, scalePoints):
  26. QDialog.__init__(self, parent)
  27. self.setupUi(self)
  28. self.label.setText(label)
  29. self.doubleSpinBox.setMinimum(minimum)
  30. self.doubleSpinBox.setMaximum(maximum)
  31. self.doubleSpinBox.setValue(current)
  32. self.doubleSpinBox.setSingleStep(step)
  33. self.ret_value = current
  34. if not scalePoints:
  35. self.groupBox.setVisible(False)
  36. self.resize(200, 0)
  37. else:
  38. text = "<table>"
  39. for scalePoint in scalePoints:
  40. text += "<tr><td align='right'>%f</td><td align='left'> - %s</td></tr>" % (scalePoint['value'], scalePoint['label'])
  41. text += "</table>"
  42. self.textBrowser.setText(text)
  43. self.resize(200, 300)
  44. self.connect(self, SIGNAL("accepted()"), self.setReturnValue)
  45. def setReturnValue(self):
  46. self.ret_value = self.doubleSpinBox.value()
  47. def done(self, r):
  48. QDialog.done(self, r)
  49. self.close()
  50. # Progress-Bar used for ParamSpinBox
  51. class ParamProgressBar(QProgressBar):
  52. def __init__(self, parent):
  53. QProgressBar.__init__(self, parent)
  54. self.m_leftClickDown = False
  55. self.m_minimum = 0.0
  56. self.m_maximum = 1.0
  57. self.m_rvalue = 0.0
  58. self.m_label = ""
  59. self.m_preLabel = " "
  60. self.m_textCall = None
  61. self.setMinimum(0)
  62. self.setMaximum(1000)
  63. self.setValue(0)
  64. self.setFormat("(none)")
  65. def set_minimum(self, value):
  66. self.m_minimum = value
  67. def set_maximum(self, value):
  68. self.m_maximum = value
  69. def set_value(self, value):
  70. self.m_rvalue = value
  71. vper = (value - self.m_minimum) / (self.m_maximum - self.m_minimum)
  72. self.setValue(vper * 1000)
  73. def set_label(self, label):
  74. self.m_label = label.strip()
  75. if self.m_label == "(coef)":
  76. self.m_label = ""
  77. self.m_preLabel = "*"
  78. self.update()
  79. def set_text_call(self, textCall):
  80. self.m_textCall = textCall
  81. def handleMouseEventPos(self, pos):
  82. xper = float(pos.x()) / self.width()
  83. value = xper * (self.m_maximum - self.m_minimum) + self.m_minimum
  84. if value < self.m_minimum:
  85. value = self.m_minimum
  86. elif value > self.m_maximum:
  87. value = self.m_maximum
  88. self.emit(SIGNAL("valueChangedFromBar(double)"), value)
  89. def mousePressEvent(self, event):
  90. if event.button() == Qt.LeftButton:
  91. self.handleMouseEventPos(event.pos())
  92. self.m_leftClickDown = True
  93. else:
  94. self.m_leftClickDown = False
  95. QProgressBar.mousePressEvent(self, event)
  96. def mouseMoveEvent(self, event):
  97. if self.m_leftClickDown:
  98. self.handleMouseEventPos(event.pos())
  99. QProgressBar.mouseMoveEvent(self, event)
  100. def mouseReleaseEvent(self, event):
  101. self.m_leftClickDown = False
  102. QProgressBar.mouseReleaseEvent(self, event)
  103. def paintEvent(self, event):
  104. if self.m_textCall:
  105. self.setFormat("%s %s %s" % (self.m_preLabel, self.m_textCall(), self.m_label))
  106. else:
  107. self.setFormat("%s %f %s" % (self.m_preLabel, self.m_rvalue, self.m_label))
  108. QProgressBar.paintEvent(self, event)
  109. # Special SpinBox used for parameters
  110. class ParamSpinBox(QAbstractSpinBox):
  111. def __init__(self, parent):
  112. QAbstractSpinBox.__init__(self, parent)
  113. self._minimum = 0.0
  114. self._maximum = 1.0
  115. self._default = 0.0
  116. self._value = None
  117. self._step = 0.0
  118. self._step_small = 0.0
  119. self._step_large = 0.0
  120. self._read_only = False
  121. self._scalepoints = None
  122. self._have_scalepoints = False
  123. self.bar = ParamProgressBar(self)
  124. self.bar.setContextMenuPolicy(Qt.NoContextMenu)
  125. self.bar.show()
  126. self.lineEdit().setVisible(False)
  127. self.connect(self.bar, SIGNAL("valueChangedFromBar(double)"), self.handleValueChangedFromBar)
  128. self.connect(self, SIGNAL("customContextMenuRequested(QPoint)"), self.showCustomMenu)
  129. QTimer.singleShot(0, self, SLOT("slot_updateBarGeometry()"))
  130. #def force_plastique_style(self):
  131. #self.setStyle(QPlastiqueStyle)
  132. def set_minimum(self, value):
  133. self._minimum = value
  134. self.bar.set_minimum(value)
  135. def set_maximum(self, value):
  136. self._maximum = value
  137. self.bar.set_maximum(value)
  138. def set_default(self, value):
  139. value = fix_value(value, self._minimum, self._maximum)
  140. self._default = value
  141. def set_value(self, value, send=True):
  142. value = fix_value(value, self._minimum, self._maximum)
  143. if self._value != value:
  144. self._value = value
  145. self.bar.set_value(value)
  146. if self._have_scalepoints:
  147. self.set_scalepoint_value(value)
  148. if send:
  149. self.emit(SIGNAL("valueChanged(double)"), value)
  150. self.update()
  151. return True
  152. else:
  153. return False
  154. def set_step(self, value):
  155. if value == 0.0:
  156. self._step = 0.001
  157. else:
  158. self._step = value
  159. if self._step_small > value:
  160. self._step_small = value
  161. if self._step_large < value:
  162. self._step_large = value
  163. def set_step_small(self, value):
  164. if value == 0.0:
  165. self._step_small = 0.0001
  166. elif value > self._step:
  167. self._step_small = self._step
  168. else:
  169. self._step_small = value
  170. def set_step_large(self, value):
  171. if value == 0.0:
  172. self._step_large = 0.1
  173. elif value < self._step:
  174. self._step_large = self._step
  175. else:
  176. self._step_large = value
  177. def set_label(self, label):
  178. self.bar.set_label(label)
  179. def set_text_call(self, textCall):
  180. self.bar.set_text_call(textCall)
  181. def set_read_only(self, yesno):
  182. self.setButtonSymbols(QAbstractSpinBox.UpDownArrows if yesno else QAbstractSpinBox.NoButtons)
  183. self._read_only = yesno
  184. self.setReadOnly(yesno)
  185. def set_scalepoints(self, scalepoints, use_scalepoints):
  186. if len(scalepoints) > 0:
  187. self._scalepoints = scalepoints
  188. self._have_scalepoints = use_scalepoints
  189. if use_scalepoints:
  190. # Hide ProgressBar and create a ComboBox
  191. self.bar.close()
  192. self.box = QComboBox(self)
  193. self.box.setContextMenuPolicy(Qt.NoContextMenu)
  194. self.box.show()
  195. self.slot_updateBarGeometry()
  196. for scalepoint in scalepoints:
  197. self.box.addItem("%f - %s" % (scalepoint['value'], scalepoint['label']))
  198. if self._value != None:
  199. self.set_scalepoint_value(self._value)
  200. self.connect(self.box, SIGNAL("currentIndexChanged(QString)"), self.handleValueChangedFromBox)
  201. else:
  202. self._scalepoints = None
  203. def set_scalepoint_value(self, value):
  204. value = self.get_nearest_scalepoint(value)
  205. for i in range(self.box.count()):
  206. if float(self.box.itemText(i).split(" - ", 1)[0] == value):
  207. self.box.setCurrentIndex(i)
  208. break
  209. def get_nearest_scalepoint(self, real_value):
  210. final_value = 0.0
  211. for i in range(len(self._scalepoints)):
  212. scale_value = self._scalepoints[i]['value']
  213. if i == 0:
  214. final_value = scale_value
  215. else:
  216. srange1 = abs(real_value - scale_value)
  217. srange2 = abs(real_value - final_value)
  218. if srange2 > srange1:
  219. final_value = scale_value
  220. return final_value
  221. def handleValueChangedFromBar(self, value):
  222. if self._read_only:
  223. return
  224. step = int(0.5 + ((value - self._minimum) / self._step))
  225. real_value = self._minimum + (step * self._step)
  226. self.set_value(real_value)
  227. def handleValueChangedFromBox(self, box_text):
  228. if self._read_only:
  229. return
  230. value = float(box_text.split(" - ", 1)[0])
  231. last_scale_value = self._scalepoints[len(self._scalepoints) - 1]['value']
  232. if value == last_scale_value:
  233. value = self._maximum
  234. self.set_value(value)
  235. def showCustomMenu(self, pos):
  236. menu = QMenu(self)
  237. act_x_reset = menu.addAction(self.tr("Reset (%f)" % self._default))
  238. menu.addSeparator()
  239. act_x_copy = menu.addAction(self.tr("Copy (%f)" % self._value))
  240. if False and not self._read_only:
  241. act_x_paste = menu.addAction(self.tr("Paste (%s)" % "TODO"))
  242. else:
  243. act_x_paste = menu.addAction(self.tr("Paste"))
  244. act_x_paste.setEnabled(False)
  245. menu.addSeparator()
  246. act_x_set = menu.addAction(self.tr("Set value..."))
  247. if self._read_only:
  248. act_x_reset.setEnabled(False)
  249. act_x_paste.setEnabled(False)
  250. act_x_set.setEnabled(False)
  251. # TODO - NOT IMPLEMENTED YET
  252. act_x_copy.setEnabled(False)
  253. act_x_sel = menu.exec_(QCursor.pos())
  254. if act_x_sel == act_x_set:
  255. dialog = CustomInputDialog(self, self.parent().label.text(), self._value, self._minimum, self._maximum, self._step, self._scalepoints)
  256. if dialog.exec_():
  257. value = dialog.ret_value
  258. self.set_value(value)
  259. elif act_x_sel == act_x_copy:
  260. pass
  261. elif act_x_sel == act_x_paste:
  262. pass
  263. elif act_x_sel == act_x_reset:
  264. self.set_value(self._default)
  265. def stepBy(self, steps):
  266. if steps == 0 or self._value == None:
  267. return
  268. value = self._value + (steps * self._step)
  269. if value < self._minimum:
  270. value = self._minimum
  271. elif value > self._maximum:
  272. value = self._maximum
  273. self.set_value(value)
  274. def stepEnabled(self):
  275. if self._read_only or self._value == None:
  276. return QAbstractSpinBox.StepNone
  277. elif self._value <= self._minimum:
  278. return QAbstractSpinBox.StepUpEnabled
  279. elif self._value >= self._maximum:
  280. return QAbstractSpinBox.StepDownEnabled
  281. else:
  282. return QAbstractSpinBox.StepUpEnabled | QAbstractSpinBox.StepDownEnabled
  283. def updateAll(self):
  284. self.update()
  285. self.bar.update()
  286. if self._have_scalepoints:
  287. self.box.update()
  288. @pyqtSlot()
  289. def slot_updateBarGeometry(self):
  290. self.bar.setGeometry(self.lineEdit().geometry())
  291. if self._have_scalepoints:
  292. self.box.setGeometry(self.lineEdit().geometry())
  293. def resizeEvent(self, event):
  294. QTimer.singleShot(0, self, SLOT("slot_updateBarGeometry()"))
  295. QAbstractSpinBox.resizeEvent(self, event)