From 3f9d4f80968a407e18a139976273a946c59fcd8d Mon Sep 17 00:00:00 2001 From: falkTX Date: Mon, 2 Feb 2015 03:22:12 +0000 Subject: [PATCH] Plugin skin work, start of style merging and compact mode --- Makefile | 3 + resources/bitmaps/dial_14.png | Bin 0 -> 84190 bytes resources/bitmaps/dial_14d.png | Bin 0 -> 1726 bytes resources/resources.qrc | 2 + resources/ui/carla_plugin_basic_fx.ui | 459 ++++++------- resources/ui/carla_plugin_compact.ui | 417 +++++++++++ resources/ui/carla_plugin_default.ui | 3 + resources/ui/carla_plugin_zynfx.ui | 604 ++++++++-------- source/carla_host.py | 42 +- source/carla_skin.py | 950 +++++++++++++------------- source/widgets/digitalpeakmeter.py | 27 +- source/widgets/racklistwidget.py | 86 ++- 12 files changed, 1487 insertions(+), 1106 deletions(-) create mode 100644 resources/bitmaps/dial_14.png create mode 100644 resources/bitmaps/dial_14d.png create mode 100644 resources/ui/carla_plugin_compact.ui mode change 100644 => 100755 source/carla_skin.py diff --git a/Makefile b/Makefile index 071cbb20e..ad2847d25 100644 --- a/Makefile +++ b/Makefile @@ -282,6 +282,7 @@ RES = \ bin/resources/ui_carla_parameter.py \ bin/resources/ui_carla_plugin_basic_fx.py \ bin/resources/ui_carla_plugin_calf.py \ + bin/resources/ui_carla_plugin_compact.py \ bin/resources/ui_carla_plugin_default.py \ bin/resources/ui_carla_plugin_sf2.py \ bin/resources/ui_carla_plugin_zynfx.py \ @@ -327,6 +328,7 @@ UIs = \ source/ui_carla_parameter.py \ source/ui_carla_plugin_basic_fx.py \ source/ui_carla_plugin_calf.py \ + source/ui_carla_plugin_compact.py \ source/ui_carla_plugin_default.py \ source/ui_carla_plugin_sf2.py \ source/ui_carla_plugin_zynfx.py \ @@ -573,6 +575,7 @@ endif $(LINK) $(PREFIX)/share/carla/ui_carla_parameter.py $(DESTDIR)$(PREFIX)/share/carla/resources/ $(LINK) $(PREFIX)/share/carla/ui_carla_plugin_basic_fx.py $(DESTDIR)$(PREFIX)/share/carla/resources/ $(LINK) $(PREFIX)/share/carla/ui_carla_plugin_calf.py $(DESTDIR)$(PREFIX)/share/carla/resources/ + $(LINK) $(PREFIX)/share/carla/ui_carla_plugin_compact.py $(DESTDIR)$(PREFIX)/share/carla/resources/ $(LINK) $(PREFIX)/share/carla/ui_carla_plugin_default.py $(DESTDIR)$(PREFIX)/share/carla/resources/ $(LINK) $(PREFIX)/share/carla/ui_carla_plugin_sf2.py $(DESTDIR)$(PREFIX)/share/carla/resources/ $(LINK) $(PREFIX)/share/carla/ui_carla_plugin_zynfx.py $(DESTDIR)$(PREFIX)/share/carla/resources/ diff --git a/resources/bitmaps/dial_14.png b/resources/bitmaps/dial_14.png new file mode 100644 index 0000000000000000000000000000000000000000..fdda04a775bfbc06227e9c458d0dc5ae40da7ee3 GIT binary patch literal 84190 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%0As$=!T&rAH=duazW#h~!w9=Q>R##Zj; zpir?O^aEK!{ptcuiSNvg>iHybIy*QoelIGv@P$+^0n3aiAPT$QIE}7MSxt3o1x3E2 z%kVV#nCkRC1kK4gO8tu_1OXhjWm z@IH#y5n}W%gMiw_@GcE-xdJ~evm3*I(m(`<0byQkAy?v%uNkh`vEKZJnC&-z<9mdT`{W%{Al{_<)mTDX*a~d`APQfg`hQkdhr6QG@=~(P6qCGsr@Ed7nI!C%G^6Nj}IJPB)pvdv6 zqVpYx_XYWIftg;O?czNin5W9Wn8Nq0ln72;QZD6j4KD*n2>4K0(! zy1523g$FA{{Jm@R;JRMvp2OdgEV-3+U-6xgjsU_H_G@M7zfM9*-R#u5VN;{_Y9^Y? zLOOkq>6u;#-Xra|md#8F7lhBr*W;e!s>xAehV7aLdQWi{o|y+xq>Kj_D+V`QXA(9; z=o&jjk|uGc&3?5JT-Jk-~)LWXQi;!h~5#a@a(?=dEj_jRx$+uX!2$}ql{!5IM zv2?FUv3|ule41mYTkO{(Pb_3k9laBWCSh}baCl6jO*qU;#%JDfxiWlPkQ zuzsojXQsq zob9ood)T`og)^?`Ha~t!zh($-F@;R@lhKp2k^g8V@8J!!mU#Pcx-zxJ#_Pc*SgzCT zb7fcDrj}~%EeH?1^ML-Yzz+1XSu1qa^n4S+F;0AzoDdxF#{!9o-22hAMsI1lI3@%lVnOK5b^oZ@=?KkJP>3oKPKM)zJxfWIkl)4~!Oj#f|h#9IG z!mEkHy5`na3Z`nawQ|!LM5>U#BIN(I04Ihv*@*e!cfBH<`eDP+PSvw08&*cLKri@C zfVzzL3c}^n#x?s@mb&p$WgQPh(CVrANXZjY9=YoSWcakkeqPxI9cI6Jc(9%Sg)bY* zbgk~uRR5<8q=g8XQ8G&(iOpOHXCNIUys*0ctS7D0iuc9Pjv5^UeV*#NyF0Um3e zvh>_1D(6dgp0zng3`u1EYM#+#?>EV$B%ofsqaZY>Ph<+w8G>X zAt+sVXY6U|eLP6??ZcsvVNjx(aKP*$T<&4)O?yGbDrY)_B2uX!Xgcb_9V&iml}xPO zz)T3lE4Z57>D~LZH5#^(7RU;sqK^ zyU$K~0_wkXzX)An&jPJTjj->0#{dm%R!E%giyJM*A=t>g>q1s)Hr9>lgnEz_gca&G zPS1KJ@+Uxx@J&MO3M)^w1YGFsJ4NEjH4{yXj|@_LQKM!cb4 pH0LEz$?)QBx>u5 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/dial_12d.png bitmaps/dial_13.png bitmaps/dial_13d.png + bitmaps/dial_14.png + bitmaps/dial_14d.png bitmaps/kbd_h_dark.png bitmaps/kbd_v_dark.png diff --git a/resources/ui/carla_plugin_basic_fx.ui b/resources/ui/carla_plugin_basic_fx.ui index 8a20da087..f3d230114 100644 --- a/resources/ui/carla_plugin_basic_fx.ui +++ b/resources/ui/carla_plugin_basic_fx.ui @@ -6,8 +6,8 @@ 0 0 - 338 - 71 + 552 + 60 @@ -16,157 +16,212 @@ Frame + + 0 + - 1 + 0 - 2 + 4 3 - 2 + 6 - 0 + 3 - + 1 - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 1 - - - - - - + - 24 + 72 24 - 24 - 24 - - - - - - - - :/bitmaps/button_off.png:/bitmaps/button_off.png - - - - 24 + 72 24 - - true - - - true - + + + 0 + + + 0 + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_off.png:/bitmaps/button_off.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_gui.png:/bitmaps/button_gui.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_edit.png:/bitmaps/button_edit.png + + + + 24 + 24 + + + + true + + + true + + + + - - - - 24 - 24 - - - - - 24 - 24 - - - - + + + Qt::Horizontal - - - :/bitmaps/button_gui.png:/bitmaps/button_gui.png + + QSizePolicy::Fixed - + - 24 - 24 + 6 + 1 - - true - - - true - - + - + - 24 - 24 + 0 + 20 - 24 - 24 + 16777215 + 20 - - - - - - :/bitmaps/button_edit.png:/bitmaps/button_edit.png - - - - 24 - 24 - + + 0 - - true + + 1 - - true + + Qt::Vertical - + Qt::Horizontal + + QSizePolicy::Fixed + - 40 - 20 + 8 + 1 @@ -177,23 +232,74 @@ PluginName - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + Qt::Horizontal - 40 - 20 + 20 + 1 + + + + 4 + + + 4 + + + 2 + + + 4 + + + 2 + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + + + @@ -289,22 +395,6 @@ - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 1 - - - - @@ -321,36 +411,26 @@ - + - 10 + 1 + + + 12 - 2 + 4 + + + 10 - - - - 20 - 0 - - - - - 20 - 16777215 - - - - - - + - + Qt::Horizontal @@ -363,102 +443,8 @@ - - - - 34 - 34 - - - - - 34 - 34 - - - - - - - - - 34 - 34 - - - - - 34 - 34 - - - - - - - - 1 - - - 0 - - - 0 - - - 0 - - - 4 - - - - - - 150 - 0 - - - - - 150 - 16777215 - - - - - - - - - 150 - 0 - - - - - 150 - 16777215 - - - - - - - - - - - 20 - 0 - - - - - 20 - 16777215 - - + + @@ -482,11 +468,6 @@ QPushButton
pixmapbutton.h
- - PixmapDial - QDial -
pixmapdial.h
-
diff --git a/resources/ui/carla_plugin_compact.ui b/resources/ui/carla_plugin_compact.ui new file mode 100644 index 000000000..ec1834710 --- /dev/null +++ b/resources/ui/carla_plugin_compact.ui @@ -0,0 +1,417 @@ + + + PluginWidget + + + + 0 + 0 + 425 + 30 + + + + Qt::CustomContextMenu + + + Frame + + + 0 + + + + 1 + + + 4 + + + 3 + + + 6 + + + 3 + + + + + + 72 + 24 + + + + + 72 + 24 + + + + + 0 + + + 0 + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_off.png:/bitmaps/button_off.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_gui.png:/bitmaps/button_gui.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_edit.png:/bitmaps/button_edit.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 6 + 1 + + + + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + 0 + + + 1 + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 8 + 1 + + + + + + + + PluginName + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 19 + 1 + + + + + + + + 4 + + + 4 + + + 2 + + + 4 + + + 2 + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + + + + + + + 1 + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + + + + + + + + DigitalPeakMeter + QWidget +
digitalpeakmeter.h
+ 1 +
+ + LEDButton + QPushButton +
ledbutton.h
+
+ + PixmapButton + QPushButton +
pixmapbutton.h
+
+
+ + + + +
diff --git a/resources/ui/carla_plugin_default.ui b/resources/ui/carla_plugin_default.ui index 28bead933..4795d0954 100644 --- a/resources/ui/carla_plugin_default.ui +++ b/resources/ui/carla_plugin_default.ui @@ -16,6 +16,9 @@ Frame + + 0 + 2 diff --git a/resources/ui/carla_plugin_zynfx.ui b/resources/ui/carla_plugin_zynfx.ui index 9ad8124f8..5704953fc 100644 --- a/resources/ui/carla_plugin_zynfx.ui +++ b/resources/ui/carla_plugin_zynfx.ui @@ -6,8 +6,8 @@ 0 0 - 559 - 75 + 484 + 65 @@ -24,116 +24,156 @@ - 1 + 0 - 2 + 4 3 - 2 + 6 - 0 + 3 - + 1 - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 1 - - - - - + - 24 + 72 24 - 24 + 72 24 - - - - - - :/bitmaps/button_off.png:/bitmaps/button_off.png - - - - 24 - 24 - - - - true - - - true - + + + 0 + + + 0 + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_off.png:/bitmaps/button_off.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_gui.png:/bitmaps/button_gui.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/bitmaps/button_edit.png:/bitmaps/button_edit.png + + + + 24 + 24 + + + + true + + + true + + + + - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - :/bitmaps/button_edit.png:/bitmaps/button_edit.png - - - - 24 - 24 - - - - true - - - true - - - - - + Qt::Horizontal @@ -142,57 +182,49 @@ - 10 - 10 + 6 + 1 - - - Preset: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - + + - 3 - 10 + 0 + 20 - - - - - + - 125 - 0 + 16777215 + 20 + + 0 + + + 1 + + + Qt::Vertical + - + Qt::Horizontal + + QSizePolicy::Fixed + - 40 - 20 + 8 + 1 @@ -211,143 +243,145 @@ - + Qt::Horizontal - 40 - 20 + 20 + 1 - - - - 160 - 0 - - - - - 160 - 16777215 - - - - - - - Qt::AlignCenter - - - - - - - - 14 - 14 - - - - - 14 - 14 - - - - - - - true - - - - - - - - 14 - 14 - - - - - 14 - 14 - - - - - - - true - - - - - - - - 14 - 14 - - - - - 14 - 14 - - - - - - - true - - - - - - - - 14 - 14 - - - - - 14 - 14 - + + + 4 - - + + 4 - - true + + 4 - + + + + Preset: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 125 + 0 + + + + + - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 1 - + + + 1 - + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + true + + + +
@@ -365,36 +399,26 @@ - + - 10 + 1 + + + 12 - 2 + 4 + + + 10 - - - - 20 - 0 - - - - - 20 - 16777215 - - - - - - + - + Qt::Horizontal @@ -407,53 +431,26 @@ - - - - 34 - 34 - - - - - 34 - 34 - - - - - - - - - 34 - 34 - - - - - 34 - 34 - - + + - + - 1 + 4 - 0 + 4 - 0 + 2 - 0 + 4 - 4 + 2 @@ -489,22 +486,6 @@ - - - - - 20 - 0 - - - - - 20 - 16777215 - - - - @@ -526,11 +507,6 @@ QPushButton
pixmapbutton.h
- - PixmapDial - QDial -
pixmapdial.h
-
diff --git a/source/carla_host.py b/source/carla_host.py index 2b0d0cdea..b41167419 100644 --- a/source/carla_host.py +++ b/source/carla_host.py @@ -128,12 +128,6 @@ class HostWindow(QMainWindow): self.fClientName = CARLA_CLIENT_NAME or "Carla" self.fSessionManagerName = "" - # ---------------------------------------------------------------------------------------------------- - # Internal stuff (rack) - - self.fCurrentRow = -1 - self.fLastSelectedItem = None - # ---------------------------------------------------------------------------------------------------- # Internal stuff (patchbay) @@ -239,8 +233,6 @@ class HostWindow(QMainWindow): self.ui.rackScrollBar.rangeChanged.connect(sb.setRange) self.ui.rackScrollBar.valueChanged.connect(sb.setValue) - self.ui.listWidget.currentRowChanged.connect(self.slot_currentRowChanged) - self.ui.rack.setStyleSheet(""" QLabel#pad_left { background-image: url(:/bitmaps/rack_padding_left.png); @@ -420,6 +412,17 @@ class HostWindow(QMainWindow): # -------------------------------------------------------------------------------------------------------- # Setup + def compactPlugin(self, pluginId): + if pluginId > self.fPluginCount: + return + + pitem = self.fPluginList[pluginId] + + if pitem is None: + return + + pitem.recreateWidget(True) + def setLoadRDFsNeeded(self): self.fLadspaRdfNeedsUpdate = True @@ -1505,24 +1508,6 @@ class HostWindow(QMainWindow): vsb.setValue(yp * vsb.maximum()) self.updateCanvasInitialPos() - # -------------------------------------------------------------------------------------------------------- - # Rack stuff - - @pyqtSlot(int) - def slot_currentRowChanged(self, row): - self.fCurrentRow = row - - if self.fLastSelectedItem is not None: - self.fLastSelectedItem.setSelected(False) - - if row < 0 or row >= self.fPluginCount or self.fPluginList[row] is None: - self.fLastSelectedItem = None - return - - pitem = self.fPluginList[row] - pitem.getWidget().setSelected(True) - self.fLastSelectedItem = pitem.getWidget() - # -------------------------------------------------------------------------------------------------------- # Timers @@ -1574,10 +1559,7 @@ class HostWindow(QMainWindow): if pitem is None: return - self.ui.listWidget.setCurrentRow(-1) - self.fCurrentRow = -1 - self.fLastSelectedItem = None - + self.ui.listWidget.customClearSelection() pitem.recreateWidget() # -------------------------------------------------------------------------------------------------------- diff --git a/source/carla_skin.py b/source/carla_skin.py old mode 100644 new mode 100755 index 0096ddfef..e70f2741e --- a/source/carla_skin.py +++ b/source/carla_skin.py @@ -38,6 +38,7 @@ else: import ui_carla_plugin_default import ui_carla_plugin_basic_fx import ui_carla_plugin_calf +import ui_carla_plugin_compact import ui_carla_plugin_sf2 import ui_carla_plugin_zynfx @@ -45,6 +46,33 @@ from carla_widgets import * from digitalpeakmeter import DigitalPeakMeter from pixmapdial import PixmapDial +# ------------------------------------------------------------------------------------------------------------ +# Plugin Skin Rules + +# Base is a QFrame (NoFrame, Plain, 0-size lines), with "PluginWidget" as object name. +# Spacing of the top-most layout must be 1px. +# Top and bottom margins must be 3px (can be splitted between different qt layouts). +# Left and right margins must be 6px (can be splitted between different qt layouts). +# If the left or right side has built-in margins, say a transparent png border, +# those margins must be taken into consideration. +# +# There's a top and bottom layout, separated by a horizontal line. +# Compacted skins do not have the bottom layout and separating line. + +# T O P A R E A +# +# ----------------------------------------------------------------- +# | <> | <> [ WIDGETS ] [ LEDS ] | +# | BUTTONS <> | <> PLUGIN NAME < spacer > [ WIDGETS ] [ LEDS ] | +# | <> | <> [ WIDGETS ] [ LEDS ] | +# ----------------------------------------------------------------- +# +# Buttons area has size fixed. (TBA) +# Spacers at the left of the plugin name must be 8x1 in size (fixed). +# The line before the plugin name must be height-10px (fixed). +# WIDGETS area can be extended to the left, if using meters they should have 80px. +# WIDGETS margins are 4px for left+right and 2px for top+bottom, with 4px spacing. + # ------------------------------------------------------------------------------------------------------------ # Try to "shortify" a parameter name @@ -107,12 +135,62 @@ def getParameterShortName(paramName): return paramName.strip() +# ------------------------------------------------------------------------------------------------------------ +# Get RGB colors for a plugin category + +def getColorFromCategory(category): + r = 40 + g = 40 + b = 40 + + if category == PLUGIN_CATEGORY_MODULATOR: + r += 10 + elif category == PLUGIN_CATEGORY_EQ: + g += 10 + elif category == PLUGIN_CATEGORY_FILTER: + b += 10 + elif category == PLUGIN_CATEGORY_DELAY: + r += 15 + b -= 15 + elif category == PLUGIN_CATEGORY_DISTORTION: + g += 10 + b += 10 + elif category == PLUGIN_CATEGORY_DYNAMICS: + r += 10 + b += 10 + elif category == PLUGIN_CATEGORY_UTILITY: + r += 10 + g += 10 + + return (r, g, b) + +def getModColorFromCategory(category): + if category == PLUGIN_CATEGORY_NONE: + return (40, 40, 40) + if category == PLUGIN_CATEGORY_SYNTH: + return (30, 150, 49) + if category == PLUGIN_CATEGORY_DELAY: + return (47, 47, 47) + if category in (PLUGIN_CATEGORY_EQ, PLUGIN_CATEGORY_FILTER): + return (255, 220, 25) + if category == PLUGIN_CATEGORY_DISTORTION: + return (255, 127, 25) + if category == PLUGIN_CATEGORY_DYNAMICS: + return (255, 25, 25) + if category == PLUGIN_CATEGORY_MODULATOR: + return (109, 31, 142) + if category == PLUGIN_CATEGORY_UTILITY: + return (95, 95, 95) + if category == PLUGIN_CATEGORY_OTHER: + return (92, 210, 254) + return (40, 40, 40) + # ------------------------------------------------------------------------------------------------------------ # Abstract plugin slot class AbstractPluginSlot(QFrame, PluginEditParentMeta): #class AbstractPluginSlot(QFrame, PluginEditParentMeta, metaclass=PyQtMetaClass): - def __init__(self, parent, host, pluginId): + def __init__(self, parent, host, pluginId, skinStyle): QFrame.__init__(self, parent) self.host = host @@ -126,6 +204,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): self.fPluginId = pluginId self.fPluginInfo = host.get_plugin_info(self.fPluginId) + self.fSkinStyle = skinStyle #if not gCarla.isLocal: #self.fPluginInfo['hints'] &= ~PLUGIN_HAS_CUSTOM_UI @@ -133,9 +212,8 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): # ------------------------------------------------------------- # Internal stuff - self.fIsActive = bool(host.get_internal_parameter_value(self.fPluginId, PARAMETER_ACTIVE) >= 0.5) - self.fIsCollapsed = False - self.fIsSelected = False + self.fIsActive = bool(host.get_internal_parameter_value(self.fPluginId, PARAMETER_ACTIVE) >= 0.5) + self.fIsSelected = False self.fLastGreenLedState = False self.fLastBlueLedState = False @@ -172,16 +250,15 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): self.cb_presets = None - self.label_name = None - self.label_type = None + self.label_name = None + self.label_presets = None + self.label_type = None self.led_control = None self.led_midi = None self.led_audio_in = None self.led_audio_out = None - self.line = None - self.peak_in = None self.peak_out = None @@ -236,7 +313,6 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): if self.fPluginId == pluginId: self.setProgram(index, True) - @pyqtSlot(int, int) def slot_handleMidiProgramChangedCallback(self, pluginId, index): if self.fPluginId == pluginId: @@ -259,18 +335,38 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): self.b_enable.setChecked(self.fIsActive) self.b_enable.clicked.connect(self.slot_enableClicked) + if "calf" in self.fSkinStyle and not isinstance(self, PluginSlot_Compact): + self.b_enable.setPixmaps(":/bitmaps/button_calf3.png", ":/bitmaps/button_calf3_down.png", ":/bitmaps/button_calf3.png") + else: + self.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png") + 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 self.b_edit is None: - # Edit dialog *must* be available + if "calf" in self.fSkinStyle and not isinstance(self, PluginSlot_Compact): + 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"): + self.b_gui.setPixmaps(":/bitmaps/button_distrho.png", ":/bitmaps/button_distrho_down.png", ":/bitmaps/button_distrho_hover.png") + elif self.fPluginInfo['iconName'] == "file": + self.b_gui.setPixmaps(":/bitmaps/button_file.png", ":/bitmaps/button_file_down.png", ":/bitmaps/button_file_hover.png") + else: + self.b_gui.setPixmaps(":/bitmaps/button_gui.png", ":/bitmaps/button_gui_down.png", ":/bitmaps/button_gui_hover.png") + + if self.b_edit is not None: + self.b_edit.clicked.connect(self.slot_showEditDialog) + + if "calf" in self.fSkinStyle and not isinstance(self, PluginSlot_Compact): + self.b_edit.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png") + else: + self.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png") + + else: + # Edit button *must* be available self.b_edit = QPushButton(self) self.b_edit.setCheckable(True) self.b_edit.hide() - self.b_edit.clicked.connect(self.slot_showEditDialog) - if self.b_remove is not None: self.b_remove.clicked.connect(self.slot_removePlugin) @@ -278,6 +374,30 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): self.label_name.setEnabled(self.fIsActive) self.label_name.setText(self.fPluginInfo['name']) + nameFont = self.label_name.font() + + if self.fSkinStyle == "openav": + QFontDatabase.addApplicationFont(":/fonts/uranium.ttf") + nameFont.setFamily("Uranium") + nameFont.setPointSize(13) + nameFont.setCapitalization(QFont.AllUppercase) + + elif "calf" in self.fSkinStyle: + nameFont.setBold(True) + nameFont.setPointSize(10) + + else: + nameFont.setBold(True) + nameFont.setPointSize(9) + + self.label_name.setFont(nameFont) + + if self.label_presets is not None: + presetFont = self.label_presets.font() + presetFont.setBold(True) + presetFont.setPointSize(8) + self.label_presets.setFont(presetFont) + if self.label_type is not None: self.label_type.setText(getPluginTypeAsString(self.fPluginInfo['type'])) @@ -301,19 +421,31 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): self.peak_in.setChannelCount(self.fPeaksInputCount) self.peak_in.setMeterColor(DigitalPeakMeter.COLOR_GREEN) self.peak_in.setMeterOrientation(DigitalPeakMeter.HORIZONTAL) - if (self.fPeaksInputCount == 0 and not isinstance(self, PluginSlot_Default)) or self.fIsCollapsed: + + if "calf" in self.fSkinStyle: + self.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_CALF) + elif self.fSkinStyle == "rncbc": + self.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_RNCBC) + elif self.fSkinStyle in ("mod", "openav", "zynfx"): + self.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV) + + if self.fPeaksInputCount == 0 and not isinstance(self, PluginSlot_Default): self.peak_in.hide() if self.peak_out is not None: self.peak_out.setChannelCount(self.fPeaksOutputCount) self.peak_out.setMeterColor(DigitalPeakMeter.COLOR_BLUE) self.peak_out.setMeterOrientation(DigitalPeakMeter.HORIZONTAL) - if (self.fPeaksOutputCount == 0 and not isinstance(self, PluginSlot_Default)) or self.fIsCollapsed: - self.peak_out.hide() - if self.line is not None: - if self.fIsCollapsed: - self.line.hide() + if "calf" in self.fSkinStyle: + self.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_CALF) + elif self.fSkinStyle == "rncbc": + self.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_RNCBC) + elif self.fSkinStyle in ("mod", "openav", "zynfx"): + self.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV) + + if self.fPeaksOutputCount == 0 and not isinstance(self, PluginSlot_Default): + self.peak_out.hide() for paramIndex, paramWidget in self.fParameterList: paramWidget.setContextMenuPolicy(Qt.CustomContextMenu) @@ -321,8 +453,50 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): paramWidget.realValueChanged.connect(self.slot_parameterValueChanged) paramWidget.setValue(self.host.get_internal_parameter_value(self.fPluginId, paramIndex)) - if self.fIsCollapsed: - paramWidget.hide() + # ------------------------------------------------------------- + + if self.fSkinStyle == "mod": + styleSheet = """ + QFrame#PluginWidget { + background-color: rgb(%i, %i, %i); + } + QLabel#label_name { color: #FFFFFF; } + QLabel#label_name:disabled { color: #505050; } + """ % getModColorFromCategory(self.fPluginInfo['category']) + + elif self.fSkinStyle == "openav": + styleSheet = """ + QFrame#PluginWidget { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #303030, stop: %f #111111, stop: 1.0 #111111); + } + QLabel#label_name { color: #FF5100; } + QLabel#label_name:disabled { color: #505050; } + """ % (0.95 if isinstance(self, PluginSlot_Compact) else 0.35) + + else: + if self.fSkinStyle in ("3bandeq", "calf_black", "calf_blue", "nekobi", "zynfx"): + styleSheet2 = "background-image: url(:/bitmaps/background_%s.png);" % self.fSkinStyle + else: + styleSheet2 = "background-color: rgb(%i, %i, %i);" % getColorFromCategory(self.fPluginInfo['category']) + styleSheet2 += "background-image: url(:/bitmaps/background_noise1.png);" + + styleSheet = """ + QFrame#PluginWidget { + %s + background-repeat: repeat-xy; + } + QLabel#label_name, + QLabel#label_audio_in, + QLabel#label_audio_out, + QLabel#label_midi, + QLabel#label_presets { color: #BBB; } + QLabel#label_name:disabled { color: #555; } + """ % styleSheet2 + + self.setStyleSheet(styleSheet) + + # ------------------------------------------------------------- self.setWindowTitle(self.fPluginInfo['name']) @@ -636,32 +810,74 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): painter.setBrush(Qt.black) painter.drawLine(0, self.height()-1, self.width(), self.height()-1) - def showDefaultCustomMenu(self, isEnabled, bEdit = None, bGui = None): + def updateParameterValues(self): + for paramIndex, paramWidget in self.fParameterList: + if paramIndex < 0: + continue + + paramWidget.blockSignals(True) + paramWidget.setValue(self.host.get_current_parameter_value(self.fPluginId, paramIndex)) + paramWidget.blockSignals(False) + + #------------------------------------------------------------------ + + @pyqtSlot(bool) + def slot_enableClicked(self, yesNo): + self.setActive(yesNo, False, True) + + @pyqtSlot() + def slot_showDefaultCustomMenu(self): menu = QMenu(self) - actActive = menu.addAction(self.tr("Disable") if isEnabled else self.tr("Enable")) + # ------------------------------------------------------------- + # Expand/Minimize + + actCompact = menu.addAction(self.tr("Expand") if isinstance(self, PluginSlot_Compact) else self.tr("Minimize")) menu.addSeparator() + # ------------------------------------------------------------- + # Bypass and Enable/Disable + + actBypass = menu.addAction(self.tr("Bypass")) + actEnable = menu.addAction(self.tr("Disable") if self.fIsActive else self.tr("Enable")) + menu.addSeparator() + + if self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET: + actBypass.setCheckable(True) + actBypass.setChecked(self.host.get_internal_parameter_value(self.fPluginId, PARAMETER_DRYWET) == 0.0) + else: + actBypass.setVisible(False) + + # ------------------------------------------------------------- + # Reset and Randomize parameters + actReset = menu.addAction(self.tr("Reset parameters")) actRandom = menu.addAction(self.tr("Randomize parameters")) menu.addSeparator() - if bEdit is not None: - actEdit = menu.addAction(self.tr("Edit")) + # ------------------------------------------------------------- + # Edit and Show Custom UI + + actEdit = menu.addAction(self.tr("Edit")) + actGui = menu.addAction(self.tr("Show Custom UI")) + menu.addSeparator() + + if self.b_edit is not None: actEdit.setCheckable(True) - actEdit.setChecked(bEdit.isChecked()) + actEdit.setChecked(self.b_edit.isChecked()) else: - actEdit = None + actEdit.setVisible(False) - if bGui is not None: - actGui = menu.addAction(self.tr("Show Custom UI")) + if self.b_gui is not None: actGui.setCheckable(True) - actGui.setChecked(bGui.isChecked()) - actGui.setEnabled(bGui.isEnabled()) + actGui.setChecked(self.b_gui.isChecked()) + actGui.setEnabled(self.b_gui.isEnabled()) else: - actGui = None + actGui.setVisible(False) + + # ------------------------------------------------------------- + # Other stuff - menu.addSeparator() actClone = menu.addAction(self.tr("Clone")) actReplace = menu.addAction(self.tr("Replace...")) actRename = menu.addAction(self.tr("Rename...")) @@ -670,13 +886,34 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): if self.fIdleTimerId != 0: actRemove.setVisible(False) + # ------------------------------------------------------------- + # exec + actSel = menu.exec_(QCursor.pos()) if not actSel: return - if actSel == actActive: - self.setActive(not isEnabled, True, True) + # ------------------------------------------------------------- + # Expand/Minimize + + elif actSel == actCompact: + # FIXME + gCarla.gui.compactPlugin(self.fPluginId) + + # ------------------------------------------------------------- + # Bypass and Enable/Disable + + elif actSel == actBypass: + value = 0.0 if actBypass.isChecked() else 1.0 + self.host.set_drywet(self.fPluginId, value) + self.setParameterValue(PARAMETER_DRYWET, value, True) + + elif actSel == actEnable: + self.setActive(not self.fIsActive, True, True) + + # ------------------------------------------------------------- + # Reset and Randomize parameters elif actSel == actReset: self.host.reset_parameters(self.fPluginId) @@ -684,17 +921,26 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): elif actSel == actRandom: self.host.randomize_parameters(self.fPluginId) - elif actSel == actGui: - bGui.click() + # ------------------------------------------------------------- + # Edit and Show Custom UI elif actSel == actEdit: - bEdit.click() + self.b_edit.click() + + elif actSel == actGui: + self.b_gui.click() + + # ------------------------------------------------------------- + # Clone elif actSel == actClone: if not self.host.clone_plugin(self.fPluginId): CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) + # ------------------------------------------------------------- + # Rename + elif actSel == actRename: oldName = self.fPluginInfo['name'] newNameTry = QInputDialog.getText(self, self.tr("Rename Plugin"), self.tr("New plugin name:"), QLineEdit.Normal, oldName) @@ -710,32 +956,22 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) + # ------------------------------------------------------------- + # Replace + elif actSel == actReplace: + # FIXME gCarla.gui.slot_pluginAdd(self.fPluginId) + # ------------------------------------------------------------- + # Remove + elif actSel == actRemove: if not self.host.remove_plugin(self.fPluginId): CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) - def updateParameterValues(self): - for paramIndex, paramWidget in self.fParameterList: - if paramIndex < 0: - continue - - paramWidget.blockSignals(True) - paramWidget.setValue(self.host.get_current_parameter_value(self.fPluginId, paramIndex)) - paramWidget.blockSignals(False) - - #------------------------------------------------------------------ - - @pyqtSlot(bool) - def slot_enableClicked(self, yesNo): - self.setActive(yesNo, False, True) - - @pyqtSlot() - def slot_showDefaultCustomMenu(self): - self.showDefaultCustomMenu(self.fIsActive, self.b_edit, self.b_gui) + # ------------------------------------------------------------- @pyqtSlot() def slot_knobCustomMenu(self): @@ -855,7 +1091,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): class PluginSlot_Default(AbstractPluginSlot): def __init__(self, parent, host, pluginId): - AbstractPluginSlot.__init__(self, parent, host, pluginId) + AbstractPluginSlot.__init__(self, parent, host, pluginId, "default") self.ui = ui_carla_plugin_default.Ui_PluginWidget() self.ui.setupUi(self) @@ -866,25 +1102,6 @@ class PluginSlot_Default(AbstractPluginSlot): self.fColorBottom = QColor(47, 47, 47) self.fColorSeprtr = QColor(70, 70, 70) - # ------------------------------------------------------------- - # Set-up GUI - - self.setStyleSheet(""" - QLabel#label_name { - color: #BBB; - } - """) - - self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png") - self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png") - - if self.fPluginInfo['iconName'] == "distrho": - self.ui.b_gui.setPixmaps(":/bitmaps/button_distrho.png", ":/bitmaps/button_distrho_down.png", ":/bitmaps/button_distrho_hover.png") - elif self.fPluginInfo['iconName'] == "file": - self.ui.b_gui.setPixmaps(":/bitmaps/button_file.png", ":/bitmaps/button_file_down.png", ":/bitmaps/button_file_hover.png") - else: - self.ui.b_gui.setPixmaps(":/bitmaps/button_gui.png", ":/bitmaps/button_gui_down.png", ":/bitmaps/button_gui_hover.png") - # ------------------------------------------------------------- self.b_enable = self.ui.b_enable @@ -962,89 +1179,49 @@ class PluginSlot_Default(AbstractPluginSlot): # ------------------------------------------------------------------------------------------------------------ -class PluginSlot_BasicFX(AbstractPluginSlot): - def __init__(self, parent, host, pluginId): - AbstractPluginSlot.__init__(self, parent, host, pluginId) - self.ui = ui_carla_plugin_basic_fx.Ui_PluginWidget() +class PluginSlot_Compact(AbstractPluginSlot): + def __init__(self, parent, host, pluginId, skinStyle): + AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle) + self.ui = ui_carla_plugin_compact.Ui_PluginWidget() self.ui.setupUi(self) - if self.fPluginInfo['type'] == PLUGIN_INTERNAL and self.fPluginInfo['label'] == "midifile": - self.fIsCollapsed = True + self.b_enable = self.ui.b_enable + self.b_gui = self.ui.b_gui + self.b_edit = self.ui.b_edit - # ------------------------------------------------------------- - # Set-up GUI + self.label_name = self.ui.label_name - labelFont = self.ui.label_name.font() - labelFont.setBold(True) - labelFont.setPointSize(9) - self.ui.label_name.setFont(labelFont) - - r = 40 - g = 40 - b = 40 - - if self.fPluginInfo['category'] == PLUGIN_CATEGORY_MODULATOR: - r += 10 - elif self.fPluginInfo['category'] == PLUGIN_CATEGORY_EQ: - g += 10 - elif self.fPluginInfo['category'] == PLUGIN_CATEGORY_FILTER: - b += 10 - elif self.fPluginInfo['category'] == PLUGIN_CATEGORY_DELAY: - r += 15 - b -= 15 - elif self.fPluginInfo['category'] == PLUGIN_CATEGORY_DISTORTION: - g += 10 - b += 10 - elif self.fPluginInfo['category'] == PLUGIN_CATEGORY_DYNAMICS: - r += 10 - b += 10 - elif self.fPluginInfo['category'] == PLUGIN_CATEGORY_UTILITY: - r += 10 - g += 10 - - bg = "noise1" - - if self.fPluginInfo['maker'] in ("falkTX, Michael Gruhn", "DISTRHO") and "3bandeq" in self.fPluginInfo['label'].lower(): - bg = "3bandeq" - - self.setStyleSheet(""" - PluginSlot_BasicFX#PluginWidget { - background-color: rgb(%i, %i, %i); - background-image: url(:/bitmaps/background_%s.png); - background-repeat: repeat-xy; - } - QLabel#label_name { - color: #BBB; - } - QLabel#label_name:disabled { - color: #555; - } - """ % (r, g, b, bg)) - - self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png") - self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png") - - if self.fPluginInfo['iconName'] == "distrho": - self.ui.b_gui.setPixmaps(":/bitmaps/button_distrho.png", ":/bitmaps/button_distrho_down.png", ":/bitmaps/button_distrho_hover.png") - elif self.fPluginInfo['iconName'] == "file": - self.ui.b_gui.setPixmaps(":/bitmaps/button_file.png", ":/bitmaps/button_file_down.png", ":/bitmaps/button_file_hover.png") - else: - self.ui.b_gui.setPixmaps(":/bitmaps/button_gui.png", ":/bitmaps/button_gui_down.png", ":/bitmaps/button_gui_hover.png") - - if self.fIsCollapsed: - self.layout().setAlignment(Qt.AlignCenter) - self.layout().setContentsMargins(2,2,2,0) - self.ui.layout_leds.setContentsMargins(0,4,0,0) - self.ui.w_knobs.hide() - self.ui.w_screws_left.hide() - self.ui.w_screws_right.hide() - self.ui.label_name.setFixedHeight(self.ui.b_enable.height()) - print("TO BOTTOM") + self.led_control = self.ui.led_control + self.led_midi = self.ui.led_midi + self.led_audio_in = self.ui.led_audio_in + self.led_audio_out = self.ui.led_audio_out + + self.peak_in = self.ui.peak_in + self.peak_out = self.ui.peak_out + + self.ready() + + self.customContextMenuRequested.connect(self.slot_showDefaultCustomMenu) + + #------------------------------------------------------------------ + + def getFixedHeight(self): + if self.fSkinStyle == "calf_blue": + return 36 + return 30 + +# ------------------------------------------------------------------------------------------------------------ + +class PluginSlot_BasicFX(AbstractPluginSlot): + def __init__(self, parent, host, pluginId, skinStyle): + AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle) + self.ui = ui_carla_plugin_basic_fx.Ui_PluginWidget() + self.ui.setupUi(self) # ------------------------------------------------------------- # Set-up parameters - parameterCount = self.host.get_parameter_count(self.fPluginId) if not self.fIsCollapsed else 0 + parameterCount = self.host.get_parameter_count(self.fPluginId) index = 0 for i in range(parameterCount): @@ -1081,49 +1258,72 @@ class PluginSlot_BasicFX(AbstractPluginSlot): #else: _r = 255 - float(index)/8*200 _g = 55 + float(index)/8*200 - _b = (r-40)*4 + _b = 0 #(r-40)*4 + index += 1 #if _r < 140: _r = 140 #if _g < 140: _g = 140 #if _b < 140: _b = 140 widget = PixmapDial(self, i) - widget.setPixmap(3) widget.setLabel(paramName) - widget.setCustomPaintColor(QColor(_r, _g, _b)) - widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_COLOR) - widget.forceWhiteLabelGradientText() widget.setMinimum(paramRanges['min']) widget.setMaximum(paramRanges['max']) - if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0: - widget.setEnabled(False) - - self.ui.w_knobs.layout().insertWidget(index, widget) - index += 1 + if skinStyle == "mod": + widget.setPixmap(14) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + elif skinStyle == "openav": + widget.setPixmap(11) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + else: + widget.setPixmap(3) + widget.setCustomPaintColor(QColor(_r, _g, _b)) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_COLOR) + widget.forceWhiteLabelGradientText() self.fParameterList.append([i, widget]) + self.ui.w_knobs_left.layout().addWidget(widget) + + if self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET: + widget = PixmapDial(self, PARAMETER_DRYWET) + widget.setLabel("Dry/Wet") + widget.setMinimum(0.0) + widget.setMaximum(1.0) + + if skinStyle == "mod": + widget.setPixmap(14) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + elif skinStyle == "openav": + widget.setPixmap(13) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + else: + widget.setPixmap(3) + widget.setCustomPaintMode(PixmapDial.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.setLabel("Volume") + widget.setMinimum(0.0) + widget.setMaximum(1.27) + + if skinStyle == "mod": + widget.setPixmap(14) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + elif skinStyle == "openav": + widget.setPixmap(12) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + else: + widget.setPixmap(3) + widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_VOL) + widget.forceWhiteLabelGradientText() - self.ui.dial_drywet.setIndex(PARAMETER_DRYWET) - self.ui.dial_drywet.setPixmap(3) - self.ui.dial_drywet.setLabel("Dry/Wet") - self.ui.dial_drywet.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_WET) - self.ui.dial_drywet.setMinimum(0.0) - self.ui.dial_drywet.setMaximum(1.0) - self.ui.dial_drywet.forceWhiteLabelGradientText() - self.ui.dial_drywet.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) - - self.ui.dial_vol.setIndex(PARAMETER_VOLUME) - self.ui.dial_vol.setPixmap(3) - self.ui.dial_vol.setLabel("Volume") - self.ui.dial_vol.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_VOL) - self.ui.dial_vol.setMinimum(0.0) - self.ui.dial_vol.setMaximum(1.27) - self.ui.dial_vol.forceWhiteLabelGradientText() - self.ui.dial_vol.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) - - self.fParameterList.append([PARAMETER_DRYWET, self.ui.dial_drywet]) - self.fParameterList.append([PARAMETER_VOLUME, self.ui.dial_vol]) + self.fParameterList.append([PARAMETER_VOLUME, widget]) + self.ui.w_knobs_right.layout().addWidget(widget) # ------------------------------------------------------------- @@ -1138,8 +1338,6 @@ class PluginSlot_BasicFX(AbstractPluginSlot): self.led_audio_in = self.ui.led_audio_in self.led_audio_out = self.ui.led_audio_out - self.line = self.ui.line - self.peak_in = self.ui.peak_in self.peak_out = self.ui.peak_out @@ -1150,7 +1348,10 @@ class PluginSlot_BasicFX(AbstractPluginSlot): #------------------------------------------------------------------ def getFixedHeight(self): - return 28 if self.fIsCollapsed else 79 + if self.fSkinStyle == "mod": + return 86 + + return 80 #------------------------------------------------------------------ @@ -1169,14 +1370,11 @@ class PluginSlot_BasicFX(AbstractPluginSlot): # ------------------------------------------------------------------------------------------------------------ class PluginSlot_Calf(AbstractPluginSlot): - def __init__(self, parent, host, pluginId): - AbstractPluginSlot.__init__(self, parent, host, pluginId) + def __init__(self, parent, host, pluginId, skinStyle): + AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle) self.ui = ui_carla_plugin_calf.Ui_PluginWidget() self.ui.setupUi(self) - # FIXME - self.fIsCollapsed = False - audioCount = self.host.get_audio_port_count_info(self.fPluginId) midiCount = self.host.get_midi_port_count_info(self.fPluginId) @@ -1187,34 +1385,12 @@ class PluginSlot_Calf(AbstractPluginSlot): self.fButtonFont.setBold(False) self.fButtonFont.setPointSize(8) - # Use black for mono plugins - self.fBackgroundBlack = bool("mono" in self.fPluginInfo["label"].lower()) - self.fButtonColorOn = QColor( 18, 41, 87) self.fButtonColorOff = QColor(150, 150, 150) # ------------------------------------------------------------- # Set-up GUI - self.setStyleSheet(""" - QLabel#label_name, QLabel#label_audio_in, QLabel#label_audio_out, QLabel#label_midi { - color: #BBB; - } - QLabel#label_name:disabled { - color: #667; - } - PluginSlot_Calf#PluginWidget { - background-image: url(:/bitmaps/background_calf_%s.png); - background-repeat: repeat-xy; - border: 2px; - } - """ % ("black" if self.fBackgroundBlack else "blue")) - - self.ui.line.setStyleSheet("* { color: #FF5100; }") - - self.ui.b_enable.setPixmaps(":/bitmaps/button_calf3.png", ":/bitmaps/button_calf3_down.png", ":/bitmaps/button_calf3.png") - self.ui.b_gui.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png") - self.ui.b_edit.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png") self.ui.b_remove.setPixmaps(":/bitmaps/button_calf1.png", ":/bitmaps/button_calf1_down.png", ":/bitmaps/button_calf1_hover.png") self.ui.b_edit.setTopText(self.tr("Edit"), self.fButtonColorOn, self.fButtonFont) @@ -1225,24 +1401,11 @@ class PluginSlot_Calf(AbstractPluginSlot): else: self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOff, self.fButtonFont) - labelFont = self.ui.label_name.font() - labelFont.setBold(True) - labelFont.setPointSize(10) - self.ui.label_name.setFont(labelFont) - - self.ui.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_CALF) - self.ui.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_CALF) - if audioCount['ins'] == 0: self.ui.label_audio_in.hide() - self.ui.peak_in.hide() - - if audioCount['outs'] > 0: - self.ui.peak_out.setMinimumWidth(200) if audioCount['outs'] == 0: self.ui.label_audio_out.hide() - self.ui.peak_out.hide() if midiCount['ins'] == 0: self.ui.label_midi.hide() @@ -1255,7 +1418,7 @@ class PluginSlot_Calf(AbstractPluginSlot): # ------------------------------------------------------------- # Set-up parameters - parameterCount = self.host.get_parameter_count(self.fPluginId) if not self.fIsCollapsed else 0 + parameterCount = self.host.get_parameter_count(self.fPluginId) index = 0 limit = 7 if midiCount['ins'] == 0 else 6 @@ -1303,8 +1466,6 @@ class PluginSlot_Calf(AbstractPluginSlot): self.label_name = self.ui.label_name self.led_midi = self.ui.led_midi - self.line = self.ui.line - self.peak_in = self.ui.peak_in self.peak_out = self.ui.peak_out @@ -1332,149 +1493,15 @@ class PluginSlot_Calf(AbstractPluginSlot): #------------------------------------------------------------------ def paintEvent(self, event): - painter = QPainter(self) - painter.setBrush(Qt.transparent) - - painter.setPen(QPen(QColor(20, 20, 20) if self.fBackgroundBlack else QColor(75, 86, 99), 1)) - painter.drawRect(0, 1, self.width()-1, 88-3) - - painter.setPen(QPen(QColor(45, 45, 45) if self.fBackgroundBlack else QColor(86, 99, 114), 1)) - painter.drawLine(0, 0, self.width(), 0) - - AbstractPluginSlot.paintEvent(self, event) - -# ------------------------------------------------------------------------------------------------------------ - -class PluginSlot_OpenAV(AbstractPluginSlot): - def __init__(self, parent, host, pluginId): - AbstractPluginSlot.__init__(self, parent, host, pluginId) - self.ui = ui_carla_plugin_basic_fx.Ui_PluginWidget() - self.ui.setupUi(self) - - # ------------------------------------------------------------- - # Set-up GUI - - QFontDatabase.addApplicationFont(":/fonts/uranium.ttf") - - labelFont = QFont() - labelFont.setFamily("Uranium") - labelFont.setPointSize(13) - labelFont.setCapitalization(QFont.AllUppercase) - self.ui.label_name.setFont(labelFont) - - self.setStyleSheet(""" - PluginSlot_OpenAV#PluginWidget { - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #303030, stop: 0.35 #111111, stop: 1.0 #111111); - } - """) - - self.ui.label_name.setStyleSheet("* { color: #FF5100; }") - #self.ui.line.setStyleSheet("* { background-color: #FF5100; color: #FF5100; }") - - self.ui.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV) - self.ui.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV) - - self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png") - self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png") - self.ui.b_gui.setPixmaps(":/bitmaps/button_gui.png", ":/bitmaps/button_gui_down.png", ":/bitmaps/button_gui_hover.png") - - # ------------------------------------------------------------- - # Set-up parameters - - parameterCount = self.host.get_parameter_count(self.fPluginId) if not self.fIsCollapsed else 0 - - index = 0 - for i in range(parameterCount): - if index >= 8: - break - - paramInfo = self.host.get_parameter_info(self.fPluginId, i) - paramData = self.host.get_parameter_data(self.fPluginId, i) - paramRanges = self.host.get_parameter_ranges(self.fPluginId, i) - - if paramData['type'] != PARAMETER_INPUT: - continue - if paramData['hints'] & PARAMETER_IS_BOOLEAN: - continue - if paramData['hints'] & PARAMETER_IS_INTEGER: - continue - if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0: - continue - - paramName = getParameterShortName(paramInfo['name']) - - widget = PixmapDial(self, i) - widget.setPixmap(11) - widget.setLabel(paramName) - widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) - widget.setMinimum(paramRanges['min']) - widget.setMaximum(paramRanges['max']) - - if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0: - widget.setEnabled(False) - - self.ui.w_knobs.layout().insertWidget(index, widget) - index += 1 - - self.fParameterList.append([i, widget]) - - self.ui.dial_drywet.setIndex(PARAMETER_DRYWET) - self.ui.dial_drywet.setPixmap(13) - self.ui.dial_drywet.setLabel("Dry/Wet") - self.ui.dial_drywet.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) - self.ui.dial_drywet.setMinimum(0.0) - self.ui.dial_drywet.setMaximum(1.0) - self.ui.dial_drywet.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) + isBlack = bool(self.fSkinStyle == "calf_black") - self.ui.dial_vol.setIndex(PARAMETER_VOLUME) - self.ui.dial_vol.setPixmap(12) - self.ui.dial_vol.setLabel("Volume") - self.ui.dial_vol.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) - self.ui.dial_vol.setMinimum(0.0) - self.ui.dial_vol.setMaximum(1.27) - self.ui.dial_vol.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) - - self.fParameterList.append([PARAMETER_DRYWET, self.ui.dial_drywet]) - self.fParameterList.append([PARAMETER_VOLUME, self.ui.dial_vol]) - - # ------------------------------------------------------------- - - self.b_enable = self.ui.b_enable - self.b_gui = self.ui.b_gui - self.b_edit = self.ui.b_edit - - self.label_name = self.ui.label_name - - self.led_control = self.ui.led_control - self.led_midi = self.ui.led_midi - self.led_audio_in = self.ui.led_audio_in - self.led_audio_out = self.ui.led_audio_out - - self.line = self.ui.line - - self.peak_in = self.ui.peak_in - self.peak_out = self.ui.peak_out - - self.ready() - - self.customContextMenuRequested.connect(self.slot_showDefaultCustomMenu) - - #------------------------------------------------------------------ - - def getFixedHeight(self): - return 28 if self.fIsCollapsed else 79 - - #------------------------------------------------------------------ - - def paintEvent(self, event): painter = QPainter(self) painter.setBrush(Qt.transparent) - painter.setPen(QPen(QColor(42, 42, 42), 1)) - painter.drawRect(0, 1, self.width()-1, 79-3) + painter.setPen(QPen(QColor(20, 20, 20) if isBlack else QColor(75, 86, 99), 1)) + painter.drawRect(0, 1, self.width()-1, self.height()-3) - painter.setPen(QPen(QColor(60, 60, 60), 1)) + painter.setPen(QPen(QColor(45, 45, 45) if isBlack else QColor(86, 99, 114), 1)) painter.drawLine(0, 0, self.width(), 0) AbstractPluginSlot.paintEvent(self, event) @@ -1482,8 +1509,8 @@ class PluginSlot_OpenAV(AbstractPluginSlot): # ------------------------------------------------------------------------------------------------------------ class PluginSlot_Nekobi(AbstractPluginSlot): - def __init__(self, parent, host, pluginId): - AbstractPluginSlot.__init__(self, parent, host, pluginId) + def __init__(self, parent, host, pluginId, skinStyle): + AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle) #self.ui = ui_carla_plugin_basic_fx.Ui_PluginWidget() #self.ui.setupUi(self) @@ -1498,16 +1525,6 @@ class PluginSlot_Nekobi(AbstractPluginSlot): self.fPixmapRight = QPixmap(":/bitmaps/background_nekobi_right.png") self.fPixmapRightRect = QRectF(0, 0, self.fPixmapRight.width(), self.fPixmapRight.height()) - #self.setStyleSheet(""" - #PluginSlot_Nekobi#PluginWidget { - #background-image: url(:/bitmaps/background_nekobi.png); - #background-repeat: repeat-xy; - #} - #QLabel#label_name { - #color: #BBB; - #} - #""") - #------------------------------------------------------------------ def getFixedHeight(self): @@ -1534,36 +1551,15 @@ class PluginSlot_Nekobi(AbstractPluginSlot): # ------------------------------------------------------------------------------------------------------------ class PluginSlot_SF2(AbstractPluginSlot): - def __init__(self, parent, host, pluginId): - AbstractPluginSlot.__init__(self, parent, host, pluginId) + def __init__(self, parent, host, pluginId, skinStyle): + AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle) self.ui = ui_carla_plugin_sf2.Ui_PluginWidget() self.ui.setupUi(self) - # ------------------------------------------------------------- - # Set-up GUI - - #labelFont = self.ui.label_name.font() - #labelFont.setBold(True) - #labelFont.setPointSize(9) - #self.ui.label_name.setFont(labelFont) - - self.setStyleSheet(""" - PluginSlot_SF2#PluginWidget { - background-image: url(:/bitmaps/background_3bandeq.png); - background-repeat: repeat-xy; - } - QLabel#label_name { - color: #BBB; - } - """) - - self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png") - self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png") - # ------------------------------------------------------------- # Set-up parameters - parameterCount = self.host.get_parameter_count(self.fPluginId) if not self.fIsCollapsed else 0 + parameterCount = self.host.get_parameter_count(self.fPluginId) index = 0 for i in range(parameterCount): @@ -1621,8 +1617,6 @@ class PluginSlot_SF2(AbstractPluginSlot): self.led_midi = self.ui.led_midi self.led_audio_out = self.ui.led_audio_out - self.line = self.ui.line - self.peak_out = self.ui.peak_out self.ready() @@ -1632,7 +1626,7 @@ class PluginSlot_SF2(AbstractPluginSlot): #------------------------------------------------------------------ def getFixedHeight(self): - return 79 + return 80 #------------------------------------------------------------------ @@ -1641,7 +1635,7 @@ class PluginSlot_SF2(AbstractPluginSlot): painter.setBrush(Qt.transparent) painter.setPen(QPen(QColor(42, 42, 42), 1)) - painter.drawRect(0, 1, self.width()-1, 79-3) + painter.drawRect(0, 1, self.width()-1, self.height()-3) painter.setPen(QPen(QColor(60, 60, 60), 1)) painter.drawLine(0, 0, self.width(), 0) @@ -1651,45 +1645,15 @@ class PluginSlot_SF2(AbstractPluginSlot): # ------------------------------------------------------------------------------------------------------------ class PluginSlot_ZynFX(AbstractPluginSlot): - def __init__(self, parent, host, pluginId): - AbstractPluginSlot.__init__(self, parent, host, pluginId) + def __init__(self, parent, host, pluginId, skinStyle): + AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle) self.ui = ui_carla_plugin_zynfx.Ui_PluginWidget() self.ui.setupUi(self) - # ------------------------------------------------------------- - # Set-up GUI - - self.setStyleSheet(""" - PluginSlot_ZynFX#PluginWidget { - background-image: url(:/bitmaps/background_zynfx.png); - background-repeat: repeat-xy; - border: 2px; - } - QLabel#label_name, QLabel#label_presets { - color: #BBB; - } - """) - - self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png") - self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png") - - labelFont = self.ui.label_name.font() - labelFont.setBold(True) - labelFont.setPointSize(9) - self.ui.label_name.setFont(labelFont) - - presetFont = self.ui.label_presets.font() - presetFont.setBold(True) - presetFont.setPointSize(8) - self.ui.label_presets.setFont(presetFont) - - self.ui.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV) - self.ui.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV) - # ------------------------------------------------------------- # Set-up parameters - parameterCount = self.host.get_parameter_count(self.fPluginId) if not self.fIsCollapsed else 0 + parameterCount = self.host.get_parameter_count(self.fPluginId) index = 0 for i in range(parameterCount): @@ -1701,8 +1665,6 @@ class PluginSlot_ZynFX(AbstractPluginSlot): continue if paramData['hints'] & PARAMETER_IS_BOOLEAN: continue - if paramData['hints'] & PARAMETER_IS_INTEGER: - continue if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0: continue @@ -1783,29 +1745,29 @@ class PluginSlot_ZynFX(AbstractPluginSlot): if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0: widget.setEnabled(False) - self.ui.w_knobs.layout().insertWidget(index, widget) + self.ui.w_knobs_left.layout().insertWidget(index, widget) index += 1 self.fParameterList.append([i, widget]) - self.ui.dial_drywet.setIndex(PARAMETER_DRYWET) - self.ui.dial_drywet.setPixmap(5) - self.ui.dial_drywet.setLabel("Wet") - self.ui.dial_drywet.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) - self.ui.dial_drywet.setMinimum(0.0) - self.ui.dial_drywet.setMaximum(1.0) - self.ui.dial_drywet.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) - - self.ui.dial_vol.setIndex(PARAMETER_VOLUME) - self.ui.dial_vol.setPixmap(5) - self.ui.dial_vol.setLabel("Vol") - self.ui.dial_vol.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) - self.ui.dial_vol.setMinimum(0.0) - self.ui.dial_vol.setMaximum(1.27) - self.ui.dial_vol.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) - - self.fParameterList.append([PARAMETER_DRYWET, self.ui.dial_drywet]) - self.fParameterList.append([PARAMETER_VOLUME, self.ui.dial_vol]) + #self.ui.dial_drywet.setIndex(PARAMETER_DRYWET) + #self.ui.dial_drywet.setPixmap(5) + #self.ui.dial_drywet.setLabel("Wet") + #self.ui.dial_drywet.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + #self.ui.dial_drywet.setMinimum(0.0) + #self.ui.dial_drywet.setMaximum(1.0) + #self.ui.dial_drywet.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) + + #self.ui.dial_vol.setIndex(PARAMETER_VOLUME) + #self.ui.dial_vol.setPixmap(5) + #self.ui.dial_vol.setLabel("Vol") + #self.ui.dial_vol.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) + #self.ui.dial_vol.setMinimum(0.0) + #self.ui.dial_vol.setMaximum(1.27) + #self.ui.dial_vol.setVisible(self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) + + #self.fParameterList.append([PARAMETER_DRYWET, self.ui.dial_drywet]) + #self.fParameterList.append([PARAMETER_VOLUME, self.ui.dial_vol]) # ------------------------------------------------------------- # Set-up MIDI programs @@ -1835,19 +1797,19 @@ class PluginSlot_ZynFX(AbstractPluginSlot): # ------------------------------------------------------------- self.b_enable = self.ui.b_enable + self.b_gui = self.ui.b_gui self.b_edit = self.ui.b_edit self.cb_presets = self.ui.cb_presets - self.label_name = self.ui.label_name + self.label_name = self.ui.label_name + self.label_presets = self.ui.label_presets self.led_control = self.ui.led_control self.led_midi = self.ui.led_midi self.led_audio_in = self.ui.led_audio_in self.led_audio_out = self.ui.led_audio_out - self.line = self.ui.line - self.peak_in = self.ui.peak_in self.peak_out = self.ui.peak_out @@ -1859,7 +1821,7 @@ class PluginSlot_ZynFX(AbstractPluginSlot): #------------------------------------------------------------------ def getFixedHeight(self): - return 30 if self.fIsCollapsed else 79 + return 80 #------------------------------------------------------------------ @@ -1877,39 +1839,60 @@ class PluginSlot_ZynFX(AbstractPluginSlot): # ------------------------------------------------------------------------------------------------------------ -def createPluginSlot(parent, host, pluginId, useSkins): - if not useSkins: - return PluginSlot_Default(parent, host, pluginId) - +def getSkinStyle(host, pluginId): pluginInfo = host.get_plugin_info(pluginId) pluginName = host.get_real_plugin_name(pluginId) - pluginLabel = pluginInfo['label'] + pluginLabel = pluginInfo['label'].lower() pluginMaker = pluginInfo['maker'] uniqueId = pluginInfo['uniqueId'] - #pluginIcon = pluginInfo['iconName'] - + # Samplers + if pluginInfo['type'] == PLUGIN_GIG: + return "gig" if pluginInfo['type'] == PLUGIN_SF2: - return PluginSlot_SF2(parent, host, pluginId) - - if pluginMaker == "OpenAV Productions": - return PluginSlot_OpenAV(parent, host, pluginId) + return "sf2" + if pluginInfo['type'] == PLUGIN_SFZ: + return "sfz" + # ZynFX if pluginInfo['type'] == PLUGIN_INTERNAL: if pluginLabel.startswith("zyn") and pluginInfo['category'] != PLUGIN_CATEGORY_SYNTH: - return PluginSlot_ZynFX(parent, host, pluginId) + return "zynfx" - elif pluginInfo['type'] == PLUGIN_LADSPA: - if pluginLabel.startswith("Zyn") and pluginMaker.startswith("Josep Andreu"): - return PluginSlot_ZynFX(parent, host, pluginId) + if pluginInfo['type'] == PLUGIN_LADSPA: + if pluginLabel.startswith("zyn") and pluginMaker.startswith("Josep Andreu"): + return "zynfx" + # Groups if pluginName.split(" ", 1)[0].lower() == "calf": - return PluginSlot_Calf(parent, host, pluginId) + return "calf_black" if "mono" in pluginLabel else "calf_blue" + if pluginLabel.startswith("http://portalmod.com/") or pluginLabel.startswith("http://plugin.org.uk/swh-plugins/"): + return "mod" + if pluginMaker == "OpenAV Productions": + return "openav" + + # DISTRHO Plugins + if pluginMaker.startswith("falkTX, ") or pluginMaker == "DISTRHO": + return pluginLabel + + return "default" + +def createPluginSlot(parent, host, pluginId, options): + if not options['useSkins']: + return PluginSlot_Default(parent, host, pluginId) + + skinStyle = getSkinStyle(host, pluginId) + + if options['compact'] or "compact" in skinStyle: + return PluginSlot_Compact(parent, host, pluginId, skinStyle) + + if "calf" in skinStyle: + return PluginSlot_Calf(parent, host, pluginId, skinStyle) - #if pluginName.lower() == "nekobi": - #return PluginSlot_Nekobi(parent, pluginId) + if skinStyle == "zynfx": + return PluginSlot_ZynFX(parent, host, pluginId, skinStyle) - return PluginSlot_BasicFX(parent, host, pluginId) + return PluginSlot_BasicFX(parent, host, pluginId, skinStyle) # ------------------------------------------------------------------------------------------------------------ # Main Testing @@ -1930,7 +1913,8 @@ if __name__ == '__main__': #host.add_plugin(BINARY_NATIVE, PLUGIN_LV2, "", "", "http://calf.sourceforge.net/plugins/Compressor", 0, None, 0x0) host.set_active(0, True) - gui = createPluginSlot(None, host, 0, True) + #gui = createPluginSlot(None, host, 0, True) + gui = PluginSlot_Compact(None, host, 0, "default") gui.testTimer() gui.show() diff --git a/source/widgets/digitalpeakmeter.py b/source/widgets/digitalpeakmeter.py index cbd2c120b..2c8598843 100644 --- a/source/widgets/digitalpeakmeter.py +++ b/source/widgets/digitalpeakmeter.py @@ -24,6 +24,8 @@ from carla_config import * # ------------------------------------------------------------------------------------------------------------ # Imports (Global) +from math import sqrt + if config_UseQt5: from PyQt5.QtCore import qCritical, Qt, QTimer, QSize from PyQt5.QtGui import QColor, QLinearGradient, QPainter, QPen, QPixmap @@ -323,13 +325,9 @@ class DigitalPeakMeter(QWidget): # draw levels for level in self.fChannelData: - if level == 0.0: - meterPos += meterSize - continue - - blevel = int(level*26.0)*3 - - painter.drawPixmap(5, meterPos, blevel, 4, self.fMeterPixmaps[1], 0, 0, blevel, 4) + if level != 0.0: + blevel = int(sqrt(level)*26.0)*3 + painter.drawPixmap(5, meterPos, blevel, 4, self.fMeterPixmaps[1], 0, 0, blevel, 4) meterPos += meterSize def paintEvent(self, event): @@ -371,16 +369,13 @@ class DigitalPeakMeter(QWidget): # draw levels for level in self.fChannelData: if level == 0.0: - meterPos += meterSize+meterPad - continue - - if self.fMeterOrientation == self.HORIZONTAL: - painter.drawRect(0, meterPos, int(level * float(width)), meterSize) - meterPos += meterSize+meterPad - + pass + elif self.fMeterOrientation == self.HORIZONTAL: + painter.drawRect(0, meterPos, int(sqrt(level) * float(width)), meterSize) elif self.fMeterOrientation == self.VERTICAL: - painter.drawRect(meterPos, height - int(level * float(height)), meterSize, height) - meterPos += meterSize+meterPad + painter.drawRect(meterPos, height - int(sqrt(level) * float(height)), meterSize, height) + + meterPos += meterSize+meterPad if not self.fMeterLinesEnabled: return diff --git a/source/widgets/racklistwidget.py b/source/widgets/racklistwidget.py index 5e4b28673..57df287e8 100644 --- a/source/widgets/racklistwidget.py +++ b/source/widgets/racklistwidget.py @@ -42,6 +42,7 @@ from carla_skin import * class RackListItem(QListWidgetItem): kRackItemType = QListWidgetItem.UserType + 1 + kMinimumWidth = 620 def __init__(self, parent, pluginId, useSkins): QListWidgetItem.__init__(self, parent, self.kRackItemType) @@ -59,11 +60,15 @@ class RackListItem(QListWidgetItem): self.fParent = parent self.fPluginId = pluginId - self.fUseSkins = useSkins self.fWidget = None + self.fOptions = { + 'compact': False, + 'useSkins': useSkins + } + self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled) - #self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsDragEnabled|Qt.ItemIsDropEnabled) + #self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsDragEnabled) # ---------------------------------------------------------------------------------------------------- # Set-up GUI @@ -76,17 +81,21 @@ class RackListItem(QListWidgetItem): if self.fWidget is None: return - self.fWidget.fEditDialog.close() - self.fWidget.fEditDialog.setParent(None) - self.fWidget.fEditDialog.deleteLater() - del self.fWidget.fEditDialog + widget = self.fWidget + self.fWidget = None - self.fWidget.close() - self.fWidget.setParent(None) - self.fWidget.deleteLater() - del self.fWidget + self.fParent.customClearSelection() + self.fParent.setItemWidget(self, None) - self.fWidget = None + widget.fEditDialog.close() + widget.fEditDialog.setParent(None) + widget.fEditDialog.deleteLater() + del widget.fEditDialog + + widget.close() + widget.setParent(None) + widget.deleteLater() + del widget def getEditDialog(self): if self.fWidget is None: @@ -108,15 +117,24 @@ class RackListItem(QListWidgetItem): if self.fWidget is not None: self.fWidget.setPluginId(pluginId) + def setSelected(self, select): + if self.fWidget is not None: + self.fWidget.setSelected(select) + + QListWidgetItem.setSelected(self, select) + # -------------------------------------------------------------------------------------------------------- - def recreateWidget(self): + def recreateWidget(self, invertCompactOption = False): + if invertCompactOption: + self.fOptions['compact'] = not self.fOptions['compact'] + self.close() - self.fWidget = createPluginSlot(self.fParent, self.host, self.fPluginId, self.fUseSkins) + self.fWidget = createPluginSlot(self.fParent, self.host, self.fPluginId, self.fOptions) self.fWidget.setFixedHeight(self.fWidget.getFixedHeight()) - self.setSizeHint(QSize(620, self.fWidget.getFixedHeight())) + self.setSizeHint(QSize(self.kMinimumWidth, self.fWidget.getFixedHeight())) self.fParent.setItemWidget(self, self.fWidget) @@ -143,10 +161,15 @@ class RackListWidget(QListWidget): if not WINDOWS: exts.append(".so") - self.fSupportedExtensions = tuple(i.replace("*","") for i in exts) + self.fSupportedExtensions = tuple(i.replace("*","").lower() for i in exts) + self.fLastSelectedItem = None self.fWasLastDragValid = False - self.setMinimumWidth(640) + self.fPixmapL = QPixmap(":/bitmaps/rack_interior_left.png") + self.fPixmapR = QPixmap(":/bitmaps/rack_interior_right.png") + self.fPixmapWidth = self.fPixmapL.width() + + self.setMinimumWidth(RackListItem.kMinimumWidth) self.setSelectionMode(QAbstractItemView.SingleSelection) self.setSortingEnabled(False) @@ -158,11 +181,6 @@ class RackListWidget(QListWidget): self.setFrameShape(QFrame.NoFrame) self.setFrameShadow(QFrame.Plain) - self.fPixmapL = QPixmap(":/bitmaps/rack_interior_left.png") - self.fPixmapR = QPixmap(":/bitmaps/rack_interior_right.png") - - self.fPixmapWidth = self.fPixmapL.width() - # -------------------------------------------------------------------------------------------------------- def createItem(self, pluginId, useSkins): @@ -173,13 +191,18 @@ class RackListWidget(QListWidget): # -------------------------------------------------------------------------------------------------------- + def customClearSelection(self): + self.setCurrentRow(-1) + self.clearSelection() + self.clearFocus() + def isDragUrlValid(self, url): filename = url.toLocalFile() if os.path.isdir(filename): if os.path.exists(os.path.join(filename, "manifest.ttl")): return True - if filename.lower().endswith((".vst", ".vst3")): + if MACOS and filename.lower().endswith((".vst", ".vst3")): return True elif os.path.isfile(filename): @@ -264,9 +287,9 @@ class RackListWidget(QListWidget): # -------------------------------------------------------------------------------------------------------- def mousePressEvent(self, event): - if self.itemAt(event.pos()) is None: + if self.itemAt(event.pos()) is None and self.currentRow() != -1: event.accept() - self.setCurrentRow(-1) + self.customClearSelection() return QListWidget.mousePressEvent(self, event) @@ -277,4 +300,19 @@ class RackListWidget(QListWidget): painter.drawTiledPixmap(self.width()-self.fPixmapWidth-2, 0, self.fPixmapWidth, self.height(), self.fPixmapR) QListWidget.paintEvent(self, event) + # -------------------------------------------------------------------------------------------------------- + + def selectionChanged(self, selected, deselected): + for index in deselected.indexes(): + item = self.itemFromIndex(index) + if item is not None: + item.setSelected(False) + + for index in selected.indexes(): + item = self.itemFromIndex(index) + if item is not None: + item.setSelected(True) + + QListWidget.selectionChanged(self, selected, deselected) + # ------------------------------------------------------------------------------------------------------------