Browse Source

Fully Scalable UI Part 1

Code preparation for scalable LEDs, Dials and Buttons
tags/v2.2.0-RC1
Térence Clastres Filipe Coelho <falktx@falktx.com> 4 years ago
parent
commit
f3928a5482
13 changed files with 838 additions and 184 deletions
  1. +28
    -25
      resources/resources.qrc
  2. +7
    -7
      resources/ui/carla_edit.ui
  3. +6
    -6
      resources/ui/carla_plugin_calf.ui
  4. +5
    -5
      resources/ui/carla_plugin_classic.ui
  5. +5
    -5
      resources/ui/carla_plugin_compact.ui
  6. +54
    -11
      resources/ui/carla_plugin_default.ui
  7. +5
    -5
      resources/ui/carla_plugin_presets.ui
  8. +82
    -81
      source/frontend/carla_skin.py
  9. +7
    -7
      source/frontend/carla_widgets.py
  10. +7
    -7
      source/frontend/widgets/ledbutton.cpp
  11. +15
    -25
      source/frontend/widgets/ledbutton.py
  12. +98
    -0
      source/frontend/widgets/scalablebutton.py
  13. +519
    -0
      source/frontend/widgets/scalabledial.py

+ 28
- 25
resources/resources.qrc View File

@@ -44,7 +44,7 @@

<file>scalable/carla.svg</file>
<file>scalable/carla-control.svg</file>
<file>scalable/folder.svgz</file>
<file>scalable/osc.svgz</file>
<file>scalable/warning.svgz</file>
@@ -75,31 +75,32 @@
<file>bitmaps/button_distrho_down-white.png</file>
<file>bitmaps/button_distrho_hover-black.png</file>
<file>bitmaps/button_distrho_hover-white.png</file>
<file>bitmaps/button_edit-black.png</file>
<file>bitmaps/button_edit-white.png</file>
<file>bitmaps/button_edit_down-black.png</file>
<file>bitmaps/button_edit_down-white.png</file>
<file>bitmaps/button_edit_hover-black.png</file>
<file>bitmaps/button_edit_hover-white.png</file>
<file>scalable/button_edit-black.svg</file>
<file>scalable/button_edit-white.svg</file>
<file>scalable/button_edit_down-black.svg</file>
<file>scalable/button_edit_down-white.svg</file>
<file>scalable/button_edit_hover-black.svg</file>
<file>scalable/button_edit_hover-white.svg</file>
<file>bitmaps/button_file-black.png</file>
<file>bitmaps/button_file-white.png</file>
<file>bitmaps/button_file_down-black.png</file>
<file>bitmaps/button_file_down-white.png</file>
<file>bitmaps/button_file_hover-black.png</file>
<file>bitmaps/button_file_hover-white.png</file>
<file>bitmaps/button_gui-black.png</file>
<file>bitmaps/button_gui-white.png</file>
<file>bitmaps/button_gui_down-black.png</file>
<file>bitmaps/button_gui_down-white.png</file>
<file>bitmaps/button_gui_hover-black.png</file>
<file>bitmaps/button_gui_hover-white.png</file>
<file>bitmaps/button_off.png</file>
<file>bitmaps/button_on.png</file>

<file>bitmaps/dial_03.png</file>
<file>bitmaps/dial_03d.png</file>
<file>bitmaps/dial_04.png</file>
<file>bitmaps/dial_04d.png</file>
<file>scalable/button_gui-black.svg</file>
<file>scalable/button_gui-white.svg</file>
<file>scalable/button_gui_down-black.svg</file>
<file>scalable/button_gui_down-white.svg</file>
<file>scalable/button_gui_hover-black.svg</file>
<file>scalable/button_gui_hover-white.svg</file>

<file>scalable/button_off.svg</file>
<file>scalable/button_on.svg</file>

<file>scalable/dial_03.svg</file>
<file>scalable/dial_03d.svg</file>
<file>scalable/dial_04.svg</file>
<file>scalable/dial_04d.svg</file>
<file>bitmaps/dial_06.png</file>
<file>bitmaps/dial_06d.png</file>
<file>bitmaps/dial_07.png</file>
@@ -125,11 +126,11 @@
<file>bitmaps/kbd_down-orange.png</file>
<file>bitmaps/kbd_down-red.png</file>

<file>bitmaps/led_off.png</file>
<file>bitmaps/led_blue.png</file>
<file>bitmaps/led_green.png</file>
<file>bitmaps/led_red.png</file>
<file>bitmaps/led_yellow.png</file>
<file>scalable/led_off.svg</file>
<file>scalable/led_red.svg</file>
<file>scalable/led_green.svg</file>
<file>scalable/led_blue.svg</file>
<file>scalable/led_yellow.svg</file>

<file>bitmaps/led_calf_off.png</file>
<file>bitmaps/led_calf_on.png</file>
@@ -160,6 +161,8 @@
<file>scalable/pb_mplayer.svg</file>
<file>scalable/pb_vlc.svg</file>



<file>cursors/zoom-generic-white.png</file>
<file>cursors/zoom-generic-black.png</file>
<file>cursors/zoom-in-white.png</file>


+ 7
- 7
resources/ui/carla_edit.ui View File

@@ -108,7 +108,7 @@
</spacer>
</item>
<item>
<widget class="PixmapDial" name="dial_drywet">
<widget class="ScalableDial" name="dial_drywet">
<property name="minimumSize">
<size>
<width>34</width>
@@ -130,7 +130,7 @@
</widget>
</item>
<item>
<widget class="PixmapDial" name="dial_vol">
<widget class="ScalableDial" name="dial_vol">
<property name="minimumSize">
<size>
<width>34</width>
@@ -183,7 +183,7 @@
<number>0</number>
</property>
<item>
<widget class="PixmapDial" name="dial_b_left">
<widget class="ScalableDial" name="dial_b_left">
<property name="minimumSize">
<size>
<width>26</width>
@@ -205,7 +205,7 @@
</widget>
</item>
<item>
<widget class="PixmapDial" name="dial_b_right">
<widget class="ScalableDial" name="dial_b_right">
<property name="minimumSize">
<size>
<width>26</width>
@@ -246,7 +246,7 @@
<number>0</number>
</property>
<item>
<widget class="PixmapDial" name="dial_pan">
<widget class="ScalableDial" name="dial_pan">
<property name="minimumSize">
<size>
<width>26</width>
@@ -871,9 +871,9 @@ Plugin Name
</widget>
<customwidgets>
<customwidget>
<class>PixmapDial</class>
<class>ScalableDial</class>
<extends>QDial</extends>
<header>widgets/pixmapdial.h</header>
<header>widgets/scalabledial.h</header>
</customwidget>
</customwidgets>
<resources>


+ 6
- 6
resources/ui/carla_plugin_calf.ui View File

@@ -59,7 +59,7 @@
<number>0</number>
</property>
<item>
<widget class="PixmapButton" name="b_enable">
<widget class="ScalableButton" name="b_enable">
<property name="text">
<string>Enable</string>
</property>
@@ -301,7 +301,7 @@
<number>3</number>
</property>
<item>
<widget class="PixmapButton" name="b_gui">
<widget class="ScalableButton" name="b_gui">
<property name="text">
<string>GUI</string>
</property>
@@ -311,7 +311,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_edit">
<widget class="ScalableButton" name="b_edit">
<property name="text">
<string>Edit</string>
</property>
@@ -321,7 +321,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_remove">
<widget class="ScalableButton" name="b_remove">
<property name="text">
<string>Remove</string>
</property>
@@ -411,9 +411,9 @@
<header>widgets/ledbutton.h</header>
</customwidget>
<customwidget>
<class>PixmapButton</class>
<class>ScalableButton</class>
<extends>QPushButton</extends>
<header>widgets/pixmapbutton.h</header>
<header>widgets/scalablebutton.h</header>
</customwidget>
</customwidgets>
<resources>


+ 5
- 5
resources/ui/carla_plugin_classic.ui View File

@@ -54,7 +54,7 @@
<number>4</number>
</property>
<item>
<widget class="PixmapButton" name="b_enable">
<widget class="ScalableButton" name="b_enable">
<property name="minimumSize">
<size>
<width>24</width>
@@ -89,7 +89,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_gui">
<widget class="ScalableButton" name="b_gui">
<property name="minimumSize">
<size>
<width>24</width>
@@ -124,7 +124,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_edit">
<widget class="ScalableButton" name="b_edit">
<property name="minimumSize">
<size>
<width>24</width>
@@ -344,9 +344,9 @@
<header>widgets/ledbutton.h</header>
</customwidget>
<customwidget>
<class>PixmapButton</class>
<class>ScalableButton</class>
<extends>QPushButton</extends>
<header>widgets/pixmapbutton.h</header>
<header>widgets/scalablebutton.h</header>
</customwidget>
</customwidgets>
<resources>


+ 5
- 5
resources/ui/carla_plugin_compact.ui View File

@@ -57,7 +57,7 @@
<number>0</number>
</property>
<item>
<widget class="PixmapButton" name="b_enable">
<widget class="ScalableButton" name="b_enable">
<property name="minimumSize">
<size>
<width>24</width>
@@ -92,7 +92,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_gui">
<widget class="ScalableButton" name="b_gui">
<property name="minimumSize">
<size>
<width>24</width>
@@ -127,7 +127,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_edit">
<widget class="ScalableButton" name="b_edit">
<property name="minimumSize">
<size>
<width>24</width>
@@ -405,9 +405,9 @@
<header>widgets/ledbutton.h</header>
</customwidget>
<customwidget>
<class>PixmapButton</class>
<class>ScalableButton</class>
<extends>QPushButton</extends>
<header>widgets/pixmapbutton.h</header>
<header>widgets/scalablebutton.h</header>
</customwidget>
</customwidgets>
<resources>


+ 54
- 11
resources/ui/carla_plugin_default.ui View File

@@ -58,11 +58,20 @@
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="PixmapButton" name="b_enable">
<widget class="ScalableButton" name="b_enable">
<property name="minimumSize">
<size>
<width>24</width>
@@ -79,8 +88,8 @@
<string/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/bitmaps/button_off.png</normaloff>:/bitmaps/button_off.png</iconset>
<iconset>
<normaloff>../scalable/button_off.svg</normaloff>../scalable/button_off.svg</iconset>
</property>
<property name="iconSize">
<size>
@@ -97,7 +106,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_gui">
<widget class="ScalableButton" name="b_gui">
<property name="minimumSize">
<size>
<width>24</width>
@@ -114,8 +123,8 @@
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/bitmaps/button_gui.png</normaloff>:/bitmaps/button_gui.png</iconset>
<iconset resource="../resources.qrc">
<normaloff>:/bitmaps/button_gui-black.png</normaloff>:/bitmaps/button_gui-black.png</iconset>
</property>
<property name="iconSize">
<size>
@@ -132,7 +141,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_edit">
<widget class="ScalableButton" name="b_edit">
<property name="minimumSize">
<size>
<width>24</width>
@@ -307,6 +316,12 @@
</property>
<item>
<widget class="LEDButton" name="led_control">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>14</width>
@@ -322,6 +337,10 @@
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/scalable/led_off.svg</normaloff>:/scalable/led_off.svg</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
@@ -344,6 +363,10 @@
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/scalable/led_off.svg</normaloff>:/scalable/led_off.svg</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
@@ -366,6 +389,10 @@
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/scalable/led_off.svg</normaloff>:/scalable/led_off.svg</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
@@ -373,6 +400,9 @@
</item>
<item>
<widget class="LEDButton" name="led_audio_out">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>14</width>
@@ -388,6 +418,10 @@
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/scalable/led_off.svg</normaloff>:/scalable/led_off.svg</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
@@ -433,7 +467,16 @@
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
@@ -490,9 +533,9 @@
<header>widgets/ledbutton.h</header>
</customwidget>
<customwidget>
<class>PixmapButton</class>
<class>ScalableButton</class>
<extends>QPushButton</extends>
<header>widgets/pixmapbutton.h</header>
<header>widgets/scalablebutton.h</header>
</customwidget>
</customwidgets>
<resources>


+ 5
- 5
resources/ui/carla_plugin_presets.ui View File

@@ -59,7 +59,7 @@
<number>0</number>
</property>
<item>
<widget class="PixmapButton" name="b_enable">
<widget class="ScalableButton" name="b_enable">
<property name="minimumSize">
<size>
<width>24</width>
@@ -94,7 +94,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_gui">
<widget class="ScalableButton" name="b_gui">
<property name="minimumSize">
<size>
<width>24</width>
@@ -129,7 +129,7 @@
</widget>
</item>
<item>
<widget class="PixmapButton" name="b_edit">
<widget class="ScalableButton" name="b_edit">
<property name="minimumSize">
<size>
<width>24</width>
@@ -517,9 +517,9 @@
<header>widgets/ledbutton.h</header>
</customwidget>
<customwidget>
<class>PixmapButton</class>
<class>ScalableButton</class>
<extends>QPushButton</extends>
<header>widgets/pixmapbutton.h</header>
<header>widgets/scalablebutton.h</header>
</customwidget>
</customwidgets>
<resources>


+ 82
- 81
source/frontend/carla_skin.py View File

@@ -20,7 +20,7 @@
# Imports (Global)

from PyQt5.QtCore import Qt, QRectF, QLineF
from PyQt5.QtGui import QFont, QFontDatabase, QPen, QPixmap
from PyQt5.QtGui import QFont, QFontDatabase, QPen
from PyQt5.QtWidgets import QColorDialog, QFrame, QPushButton

# ------------------------------------------------------------------------------------------------------------
@@ -34,7 +34,7 @@ import ui_carla_plugin_presets

from carla_widgets import *
from widgets.digitalpeakmeter import DigitalPeakMeter
from widgets.pixmapdial import PixmapDial
from widgets.scalabledial import ScalableDial

# ------------------------------------------------------------------------------------------------------------
# Plugin Skin Rules (WORK IN PROGRESS)
@@ -43,7 +43,7 @@ from widgets.pixmapdial import PixmapDial
# Spacing of the top-most layout must be 1px.
# Top and bottom margins must be 3px (can be split between different Qt layouts).
# Left and right margins must be 6px (can be split between different Qt layouts).
# If the left or right side has built-in margins, say a transparent png border,
# If the left or right side has built-in margins, say a transparent svg border,
# those margins must be taken into consideration.
#
# There's a top and bottom layout, separated by a horizontal line.
@@ -158,33 +158,33 @@ def getColorFromCategory(category):
# ------------------------------------------------------------------------------------------------------------
#

def setPixmapDialStyle(widget, parameterId, parameterCount, whiteLabels, skinStyle):
def setScalableDialStyle(widget, parameterId, parameterCount, whiteLabels, skinStyle):
if skinStyle.startswith("calf"):
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT)
widget.setPixmap(7)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_NO_GRADIENT)
widget.setSvg(7)

elif skinStyle.startswith("openav"):
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_NO_GRADIENT)
if parameterId == PARAMETER_DRYWET:
widget.setPixmap(13)
widget.setSvg(13)
elif parameterId == PARAMETER_VOLUME:
widget.setPixmap(12)
widget.setSvg(12)
else:
widget.setPixmap(11)
widget.setSvg(11)

else:
if parameterId == PARAMETER_DRYWET:
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_WET)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_CARLA_WET)

elif parameterId == PARAMETER_VOLUME:
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_VOL)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_CARLA_VOL)

else:
_r = 255 - int((float(parameterId)/float(parameterCount))*200.0)
_g = 55 + int((float(parameterId)/float(parameterCount))*200.0)
_b = 0 #(r-40)*4
widget.setCustomPaintColor(QColor(_r, _g, _b))
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_COLOR)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_COLOR)

if whiteLabels:
colorEnabled = QColor("#BBB")
@@ -194,7 +194,7 @@ def setPixmapDialStyle(widget, parameterId, parameterCount, whiteLabels, skinSty
colorDisabled = QColor("#AAA")

widget.setLabelColor(colorEnabled, colorDisabled)
widget.setPixmap(3)
widget.setSvg(3)

# ------------------------------------------------------------------------------------------------------------
# Abstract plugin slot
@@ -357,7 +357,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
if self.fPluginId == pluginId:
self.customUiStateChanged(state)

#------------------------------------------------------------------
# ------------------------------------------------------------------

def ready(self):
self.fIsActive = bool(self.host.get_internal_parameter_value(self.fPluginId, PARAMETER_ACTIVE) >= 0.5)
@@ -368,6 +368,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):

if self.fSkinStyle.startswith("calf") or self.fSkinStyle.startswith("openav") or self.fSkinStyle in (
"3bandeq", "3bandsplitter", "pingpongpan", "nekobi", "calf_black", "zynfx"):

imageSuffix = "white"
whiteLabels = True

@@ -376,46 +377,46 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
self.b_enable.clicked.connect(self.slot_enableClicked)

if isCalfSkin:
self.b_enable.setPixmaps(":/bitmaps/button_calf3.png",
":/bitmaps/button_calf3_down.png",
":/bitmaps/button_calf3.png")
self.b_enable.setSvgs(":/scalable/button_calf3.svg",
":/scalable/button_calf3_down.svg",
":/scalable/button_calf3.svg")
else:
self.b_enable.setPixmaps(":/bitmaps/button_off.png",
":/bitmaps/button_on.png",
":/bitmaps/button_off.png")
self.b_enable.setSvgs(":/scalable/button_off.svg",
":/scalable/button_on.svg",
":/scalable/button_off.svg")

if self.b_gui is not None:
self.b_gui.clicked.connect(self.slot_showCustomUi)
self.b_gui.setEnabled(bool(self.fPluginInfo['hints'] & PLUGIN_HAS_CUSTOM_UI))

if isCalfSkin:
self.b_gui.setPixmaps(":/bitmaps/button_calf2.png",
":/bitmaps/button_calf2_down.png",
":/bitmaps/button_calf2_hover.png")
elif self.fPluginInfo['iconName'] == "distrho" or self.fSkinStyle in ("3bandeq","3bandsplitter","pingpongpan", "nekobi"):
self.b_gui.setPixmaps(":/bitmaps/button_distrho-{}.png".format(imageSuffix),
":/bitmaps/button_distrho_down-{}.png".format(imageSuffix),
":/bitmaps/button_distrho_hover-{}.png".format(imageSuffix))
self.b_gui.setSvgs(":/scalable/button_calf2.svg",
":/scalable/button_calf2_down.svg",
":/scalable/button_calf2_hover.svg")
elif self.fPluginInfo['iconName'] == "distrho" or self.fSkinStyle in ("3bandeq", "3bandsplitter", "pingpongpan", "nekobi"):
self.b_gui.setSvgs(":/scalable/button_distrho-{}.svg".format(imageSuffix),
":/scalable/button_distrho_down-{}.svg".format(imageSuffix),
":/scalable/button_distrho_hover-{}.svg".format(imageSuffix))
elif self.fPluginInfo['iconName'] == "file":
self.b_gui.setPixmaps(":/bitmaps/button_file-{}.png".format(imageSuffix),
":/bitmaps/button_file_down-{}.png".format(imageSuffix),
":/bitmaps/button_file_hover-{}.png".format(imageSuffix))
self.b_gui.setSvgs(":/scalable/button_file-{}.svg".format(imageSuffix),
":/scalable/button_file_down-{}.svg".format(imageSuffix),
":/scalable/button_file_hover-{}.svg".format(imageSuffix))
else:
self.b_gui.setPixmaps(":/bitmaps/button_gui-{}.png".format(imageSuffix),
":/bitmaps/button_gui_down-{}.png".format(imageSuffix),
":/bitmaps/button_gui_hover-{}.png".format(imageSuffix))
self.b_gui.setSvgs(":/scalable/button_gui-{}.svg".format(imageSuffix),
":/scalable/button_gui_down-{}.svg".format(imageSuffix),
":/scalable/button_gui_hover-{}.svg".format(imageSuffix))

if self.b_edit is not None:
self.b_edit.clicked.connect(self.slot_showEditDialog)

if isCalfSkin:
self.b_edit.setPixmaps(":/bitmaps/button_calf2.png".format(imageSuffix),
":/bitmaps/button_calf2_down.png".format(imageSuffix),
":/bitmaps/button_calf2_hover.png".format(imageSuffix))
self.b_edit.setSvgs(":/scalable/button_calf2.svg",
":/scalable/button_calf2_down.svg",
":/scalable/button_calf2_hover.svg")
else:
self.b_edit.setPixmaps(":/bitmaps/button_edit-{}.png".format(imageSuffix),
":/bitmaps/button_edit_down-{}.png".format(imageSuffix),
":/bitmaps/button_edit_hover-{}.png".format(imageSuffix))
self.b_edit.setSvgs(":/scalable/button_edit-{}.svg".format(imageSuffix),
":/scalable/button_edit_down-{}.svg".format(imageSuffix),
":/scalable/button_edit_hover-{}.svg".format(imageSuffix))

else:
# Edit button *must* be available
@@ -594,7 +595,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):

paramName = getParameterShortName(paramInfo['name'])

widget = PixmapDial(self, i)
widget = ScalableDial(self, i)
widget.setLabel(paramName)
widget.setMinimum(paramRanges['min'])
widget.setMaximum(paramRanges['max'])
@@ -603,28 +604,28 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
if isInteger:
widget.setPrecision(paramRanges['max']-paramRanges['min'], True)

setPixmapDialStyle(widget, i, parameterCount, whiteLabels, self.fSkinStyle)
setScalableDialStyle(widget, i, parameterCount, whiteLabels, self.fSkinStyle)

index += 1
self.fParameterList.append([i, widget])
layout.addWidget(widget)

if self.w_knobs_right is not None and (self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) != 0:
widget = PixmapDial(self, PARAMETER_DRYWET)
widget = ScalableDial(self, PARAMETER_DRYWET)
widget.setLabel("Dry/Wet")
widget.setMinimum(0.0)
widget.setMaximum(1.0)
setPixmapDialStyle(widget, PARAMETER_DRYWET, 0, whiteLabels, self.fSkinStyle)
setScalableDialStyle(widget, PARAMETER_DRYWET, 0, whiteLabels, self.fSkinStyle)

self.fParameterList.append([PARAMETER_DRYWET, widget])
self.w_knobs_right.layout().addWidget(widget)

if self.w_knobs_right is not None and (self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) != 0:
widget = PixmapDial(self, PARAMETER_VOLUME)
widget = ScalableDial(self, PARAMETER_VOLUME)
widget.setLabel("Volume")
widget.setMinimum(0.0)
widget.setMaximum(1.27)
setPixmapDialStyle(widget, PARAMETER_VOLUME, 0, whiteLabels, self.fSkinStyle)
setScalableDialStyle(widget, PARAMETER_VOLUME, 0, whiteLabels, self.fSkinStyle)

self.fParameterList.append([PARAMETER_VOLUME, widget])
self.w_knobs_right.layout().addWidget(widget)
@@ -646,7 +647,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
self.fAdjustViewableKnobCountScheduled = True
QTimer.singleShot(5, self.adjustViewableKnobCount)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def getFixedHeight(self):
return 32
@@ -657,7 +658,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
def getPluginId(self):
return self.fPluginId

#------------------------------------------------------------------
# -----------------------------------------------------------------

def setPluginId(self, idx):
self.fPluginId = idx
@@ -677,7 +678,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
self.fIsSelected = yesNo
self.update()

#------------------------------------------------------------------
# -----------------------------------------------------------------

def setActive(self, active, sendCallback=False, sendHost=True):
self.fIsActive = active
@@ -729,7 +730,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):

self.fEditDialog.setParameterValue(parameterId, value)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def setParameterValue(self, parameterId, value, sendCallback):
if parameterId == PARAMETER_ACTIVE:
@@ -753,7 +754,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
def setParameterMidiChannel(self, parameterId, channel):
self.fEditDialog.setParameterMidiChannel(parameterId, channel)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def setProgram(self, index, sendCallback):
self.fEditDialog.setProgram(index)
@@ -773,12 +774,12 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):

self.updateParameterValues()

#------------------------------------------------------------------
# -----------------------------------------------------------------

def setOption(self, option, yesNo):
self.fEditDialog.setOption(option, yesNo)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def showCustomUI(self):
self.host.show_custom_ui(self.fPluginId, True)
@@ -826,7 +827,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
if not ok:
CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def activeChanged(self, onOff):
self.fIsActive = onOff
@@ -933,7 +934,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
def editDialogMidiActivityChanged(self, pluginId, onOff):
self.midiActivityChanged(onOff)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def idleFast(self):
# Input peaks
@@ -994,7 +995,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):

self.fEditDialog.idleSlow()

#------------------------------------------------------------------
# -----------------------------------------------------------------

def drawOutline(self, painter):
painter.save()
@@ -1027,7 +1028,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
paramWidget.setValue(self.host.get_current_parameter_value(self.fPluginId, paramIndex))
paramWidget.blockSignals(False)

#------------------------------------------------------------------
# -----------------------------------------------------------------

@pyqtSlot(bool)
def slot_enableClicked(self, yesNo):
@@ -1376,7 +1377,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):

sender.setValue(value, True)

#------------------------------------------------------------------
# -----------------------------------------------------------------

@pyqtSlot(bool)
def slot_showCustomUi(self, show):
@@ -1392,7 +1393,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)

#------------------------------------------------------------------
# -----------------------------------------------------------------

@pyqtSlot(bool)
def slot_parameterDragStateChanged(self, touch):
@@ -1421,7 +1422,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
self.host.set_midi_program(self.fPluginId, index)
self.setMidiProgram(index, False)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def adjustViewableKnobCount(self):
if self.w_knobs_left is None or self.spacer_knobs is None:
@@ -1457,7 +1458,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta):
def testTimer(self):
self.fIdleTimerId = self.startTimer(25)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def mouseDoubleClickEvent(self, event):
QFrame.mouseDoubleClickEvent(self, event)
@@ -1529,7 +1530,7 @@ class PluginSlot_Calf(AbstractPluginSlot):

self.ui.label_active.setFont(self.fButtonFont)

self.ui.b_remove.setPixmaps(":/bitmaps/button_calf1.png", ":/bitmaps/button_calf1_down.png", ":/bitmaps/button_calf1_hover.png")
self.ui.b_remove.setSvgs(":/scalable/button_calf1.svg", ":/scalable/button_calf1_down.svg", ":/scalable/button_calf1_hover.svg")

self.ui.b_edit.setTopText(self.tr("Edit"), self.fButtonColorOn, self.fButtonFont)
self.ui.b_remove.setTopText(self.tr("Remove"), self.fButtonColorOn, self.fButtonFont)
@@ -1573,12 +1574,12 @@ class PluginSlot_Calf(AbstractPluginSlot):

self.ui.led_midi.setColor(self.ui.led_midi.CALF)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def getFixedHeight(self):
return 94 if max(self.peak_in.channelCount(), self.peak_out.channelCount()) < 2 else 106

#------------------------------------------------------------------
# -----------------------------------------------------------------

def editDialogPluginHintsChanged(self, pluginId, hints):
if hints & PLUGIN_HAS_CUSTOM_UI:
@@ -1588,7 +1589,7 @@ class PluginSlot_Calf(AbstractPluginSlot):

AbstractPluginSlot.editDialogPluginHintsChanged(self, pluginId, hints)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def paintEvent(self, event):
isBlack = bool(self.fSkinStyle == "calf_black")
@@ -1636,12 +1637,12 @@ class PluginSlot_Classic(AbstractPluginSlot):

self.ready()

#------------------------------------------------------------------
# -----------------------------------------------------------------

def getFixedHeight(self):
return 36

#------------------------------------------------------------------
# -----------------------------------------------------------------

def paintEvent(self, event):
painter = QPainter(self)
@@ -1716,7 +1717,7 @@ class PluginSlot_Compact(AbstractPluginSlot):

self.ready()

#------------------------------------------------------------------
# -----------------------------------------------------------------

def getFixedHeight(self):
if self.fSkinStyle == "calf_blue":
@@ -1753,12 +1754,12 @@ class PluginSlot_Default(AbstractPluginSlot):

self.ready()

#------------------------------------------------------------------
# -----------------------------------------------------------------

def getFixedHeight(self):
return 80

#------------------------------------------------------------------
# -----------------------------------------------------------------

def paintEvent(self, event):
painter = QPainter(self)
@@ -1934,14 +1935,14 @@ class PluginSlot_Presets(AbstractPluginSlot):
else:
paramName = getParameterShortName(paramName)

widget = PixmapDial(self, i)
widget = ScalableDial(self, i)

widget.setLabel(paramName)
widget.setMinimum(paramRanges['min'])
widget.setMaximum(paramRanges['max'])
widget.setPixmap(3)
widget.setSvg(3)
widget.setCustomPaintColor(QColor(83, 173, 10))
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_COLOR)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_COLOR)
widget.forceWhiteLabelGradientText()
widget.hide()

@@ -1952,35 +1953,35 @@ class PluginSlot_Presets(AbstractPluginSlot):
self.ui.w_knobs_left.layout().addWidget(widget)

if self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET:
widget = PixmapDial(self, PARAMETER_DRYWET)
widget = ScalableDial(self, PARAMETER_DRYWET)
widget.setLabel("Wet")
widget.setMinimum(0.0)
widget.setMaximum(1.0)
widget.setPixmap(3)
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_WET)
widget.setSvg(3)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_CARLA_WET)
widget.forceWhiteLabelGradientText()

self.fParameterList.append([PARAMETER_DRYWET, widget])
self.ui.w_knobs_right.layout().addWidget(widget)

if self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME:
widget = PixmapDial(self, PARAMETER_VOLUME)
widget = ScalableDial(self, PARAMETER_VOLUME)
widget.setLabel("Volume")
widget.setMinimum(0.0)
widget.setMaximum(1.27)
widget.setPixmap(3)
widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_VOL)
widget.setSvg(3)
widget.setCustomPaintMode(ScalableDial.CUSTOM_PAINT_MODE_CARLA_VOL)
widget.forceWhiteLabelGradientText()

self.fParameterList.append([PARAMETER_VOLUME, widget])
self.ui.w_knobs_right.layout().addWidget(widget)

#------------------------------------------------------------------
# -----------------------------------------------------------------

def getFixedHeight(self):
return 80

#------------------------------------------------------------------
# -----------------------------------------------------------------

def paintEvent(self, event):
painter = QPainter(self)


+ 7
- 7
source/frontend/carla_widgets.py View File

@@ -585,8 +585,8 @@ class PluginEdit(QDialog):

self.fPlayingNotes = [] # (channel, note)

self.fTabIconOff = QIcon(":/bitmaps/led_off.png")
self.fTabIconOn = QIcon(":/bitmaps/led_yellow.png")
self.fTabIconOff = QIcon(":/scalable/led_off.svg")
self.fTabIconOn = QIcon(":/scalable/led_yellow.svg")
self.fTabIconTimers = []

# used during testing
@@ -601,35 +601,35 @@ class PluginEdit(QDialog):
self.ui.label_plugin.setFont(labelPluginFont)

self.ui.dial_drywet.setCustomPaintMode(self.ui.dial_drywet.CUSTOM_PAINT_MODE_CARLA_WET)
self.ui.dial_drywet.setPixmap(3)
self.ui.dial_drywet.setSvg(3)
self.ui.dial_drywet.setLabel("Dry/Wet")
self.ui.dial_drywet.setMinimum(0.0)
self.ui.dial_drywet.setMaximum(1.0)
self.ui.dial_drywet.setValue(host.get_internal_parameter_value(pluginId, PARAMETER_DRYWET))

self.ui.dial_vol.setCustomPaintMode(self.ui.dial_vol.CUSTOM_PAINT_MODE_CARLA_VOL)
self.ui.dial_vol.setPixmap(3)
self.ui.dial_vol.setSvg(3)
self.ui.dial_vol.setLabel("Volume")
self.ui.dial_vol.setMinimum(0.0)
self.ui.dial_vol.setMaximum(1.27)
self.ui.dial_vol.setValue(host.get_internal_parameter_value(pluginId, PARAMETER_VOLUME))

self.ui.dial_b_left.setCustomPaintMode(self.ui.dial_b_left.CUSTOM_PAINT_MODE_CARLA_L)
self.ui.dial_b_left.setPixmap(4)
self.ui.dial_b_left.setSvg(4)
self.ui.dial_b_left.setLabel("L")
self.ui.dial_b_left.setMinimum(-1.0)
self.ui.dial_b_left.setMaximum(1.0)
self.ui.dial_b_left.setValue(host.get_internal_parameter_value(pluginId, PARAMETER_BALANCE_LEFT))

self.ui.dial_b_right.setCustomPaintMode(self.ui.dial_b_right.CUSTOM_PAINT_MODE_CARLA_R)
self.ui.dial_b_right.setPixmap(4)
self.ui.dial_b_right.setSvg(4)
self.ui.dial_b_right.setLabel("R")
self.ui.dial_b_right.setMinimum(-1.0)
self.ui.dial_b_right.setMaximum(1.0)
self.ui.dial_b_right.setValue(host.get_internal_parameter_value(pluginId, PARAMETER_BALANCE_RIGHT))

self.ui.dial_pan.setCustomPaintMode(self.ui.dial_b_right.CUSTOM_PAINT_MODE_CARLA_PAN)
self.ui.dial_pan.setPixmap(4)
self.ui.dial_pan.setSvg(4)
self.ui.dial_pan.setLabel("Pan")
self.ui.dial_pan.setMinimum(-1.0)
self.ui.dial_pan.setMaximum(1.0)


+ 7
- 7
source/frontend/widgets/ledbutton.cpp View File

@@ -32,7 +32,7 @@ LEDButton::LEDButton(QWidget* parent):
setColor(BLUE);

// matching fLastColor
fPixmap.load(":/bitmaps/led_off.png");
fPixmap.load(":/scalable/led_off.svg");
}

void LEDButton::setColor(Color color)
@@ -58,19 +58,19 @@ void LEDButton::paintEvent(QPaintEvent* event)
switch (fColor)
{
case OFF:
fPixmap.load(":/bitmaps/led_off.png");
fPixmap.load(":/scalable/led_off.svg");
break;
case BLUE:
fPixmap.load(":/bitmaps/led_blue.png");
fPixmap.load(":/scalable/led_blue.svg");
break;
case GREEN:
fPixmap.load(":/bitmaps/led_green.png");
fPixmap.load(":/scalable/led_green.svg");
break;
case RED:
fPixmap.load(":/bitmaps/led_red.png");
fPixmap.load(":/scalable/led_red.svg");
break;
case YELLOW:
fPixmap.load(":/bitmaps/led_yellow.png");
fPixmap.load(":/scalable/led_yellow.svg");
break;
default:
return;
@@ -81,7 +81,7 @@ void LEDButton::paintEvent(QPaintEvent* event)
}
else if (fLastColor != OFF)
{
fPixmap.load(":/bitmaps/led_off.png");
fPixmap.load(":/scalable/led_off.svg");
fLastColor = OFF;
}



+ 15
- 25
source/frontend/widgets/ledbutton.py View File

@@ -19,13 +19,13 @@
# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

from PyQt5.QtCore import QRectF
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QPushButton

# ------------------------------------------------------------------------------------------------------------
# Widget Class


class LEDButton(QPushButton):
# normal
OFF = 0
@@ -39,60 +39,50 @@ class LEDButton(QPushButton):
def __init__(self, parent):
QPushButton.__init__(self, parent)

self.fPixmap = QPixmap()
self.fPixmapRect = QRectF(0, 0, 0, 0)
self.fSvgWidget = QSvgWidget(self)

self.setCheckable(True)
self.setText("")

self.fLastColor = self.OFF
self.fPixmap.load(":/bitmaps/led_off.png")
self.fSvgWidget.load(":/scalable/led_off.svg")

self.setColor(self.BLUE)

def setColor(self, color):
self.fColor = color
self._loadPixmapNow()
self._loadSVGNow()

# Fix calf off
if color == self.CALF:
self.fPixmap.load(":/bitmaps/led_calf_off.png")

size = self.fPixmap.width()
self.fPixmapRect = QRectF(0, 0, size, size)

self.setMinimumSize(size, size)
self.setMaximumSize(size, size)
self.fSvgWidget.load(":/bitmaps/led_calf_off.png")

def paintEvent(self, event):
painter = QPainter(self)
event.accept()

self._loadPixmapNow()

painter.drawPixmap(self.fPixmapRect, self.fPixmap, self.fPixmapRect)
self._loadSVGNow()

def _loadPixmapNow(self):
def _loadSVGNow(self):

if self.isChecked():
if self.fLastColor != self.fColor:
if self.fColor == self.OFF:
self.fPixmap.load(":/bitmaps/led_off.png")
self.fSvgWidget.load(":/scalable/led_off.svg")
elif self.fColor == self.BLUE:
self.fPixmap.load(":/bitmaps/led_blue.png")
self.fSvgWidget.load(":/scalable/led_blue.svg")
elif self.fColor == self.GREEN:
self.fPixmap.load(":/bitmaps/led_green.png")
self.fSvgWidget.load(":/scalable/led_green.svg")
elif self.fColor == self.RED:
self.fPixmap.load(":/bitmaps/led_red.png")
self.fSvgWidget.load(":/scalable/led_red.svg")
elif self.fColor == self.YELLOW:
self.fPixmap.load(":/bitmaps/led_yellow.png")
self.fSvgWidget.load(":/scalable/led_yellow.svg")
elif self.fColor == self.CALF:
self.fPixmap.load(":/bitmaps/led_calf_on.png")
self.fSvgWidget.load(":/bitmaps/led_calf_on.png")
else:
return

self.fLastColor = self.fColor

elif self.fLastColor != self.OFF:
self.fPixmap.load(":/bitmaps/led_calf_off.png" if self.fColor == self.CALF else ":/bitmaps/led_off.png")
self.fSvgWidget.load(":/scalable/led_calf_off.png" if self.fColor == self.CALF else ":/scalable/led_off.svg")
self.fLastColor = self.OFF

+ 98
- 0
source/frontend/widgets/scalablebutton.py View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Svg Button, a custom Qt widget
# Copyright (C) 2020 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

from PyQt5.QtCore import QPointF, QRectF
from PyQt5.QtGui import QColor, QFont, QPainter
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QPushButton

# ------------------------------------------------------------------------------------------------------------
# Widget Class


class ScalableButton(QPushButton):
def __init__(self, parent):
QPushButton.__init__(self, parent)

self.fSvgNormal = QSvgWidget()
self.fSvgDown = QSvgWidget()
self.fSvgHover = QSvgWidget()

self.fIsHovered = False

self.fTopText = ""
self.fTopTextColor = QColor()
self.fTopTextFont = QFont()

self.setText("")

def setSvgs(self, normal, down, hover):
self.fSvgNormal.load(normal)
self.fSvgDown.load(down)
self.fSvgHover.load(hover)

width = self.fSvgNormal.sizeHint().width()
height = self.fSvgNormal.sizeHint().height()

self.fSvgRect = QRectF(0, 0, width, height)

self.setMinimumSize(width, height)
self.setMaximumSize(width, height)

def setTopText(self, text, color, font):
self.fTopText = text
self.fTopTextColor = color
self.fTopTextFont = font

def enterEvent(self, event):
self.fIsHovered = True
QPushButton.enterEvent(self, event)

def leaveEvent(self, event):
self.fIsHovered = False
QPushButton.leaveEvent(self, event)

def paintEvent(self, event):
painter = QPainter(self)
event.accept()

if not self.isEnabled():
painter.save()
painter.setOpacity(0.2)
self.fSvgNormal.renderer().render(painter, self.fSvgRect)
painter.restore()

elif self.isChecked() or self.isDown():
self.fSvgDown.renderer().render(painter, self.fSvgRect)

elif self.fIsHovered:
self.fSvgHover.renderer().render(painter, self.fSvgRect)
else:
self.fSvgNormal.renderer().render(painter, self.fSvgRect)
if not self.fTopText:
return

painter.save()
painter.setPen(self.fTopTextColor)
painter.setBrush(self.fTopTextColor)
painter.setFont(self.fTopTextFont)
painter.drawText(QPointF(10, 16), self.fTopText)
painter.restore()

+ 519
- 0
source/frontend/widgets/scalabledial.py View File

@@ -0,0 +1,519 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Svg Dial, a custom Qt widget
# Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

from math import cos, floor, pi, sin

from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QPointF, QRectF, QTimer, QSize
from PyQt5.QtGui import QColor, QConicalGradient, QFont, QFontMetrics
from PyQt5.QtGui import QLinearGradient, QPainter, QPainterPath, QPen
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QDial

# ------------------------------------------------------------------------------------------------------------
# Widget Class

class ScalableDial(QDial):
# enum CustomPaintMode
CUSTOM_PAINT_MODE_NULL = 0 # default (NOTE: only this mode has label gradient)
CUSTOM_PAINT_MODE_CARLA_WET = 1 # color blue-green gradient (reserved #3)
CUSTOM_PAINT_MODE_CARLA_VOL = 2 # color blue (reserved #3)
CUSTOM_PAINT_MODE_CARLA_L = 3 # color yellow (reserved #4)
CUSTOM_PAINT_MODE_CARLA_R = 4 # color yellow (reserved #4)
CUSTOM_PAINT_MODE_CARLA_PAN = 5 # color yellow (reserved #3)
CUSTOM_PAINT_MODE_COLOR = 6 # color, selectable (reserved #3)
CUSTOM_PAINT_MODE_ZITA = 7 # custom zita knob (reserved #6)
CUSTOM_PAINT_MODE_NO_GRADIENT = 8 # skip label gradient

# enum Orientation
HORIZONTAL = 0
VERTICAL = 1

HOVER_MIN = 0
HOVER_MAX = 9

MODE_DEFAULT = 0
MODE_LINEAR = 1

# signals
dragStateChanged = pyqtSignal(bool)
realValueChanged = pyqtSignal(float)

def __init__(self, parent, index=0):
QDial.__init__(self, parent)

self.fDialMode = self.MODE_LINEAR

self.fMinimum = 0.0
self.fMaximum = 1.0
self.fRealValue = 0.0
self.fPrecision = 10000
self.fIsInteger = False

self.fIsHovered = False
self.fIsPressed = False
self.fHoverStep = self.HOVER_MIN

self.fLastDragPos = None
self.fLastDragValue = 0.0

self.fIndex = index
self.fSvg = QSvgWidget(":/scalable/dial_03.svg")
self.fSvgNum = "01"

if self.fSvg.sizeHint().width() > self.fSvg.sizeHint().height():
self.fSvgOrientation = self.HORIZONTAL
else:
self.fSvgOrientation = self.VERTICAL

self.fLabel = ""
self.fLabelPos = QPointF(0.0, 0.0)
self.fLabelFont = QFont(self.font())
self.fLabelFont.setPixelSize(8)
self.fLabelWidth = 0
self.fLabelHeight = 0

if self.palette().window().color().lightness() > 100:
# Light background
c = self.palette().dark().color()
self.fLabelGradientColor1 = c
self.fLabelGradientColor2 = QColor(c.red(), c.green(), c.blue(), 0)
self.fLabelGradientColorT = [self.palette().buttonText().color(), self.palette().mid().color()]
else:
# Dark background
self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
self.fLabelGradientColorT = [Qt.white, Qt.darkGray]

self.fLabelGradient = QLinearGradient(0, 0, 0, 1)
self.fLabelGradient.setColorAt(0.0, self.fLabelGradientColor1)
self.fLabelGradient.setColorAt(0.6, self.fLabelGradientColor1)
self.fLabelGradient.setColorAt(1.0, self.fLabelGradientColor2)

self.fLabelGradientRect = QRectF(0.0, 0.0, 0.0, 0.0)

self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_NULL
self.fCustomPaintColor = QColor(0xff, 0xff, 0xff)

self.updateSizes()

# Fake internal value, custom precision
QDial.setMinimum(self, 0)
QDial.setMaximum(self, self.fPrecision)
QDial.setValue(self, 0)

self.valueChanged.connect(self.slot_valueChanged)

def getIndex(self):
return self.fIndex

def getBaseSize(self):
return self.fSvgBaseSize

def forceWhiteLabelGradientText(self):
self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
self.fLabelGradientColorT = [Qt.white, Qt.darkGray]

def setLabelColor(self, enabled, disabled):
self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
self.fLabelGradientColorT = [enabled, disabled]

def updateSizes(self):
self.fSvgWidth = self.fSvg.sizeHint().width()
self.fSvgHeight = self.fSvg.sizeHint().height()

if self.fSvgWidth < 1:
self.fSvgWidth = 1

if self.fSvgHeight < 1:
self.fSvgHeight = 1

if self.fSvgOrientation == self.HORIZONTAL:
self.fSvgBaseSize = self.fSvgHeight
self.fSvgLayersCount = self.fSvgWidth / self.fSvgHeight
else:
self.fSvgBaseSize = self.fSvgWidth
self.fSvgLayersCount = self.fSvgHeight / self.fSvgWidth

self.setMinimumSize(self.fSvgBaseSize, self.fSvgBaseSize + self.fLabelHeight + 5)
self.setMaximumSize(self.fSvgBaseSize, self.fSvgBaseSize + self.fLabelHeight + 5)

if not self.fLabel:
self.fLabelHeight = 0
self.fLabelWidth = 0
return

self.fLabelWidth = QFontMetrics(self.fLabelFont).width(self.fLabel)
self.fLabelHeight = QFontMetrics(self.fLabelFont).height()

self.fLabelPos.setX(float(self.fSvgBaseSize)/2.0 - float(self.fLabelWidth)/2.0)

if self.fSvgNum in ("01", "02", "07", "08", "09", "10"):
self.fLabelPos.setY(self.fSvgBaseSize + self.fLabelHeight)
elif self.fSvgNum in ("11",):
self.fLabelPos.setY(self.fSvgBaseSize + self.fLabelHeight*2/3)
else:
self.fLabelPos.setY(self.fSvgBaseSize + self.fLabelHeight/2)

self.fLabelGradient.setStart(0, float(self.fSvgBaseSize)/2.0)
self.fLabelGradient.setFinalStop(0, self.fSvgBaseSize + self.fLabelHeight + 5)

self.fLabelGradientRect = QRectF(float(self.fSvgBaseSize)/8.0, float(self.fSvgBaseSize)/2.0,
float(self.fSvgBaseSize*3)/4.0, self.fSvgBaseSize+self.fLabelHeight+5)

def setCustomPaintMode(self, paintMode):
if self.fCustomPaintMode == paintMode:
return

self.fCustomPaintMode = paintMode
self.update()

def setCustomPaintColor(self, color):
if self.fCustomPaintColor == color:
return

self.fCustomPaintColor = color
self.update()

def setLabel(self, label):
if self.fLabel == label:
return

self.fLabel = label
self.updateSizes()
self.update()

def setIndex(self, index):
self.fIndex = index

def setSvg(self, SvgId):
self.fSvgNum = "%02i" % SvgId
self.fSvg.load(":/scalable/dial_%s%s.svg" % (self.fSvgNum, "" if self.isEnabled() else "d"))

if self.fSvg.width() > self.fSvg.height():
self.fSvgOrientation = self.HORIZONTAL
else:
self.fSvgOrientation = self.VERTICAL

# special svg
if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
# reserved for carla-wet, carla-vol, carla-pan and color
if self.fSvgNum == "03":
self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_COLOR

# reserved for carla-L and carla-R
elif self.fSvgNum == "04":
self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_CARLA_L

# reserved for zita
elif self.fSvgNum == "06":
self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_ZITA

self.updateSizes()
self.update()

def setPrecision(self, value, isInteger):
self.fPrecision = value
self.fIsInteger = isInteger
QDial.setMaximum(self, value)

def setMinimum(self, value):
self.fMinimum = value

def setMaximum(self, value):
self.fMaximum = value

def setValue(self, value, emitSignal=False):
if self.fRealValue == value:
return

if value <= self.fMinimum:
qtValue = 0
self.fRealValue = self.fMinimum

elif value >= self.fMaximum:
qtValue = self.fPrecision
self.fRealValue = self.fMaximum

else:
qtValue = round(float(value - self.fMinimum) / float(self.fMaximum - self.fMinimum) * self.fPrecision)
self.fRealValue = value

# Block change signal, we'll handle it ourselves
self.blockSignals(True)
QDial.setValue(self, qtValue)
self.blockSignals(False)

if emitSignal:
self.realValueChanged.emit(self.fRealValue)

@pyqtSlot(int)
def slot_valueChanged(self, value):
self.fRealValue = float(value)/self.fPrecision * (self.fMaximum - self.fMinimum) + self.fMinimum
self.realValueChanged.emit(self.fRealValue)

@pyqtSlot()
def slot_updateSvg(self):
self.seSvg(int(self.fSvgNum))

def minimumSizeHint(self):
return QSize(self.fSvgBaseSize, self.fSvgBaseSize)

def sizeHint(self):
return QSize(self.fSvgBaseSize, self.fSvgBaseSize)

def changeEvent(self, event):
QDial.changeEvent(self, event)

# Force svg update if enabled state changes
if event.type() == QEvent.EnabledChange:
self.setSvg(int(self.fSvgNum))

def enterEvent(self, event):
self.fIsHovered = True
if self.fHoverStep == self.HOVER_MIN:
self.fHoverStep = self.HOVER_MIN + 1
QDial.enterEvent(self, event)

def leaveEvent(self, event):
self.fIsHovered = False
if self.fHoverStep == self.HOVER_MAX:
self.fHoverStep = self.HOVER_MAX - 1
QDial.leaveEvent(self, event)

def mousePressEvent(self, event):
if self.fDialMode == self.MODE_DEFAULT:
return QDial.mousePressEvent(self, event)

if event.button() == Qt.LeftButton:
self.fIsPressed = True
self.fLastDragPos = event.pos()
self.fLastDragValue = self.fRealValue
self.dragStateChanged.emit(True)

def mouseMoveEvent(self, event):
if self.fDialMode == self.MODE_DEFAULT:
return QDial.mouseMoveEvent(self, event)

if not self.fIsPressed:
return

range = (self.fMaximum - self.fMinimum) / 4.0
pos = event.pos()
dx = range * float(pos.x() - self.fLastDragPos.x()) / self.width()
dy = range * float(pos.y() - self.fLastDragPos.y()) / self.height()
value = self.fLastDragValue + dx - dy

if value < self.fMinimum:
value = self.fMinimum
elif value > self.fMaximum:
value = self.fMaximum
elif self.fIsInteger:
value = float(round(value))

self.setValue(value, True)

def mouseReleaseEvent(self, event):
if self.fDialMode == self.MODE_DEFAULT:
return QDial.mouseReleaseEvent(self, event)

if self.fIsPressed:
self.fIsPressed = False
self.dragStateChanged.emit(False)

def paintEvent(self, event):
painter = QPainter(self)
event.accept()

painter.save()
painter.setRenderHint(QPainter.Antialiasing, True)

if self.fLabel:
if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
painter.setPen(self.fLabelGradientColor2)
painter.setBrush(self.fLabelGradient)
painter.drawRect(self.fLabelGradientRect)

painter.setFont(self.fLabelFont)
painter.setPen(self.fLabelGradientColorT[0 if self.isEnabled() else 1])
painter.drawText(self.fLabelPos, self.fLabel)

if self.isEnabled():
normValue = float(self.fRealValue - self.fMinimum) / float(self.fMaximum - self.fMinimum)
curLayer = int((self.fSvgLayersCount - 1) * normValue)

if self.fSvgOrientation == self.HORIZONTAL:
xpos = self.fSvgBaseSize * curLayer
ypos = 0.0
else:
xpos = 0.0
ypos = self.fSvgBaseSize * curLayer

source = QRectF(xpos, ypos, self.fSvgBaseSize, self.fSvgBaseSize)
self.fSvg.renderer().render(painter, source)

# Custom knobs (Dry/Wet and Volume)
if self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_WET, self.CUSTOM_PAINT_MODE_CARLA_VOL):
# knob color
colorGreen = QColor(0x5D, 0xE7, 0x3D).lighter(100 + self.fHoverStep*6)
colorBlue = QColor(0x3E, 0xB8, 0xBE).lighter(100 + self.fHoverStep*6)

# draw small circle
ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
ballPath = QPainterPath()
ballPath.addEllipse(ballRect)
#painter.drawRect(ballRect)
tmpValue = (0.375 + 0.75*normValue)
ballValue = tmpValue - floor(tmpValue)
ballPoint = ballPath.pointAtPercent(ballValue)

# draw arc
startAngle = 220*16
spanAngle = -258*16*normValue

if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_WET:
painter.setBrush(colorBlue)
painter.setPen(QPen(colorBlue, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

gradient = QConicalGradient(15.5, 15.5, -45)
gradient.setColorAt(0.0, colorBlue)
gradient.setColorAt(0.125, colorBlue)
gradient.setColorAt(0.625, colorGreen)
gradient.setColorAt(0.75, colorGreen)
gradient.setColorAt(0.76, colorGreen)
gradient.setColorAt(1.0, colorGreen)
painter.setBrush(gradient)
painter.setPen(QPen(gradient, 3))

else:
painter.setBrush(colorBlue)
painter.setPen(QPen(colorBlue, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

painter.setBrush(colorBlue)
painter.setPen(QPen(colorBlue, 3))

painter.drawArc(2.0, 2.0, 30.5, 30.5, startAngle, spanAngle)

# Custom knobs (L and R)
elif self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_L, self.CUSTOM_PAINT_MODE_CARLA_R):
# knob color
color = QColor(0xAD, 0xD5, 0x48).lighter(100 + self.fHoverStep*6)

# draw small circle
ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
ballPath = QPainterPath()
ballPath.addEllipse(ballRect)
#painter.drawRect(ballRect)
tmpValue = (0.375 + 0.75*normValue)
ballValue = tmpValue - floor(tmpValue)
ballPoint = ballPath.pointAtPercent(ballValue)

painter.setBrush(color)
painter.setPen(QPen(color, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0))

# draw arc
if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_L:
startAngle = 220*16
spanAngle = -258.0*16*normValue
else:
startAngle = 320.0*16
spanAngle = 262.0*16*(1.0-normValue)

painter.setPen(QPen(color, 2))
painter.drawArc(2, 2.0, 24.0, 24.0, startAngle, spanAngle)

# Custom knobs (Color)
elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_COLOR:
# knob color
color = self.fCustomPaintColor.lighter(100 + self.fHoverStep*6)

# draw small circle
ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
ballPath = QPainterPath()
ballPath.addEllipse(ballRect)
tmpValue = (0.375 + 0.75*normValue)
ballValue = tmpValue - floor(tmpValue)
ballPoint = ballPath.pointAtPercent(ballValue)

# draw arc
startAngle = 220*16
spanAngle = -258*16*normValue

painter.setBrush(color)
painter.setPen(QPen(color, 0))
painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

painter.setBrush(color)
painter.setPen(QPen(color, 3))
painter.drawArc(2.0, 2.0, 30.5, 30.5, startAngle, spanAngle)

# Custom knobs (Zita)
elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_ZITA:
a = normValue * pi * 1.5 - 2.35
r = 10.0
x = 10.5
y = 10.5
x += r * sin(a)
y -= r * cos(a)
painter.setBrush(Qt.black)
painter.setPen(QPen(Qt.black, 2))
painter.drawLine(QPointF(11.0, 11.0), QPointF(x, y))

# Custom knobs
else:
painter.restore()
return

if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
self.fHoverStep += 1 if self.fIsHovered else -1
QTimer.singleShot(20, self.update)

else: # isEnabled()
target = QRectF(0.0, 0.0, self.fSvgBaseSize, self.fSvgBaseSize)
self.fSvg.renderer().render(painter, target)

painter.restore()

def resizeEvent(self, event):
QDial.resizeEvent(self, event)
self.updateSizes()

# ------------------------------------------------------------------------------------------------------------
# Main Testing

if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
import resources_rc

app = QApplication(sys.argv)
gui = ScalableDial(None)
#gui.setEnabled(True)
#gui.setEnabled(False)
gui.setSvg(3)
gui.setLabel("hahaha")
gui.show()

sys.exit(app.exec_())

Loading…
Cancel
Save