#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla plugin/slot skin code
# Copyright (C) 2013-2014 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 (Config)

from carla_config import *

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

if config_UseQt5:
    from PyQt5.QtCore import Qt, QRectF
    from PyQt5.QtGui import QFont, QFontDatabase, QPen, QPixmap
    from PyQt5.QtWidgets import QFrame, QPushButton
else:
    from PyQt4.QtCore import Qt, QRectF
    from PyQt4.QtGui import QFont, QFontDatabase, QFrame, QPen, QPixmap, QPushButton

# ------------------------------------------------------------------------------------------------------------
# Imports (Custom)

import ui_carla_plugin_default
import ui_carla_plugin_basic_fx
import ui_carla_plugin_calf
import ui_carla_plugin_sf2
import ui_carla_plugin_zita
import ui_carla_plugin_zynfx

from carla_widgets import *
from digitalpeakmeter import DigitalPeakMeter
from pixmapdial import PixmapDial

# ------------------------------------------------------------------------------------------------------------
# Try to "shortify" a parameter name

def getParameterShortName(paramName):
    paramName = paramName.split("/",1)[0].split(" (",1)[0].split(" [",1)[0].strip()
    paramLow  = paramName.lower()

    if paramLow.startswith("compressor "):
        paramName = paramName.replace("ompressor ", ".", 1)
        paramLow  = paramName.lower()

    # Cut generic names
    if "attack" in paramLow:
        paramName = paramName.replace("ttack", "tk")
    elif "bandwidth" in paramLow:
        paramName = paramName.replace("andwidth", "w")
    elif "damping" in paramLow:
        paramName = paramName.replace("amping", "amp")
    elif "distortion" in paramLow:
        paramName = paramName.replace("istortion", "ist")
    elif "feedback" in paramLow:
        paramName = paramName.replace("eedback", "b")
    elif "frequency" in paramLow:
        paramName = paramName.replace("requency", "req")
    elif "makeup" in paramLow:
        paramName = paramName.replace("akeup", "kUp" if "Make" in paramName else "kup")
    elif "output" in paramLow:
        paramName = paramName.replace("utput", "ut")
    elif "random" in paramLow:
        paramName = paramName.replace("andom", "nd")
    elif "threshold" in paramLow:
        paramName = paramName.replace("hreshold", "hres")

    # Cut useless prefix
    elif paramLow.startswith("room "):
        paramName = paramName.split(" ",1)[1]

    # Cut useless suffix
    elif paramLow.endswith(" level"):
        paramName = paramName.rsplit(" ",1)[0]
    elif paramLow.endswith(" time"):
        paramName = paramName.rsplit(" ",1)[0]

    if len(paramName) > 7:
        paramName = paramName[:7]

    return paramName.strip()

# ------------------------------------------------------------------------------------------------------------
# Abstract plugin slot

class AbstractPluginSlot(QFrame, PluginEditParentMeta):
#class AbstractPluginSlot(QFrame, PluginEditParentMeta, metaclass=PyQtMetaClass):
    def __init__(self, parent, host, pluginId):
        QFrame.__init__(self, parent)
        self.host = host

        if False:
            # kdevelop likes this :)
            host = CarlaHostMeta()
            self.host = host

        # -------------------------------------------------------------
        # Get plugin info

        self.fPluginId   = pluginId
        self.fPluginInfo = host.get_plugin_info(self.fPluginId)

        #if not gCarla.isLocal:
            #self.fPluginInfo['hints'] &= ~PLUGIN_HAS_CUSTOM_UI

        # -------------------------------------------------------------
        # Internal stuff

        self.fIsActive   = bool(host.get_internal_parameter_value(self.fPluginId, PARAMETER_ACTIVE) >= 0.5)
        self.fIsSelected = False

        self.fLastGreenLedState = False
        self.fLastBlueLedState  = False

        self.fParameterIconTimer = ICON_STATE_OFF
        self.fParameterList      = [] # index, widget

        if host.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
            self.fPeaksInputCount  = 2
            self.fPeaksOutputCount = 2
        else:
            audioCountInfo = host.get_audio_port_count_info(self.fPluginId)

            self.fPeaksInputCount  = int(audioCountInfo['ins'])
            self.fPeaksOutputCount = int(audioCountInfo['outs'])

            if self.fPeaksInputCount > 2:
                self.fPeaksInputCount = 2

            if self.fPeaksOutputCount > 2:
                self.fPeaksOutputCount = 2

        # used during testing
        self.fIdleTimerId = 0

        # -------------------------------------------------------------
        # Set-up GUI

        self.fEditDialog = PluginEdit(self, host, self.fPluginId)

        # -------------------------------------------------------------
        # Set-up common widgets (as none)

        self.b_enable = None
        self.b_gui    = None
        self.b_edit   = None
        self.b_remove = None

        self.cb_presets = None

        self.label_name = None
        self.label_type = None

        self.led_control   = None
        self.led_midi      = None
        self.led_audio_in  = None
        self.led_audio_out = None

        self.peak_in  = None
        self.peak_out = None

        # -------------------------------------------------------------
        # Set-up connections

        host.PluginRenamedCallback.connect(self.slot_handlePluginRenamedCallback)
        host.PluginUnavailableCallback.connect(self.slot_handlePluginUnavailableCallback)
        host.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback)
        host.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback)
        host.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback)
        host.ParameterMidiCcChangedCallback.connect(self.slot_handleParameterMidiCcChangedCallback)
        host.ProgramChangedCallback.connect(self.slot_handleProgramChangedCallback)
        host.MidiProgramChangedCallback.connect(self.slot_handleMidiProgramChangedCallback)
        host.OptionChangedCallback.connect(self.slot_handleOptionChangedCallback)
        host.UiStateChangedCallback.connect(self.slot_handleUiStateChangedCallback)

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

    @pyqtSlot(int, str)
    def slot_handlePluginRenamedCallback(self, pluginId, newName):
        if self.fPluginId == pluginId:
            self.setName(newName)

    @pyqtSlot(int, str)
    def slot_handlePluginUnavailableCallback(self, pluginId, errorMsg):
        if self.fPluginId == pluginId:
            pass

    @pyqtSlot(int, int, float)
    def slot_handleParameterValueChangedCallback(self, pluginId, index, value):
        if self.fPluginId == pluginId:
            self.setParameterValue(index, value, True)

    @pyqtSlot(int, int, float)
    def slot_handleParameterDefaultChangedCallback(self, pluginId, index, value):
        if self.fPluginId == pluginId:
            self.setParameterDefault(index, value)

    @pyqtSlot(int, int, int)
    def slot_handleParameterMidiCcChangedCallback(self, pluginId, index, cc):
        if self.fPluginId == pluginId:
            self.setParameterMidiControl(index, cc)

    @pyqtSlot(int, int, int)
    def slot_handleParameterMidiChannelChangedCallback(self, pluginId, index, channel):
        if self.fPluginId == pluginId:
            self.setParameterMidiChannel(index, channel)

    @pyqtSlot(int, int)
    def slot_handleProgramChangedCallback(self, pluginId, index):
        if self.fPluginId == pluginId:
            self.setProgram(index, True)


    @pyqtSlot(int, int)
    def slot_handleMidiProgramChangedCallback(self, pluginId, index):
        if self.fPluginId == pluginId:
            self.setMidiProgram(index, True)

    @pyqtSlot(int, int, bool)
    def slot_handleOptionChangedCallback(self, pluginId, option, yesNo):
        if self.fPluginId == pluginId:
            self.setOption(option, yesNo)

    @pyqtSlot(int, int)
    def slot_handleUiStateChangedCallback(self, pluginId, state):
        if self.fPluginId == pluginId:
            self.customUiStateChanged(state)

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

    def ready(self):
        if self.b_enable is not None:
            self.b_enable.setChecked(self.fIsActive)
            self.b_enable.clicked.connect(self.slot_enableClicked)

        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
            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)

        if self.label_name is not None:
            self.label_name.setText(self.fPluginInfo['name'])

        if self.label_type is not None:
            self.label_type.setText(getPluginTypeAsString(self.fPluginInfo['type']))

        if self.led_control is not None:
            self.led_control.setColor(self.led_control.YELLOW)
            self.led_control.setEnabled(False)

        if self.led_midi is not None:
            self.led_midi.setColor(self.led_midi.RED)
            self.led_midi.setEnabled(False)

        if self.led_audio_in is not None:
            self.led_audio_in.setColor(self.led_audio_in.GREEN)
            self.led_audio_in.setEnabled(False)

        if self.led_audio_out is not None:
            self.led_audio_out.setColor(self.led_audio_out.BLUE)
            self.led_audio_out.setEnabled(False)

        if self.peak_in is not None:
            self.peak_in.setColor(DigitalPeakMeter.GREEN)
            self.peak_in.setChannels(self.fPeaksInputCount)
            self.peak_in.setOrientation(DigitalPeakMeter.HORIZONTAL)

        if self.peak_out is not None:
            self.peak_out.setColor(DigitalPeakMeter.BLUE)
            self.peak_out.setChannels(self.fPeaksOutputCount)
            self.peak_out.setOrientation(DigitalPeakMeter.HORIZONTAL)

        for paramIndex, paramWidget in self.fParameterList:
            paramWidget.setContextMenuPolicy(Qt.CustomContextMenu)
            paramWidget.customContextMenuRequested.connect(self.slot_knobCustomMenu)
            paramWidget.realValueChanged.connect(self.slot_parameterValueChanged)
            paramWidget.setValue(self.host.get_internal_parameter_value(self.fPluginId, paramIndex))

        self.setWindowTitle(self.fPluginInfo['name'])

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

    def getFixedHeight(self):
        return 32

    def getHints(self):
        return self.fPluginInfo['hints']

    def getPluginId(self):
        return self.fPluginId

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

    def setPluginId(self, idx):
        self.fPluginId = idx
        self.fEditDialog.setPluginId(idx)

    def setName(self, name):
        self.fEditDialog.setName(name)

        if self.label_name is not None:
            self.label_name.setText(name)

    def setSelected(self, yesNo):
        if self.fIsSelected == yesNo:
            return

        self.fIsSelected = yesNo
        self.update()

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

    def setActive(self, active, sendCallback=False, sendHost=True):
        self.fIsActive = active

        if sendCallback:
            self.fParameterIconTimer = ICON_STATE_ON
            self.activeChanged(active)

        if sendHost:
            self.host.set_active(self.fPluginId, active)

        if active:
            self.fEditDialog.clearNotes()
            self.midiActivityChanged(False)

    # called from rack, checks if param is possible first
    def setInternalParameter(self, parameterId, value):
        if parameterId <= PARAMETER_MAX or parameterId >= PARAMETER_NULL:
            return

        elif parameterId == PARAMETER_ACTIVE:
            return self.setActive(bool(value), True, True)

        elif parameterId == PARAMETER_DRYWET:
            if (self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) == 0: return
            self.host.set_drywet(self.fPluginId, value)

        elif parameterId == PARAMETER_VOLUME:
            if (self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) == 0: return
            self.host.set_volume(self.fPluginId, value)

        elif parameterId == PARAMETER_BALANCE_LEFT:
            if (self.fPluginInfo['hints'] & PLUGIN_CAN_BALANCE) == 0: return
            self.host.set_balance_left(self.fPluginId, value)

        elif parameterId == PARAMETER_BALANCE_RIGHT:
            if (self.fPluginInfo['hints'] & PLUGIN_CAN_BALANCE) == 0: return
            self.host.set_balance_right(self.fPluginId, value)

        elif parameterId == PARAMETER_PANNING:
            if (self.fPluginInfo['hints'] & PLUGIN_CAN_PANNING) == 0: return
            self.host.set_panning(self.fPluginId, value)

        elif parameterId == PARAMETER_CTRL_CHANNEL:
            self.host.set_ctrl_channel(self.fPluginId, value)

        self.fEditDialog.setParameterValue(parameterId, value)

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

    def setParameterValue(self, parameterId, value, sendCallback):
        if parameterId == PARAMETER_ACTIVE:
            return self.setActive(bool(value), True, False)

        self.fEditDialog.setParameterValue(parameterId, value)

        if sendCallback:
            self.fParameterIconTimer = ICON_STATE_ON
            self.editDialogParameterValueChanged(self.fPluginId, parameterId, value)

    def setParameterDefault(self, parameterId, value):
        self.fEditDialog.setParameterDefault(parameterId, value)

    def setParameterMidiControl(self, parameterId, control):
        self.fEditDialog.setParameterMidiControl(parameterId, control)

    def setParameterMidiChannel(self, parameterId, channel):
        self.fEditDialog.setParameterMidiChannel(parameterId, channel)

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

    def setProgram(self, index, sendCallback):
        self.fEditDialog.setProgram(index)

        if sendCallback:
            self.fParameterIconTimer = ICON_STATE_ON
            self.editDialogProgramChanged(self.fPluginId, index)

        self.updateParameterValues()

    def setMidiProgram(self, index, sendCallback):
        self.fEditDialog.setMidiProgram(index)

        if sendCallback:
            self.fParameterIconTimer = ICON_STATE_ON
            self.editDialogMidiProgramChanged(self.fPluginId, index)

        self.updateParameterValues()

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

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

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

    def activeChanged(self, onOff):
        self.fIsActive = onOff

        if self.b_enable is None:
            return

        self.b_enable.blockSignals(True)
        self.b_enable.setChecked(onOff)
        self.b_enable.blockSignals(False)

    def customUiStateChanged(self, state):
        if self.b_gui is None:
            return

        self.b_gui.blockSignals(True)
        if state == 0:
            self.b_gui.setChecked(False)
            self.b_gui.setEnabled(True)
        elif state == 1:
            self.b_gui.setChecked(True)
            self.b_gui.setEnabled(True)
        elif state == -1:
            self.b_gui.setChecked(False)
            self.b_gui.setEnabled(False)
        self.b_gui.blockSignals(False)

    def parameterActivityChanged(self, onOff):
        if self.led_control is None:
            return

        self.led_control.setChecked(onOff)

    def midiActivityChanged(self, onOff):
        if self.led_midi is None:
            return

        self.led_midi.setChecked(onOff)

    def optionChanged(self, option, yesNo):
        pass

    # -----------------------------------------------------------------
    # PluginEdit callbacks

    def editDialogVisibilityChanged(self, pluginId, visible):
        if self.b_edit is None:
            return

        self.b_edit.blockSignals(True)
        self.b_edit.setChecked(visible)
        self.b_edit.blockSignals(False)

    def editDialogPluginHintsChanged(self, pluginId, hints):
        self.fPluginInfo['hints'] = hints

        for paramIndex, paramWidget in self.fParameterList:
            if paramIndex == PARAMETER_DRYWET:
                paramWidget.setVisible(hints & PLUGIN_CAN_DRYWET)
            elif paramIndex == PARAMETER_VOLUME:
                paramWidget.setVisible(hints & PLUGIN_CAN_VOLUME)

        if self.b_gui is not None:
            self.b_gui.setEnabled(bool(hints & PLUGIN_HAS_CUSTOM_UI))

    def editDialogParameterValueChanged(self, pluginId, parameterId, value):
        for paramIndex, paramWidget in self.fParameterList:
            if paramIndex != parameterId:
                continue

            paramWidget.blockSignals(True)
            paramWidget.setValue(value)
            paramWidget.blockSignals(False)
            break

    def editDialogProgramChanged(self, pluginId, index):
        if self.cb_presets is None:
            return

        self.cb_presets.blockSignals(True)
        self.cb_presets.setCurrentIndex(index)
        self.cb_presets.blockSignals(False)

        # FIXME
        self.updateParameterValues()

    def editDialogMidiProgramChanged(self, pluginId, index):
        if self.cb_presets is None:
            return

        self.cb_presets.blockSignals(True)
        self.cb_presets.setCurrentIndex(index)
        self.cb_presets.blockSignals(False)

        # FIXME
        self.updateParameterValues()

    def editDialogNotePressed(self, pluginId, note):
        pass

    def editDialogNoteReleased(self, pluginId, note):
        pass

    def editDialogMidiActivityChanged(self, pluginId, onOff):
        self.midiActivityChanged(onOff)

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

    def idleFast(self):
        # Input peaks
        if self.fPeaksInputCount > 0:
            if self.fPeaksInputCount > 1:
                peak1 = self.host.get_input_peak_value(self.fPluginId, True)
                peak2 = self.host.get_input_peak_value(self.fPluginId, False)
                ledState = bool(peak1 != 0.0 or peak2 != 0.0)

                if self.peak_in is not None:
                    self.peak_in.displayMeter(1, peak1)
                    self.peak_in.displayMeter(2, peak2)

            else:
                peak = self.host.get_input_peak_value(self.fPluginId, True)
                ledState = bool(peak != 0.0)

                if self.peak_in is not None:
                    self.peak_in.displayMeter(1, peak)

            if self.fLastGreenLedState != ledState and self.led_audio_in is not None:
                self.fLastGreenLedState = ledState
                self.led_audio_in.setChecked(ledState)

        # Output peaks
        if self.fPeaksOutputCount > 0:
            if self.fPeaksOutputCount > 1:
                peak1 = self.host.get_output_peak_value(self.fPluginId, True)
                peak2 = self.host.get_output_peak_value(self.fPluginId, False)
                ledState = bool(peak1 != 0.0 or peak2 != 0.0)

                if self.peak_out is not None:
                    self.peak_out.displayMeter(1, peak1)
                    self.peak_out.displayMeter(2, peak2)

            else:
                peak = self.host.get_output_peak_value(self.fPluginId, True)
                ledState = bool(peak != 0.0)

                if self.peak_out is not None:
                    self.peak_out.displayMeter(1, peak)

            if self.fLastBlueLedState != ledState and self.led_audio_out is not None:
                self.fLastBlueLedState = ledState
                self.led_audio_out.setChecked(ledState)

    def idleSlow(self):
        if self.fParameterIconTimer == ICON_STATE_ON:
            self.fParameterIconTimer = ICON_STATE_WAIT1
            self.parameterActivityChanged(True)
        elif self.fParameterIconTimer == ICON_STATE_WAIT1:
            self.fParameterIconTimer = ICON_STATE_WAIT2
        elif self.fParameterIconTimer == ICON_STATE_WAIT2:
            self.fParameterIconTimer = ICON_STATE_OFF
            self.parameterActivityChanged(False)

        self.fEditDialog.idleSlow()

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

    def drawOutline(self):
        painter = QPainter(self)

        if self.fIsSelected:
            painter.setPen(QPen(Qt.cyan, 4))
            painter.setBrush(Qt.transparent)
            painter.drawRect(0, 0, self.width(), self.height())
        else:
            painter.setPen(QPen(Qt.black, 1))
            painter.setBrush(Qt.black)
            painter.drawLine(0, self.height()-1, self.width(), self.height()-1)

    def showDefaultCustomMenu(self, isEnabled, bEdit = None, bGui = None):
        menu = QMenu(self)

        actActive = menu.addAction(self.tr("Disable") if isEnabled else self.tr("Enable"))
        menu.addSeparator()

        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"))
            actEdit.setCheckable(True)
            actEdit.setChecked(bEdit.isChecked())
        else:
            actEdit = None

        if bGui is not None:
            actGui = menu.addAction(self.tr("Show Custom UI"))
            actGui.setCheckable(True)
            actGui.setChecked(bGui.isChecked())
            actGui.setEnabled(bGui.isEnabled())
        else:
            actGui = None

        menu.addSeparator()
        actClone   = menu.addAction(self.tr("Clone"))
        actReplace = menu.addAction(self.tr("Replace..."))
        actRename  = menu.addAction(self.tr("Rename..."))
        actRemove  = menu.addAction(self.tr("Remove"))

        if self.fIdleTimerId != 0:
            actRemove.setVisible(False)

        actSel = menu.exec_(QCursor.pos())

        if not actSel:
            return

        if actSel == actActive:
            self.setActive(not isEnabled, True, True)

        elif actSel == actReset:
            self.host.reset_parameters(self.fPluginId)

        elif actSel == actRandom:
            self.host.randomize_parameters(self.fPluginId)

        elif actSel == actGui:
            bGui.click()

        elif actSel == actEdit:
            bEdit.click()

        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)

        elif actSel == actRename:
            oldName    = self.fPluginInfo['name']
            newNameTry = QInputDialog.getText(self, self.tr("Rename Plugin"), self.tr("New plugin name:"), QLineEdit.Normal, oldName)

            if not (newNameTry[1] and newNameTry[0] and oldName != newNameTry[0]):
                return

            newName = newNameTry[0]

            if self.host.rename_plugin(self.fPluginId, newName):
                self.setName(newName)
            else:
                CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
                                       self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)

        elif actSel == actReplace:
            gCarla.gui.slot_pluginAdd(self.fPluginId)

        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):
        sender  = self.sender()
        index   = sender.fIndex
        minimum = sender.fMinimum
        maximum = sender.fMaximum
        current = sender.fRealValue
        label   = sender.fLabel

        if index in (PARAMETER_DRYWET, PARAMETER_VOLUME):
            default   = 1.0
            resetText = self.tr("Reset (%i%%)" % int(default*100.0))
            minimText = self.tr("Set to Minimum (%i%%)" % int(minimum*100.0))
            maximText = self.tr("Set to Maximum (%i%%)" % int(maximum*100.0))
        else:
            default   = self.host.get_default_parameter_value(self.fPluginId, index)
            resetText = self.tr("Reset (%f)" % default)
            minimText = self.tr("Set to Minimum (%f)" % minimum)
            maximText = self.tr("Set to Maximum (%f)" % maximum)

        menu = QMenu(self)
        actReset = menu.addAction(resetText)
        menu.addSeparator()
        actMinimum = menu.addAction(minimText)
        actMaximum = menu.addAction(maximText)
        menu.addSeparator()
        actSet = menu.addAction(self.tr("Set value..."))

        actSelected = menu.exec_(QCursor.pos())

        if actSelected == actSet:
            valueTry = QInputDialog.getDouble(self, self.tr("Set value"), label, current, minimum, maximum, 3) # FIXME - 3 decimals
            if valueTry[1]:
                value = valueTry[0] * 10
            else:
                return

        elif actSelected == actMinimum:
            value = minimum
        elif actSelected == actMaximum:
            value = maximum
        elif actSelected == actReset:
            value = default
        else:
            return

        self.sender().setValue(value)

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

    @pyqtSlot(bool)
    def slot_showCustomUi(self, show):
        self.host.show_custom_ui(self.fPluginId, show)

    @pyqtSlot(bool)
    def slot_showEditDialog(self, show):
        self.fEditDialog.setVisible(show)

    @pyqtSlot()
    def slot_removePlugin(self):
        self.host.remove_plugin(self.fPluginId)

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

    @pyqtSlot(int)
    def slot_parameterValueChanged(self, value):
        index = self.sender().getIndex()

        if index < 0:
            self.setInternalParameter(index, value)
        else:
            self.host.set_parameter_value(self.fPluginId, index, value)
            self.setParameterValue(index, value, False)

    @pyqtSlot(int)
    def slot_programChanged(self, index):
        self.host.set_program(self.fPluginId, index)
        self.setProgram(index, False)

    @pyqtSlot(int)
    def slot_midiProgramChanged(self, index):
        self.host.set_midi_program(self.fPluginId, index)
        self.setMidiProgram(index, False)

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

    def testTimer(self):
        self.fIdleTimerId = self.startTimer(25)

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

    def closeEvent(self, event):
        if self.fIdleTimerId != 0:
            self.killTimer(self.fIdleTimerId)
            self.fIdleTimerId = 0

            self.host.engine_close()

        QFrame.closeEvent(self, event)

    def timerEvent(self, event):
        if event.timerId() == self.fIdleTimerId:
            self.host.engine_idle()
            self.idleFast()
            self.idleSlow()

        QFrame.timerEvent(self, event)

    def paintEvent(self, event):
        self.drawOutline()
        QFrame.paintEvent(self, event)

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

class PluginSlot_Default(AbstractPluginSlot):
    def __init__(self, parent, host, pluginId):
        AbstractPluginSlot.__init__(self, parent, host, pluginId)
        self.ui = ui_carla_plugin_default.Ui_PluginWidget()
        self.ui.setupUi(self)

        # -------------------------------------------------------------
        # Internal stuff

        self.fColorTop    = QColor(60, 60, 60)
        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
        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.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 36

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

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

        areaX  = self.ui.area_right.x()+7
        width  = self.width()
        height = self.height()

        painter.setPen(QPen(QColor(17, 17, 17), 1))
        painter.setBrush(QColor(17, 17, 17))
        painter.drawRect(0, 0, width, height)

        painter.setPen(self.fColorSeprtr.lighter(110))
        painter.setBrush(self.fColorBottom)
        painter.setRenderHint(QPainter.Antialiasing, True)

        # name -> leds arc
        path = QPainterPath()
        path.moveTo(areaX-20, height-4)
        path.cubicTo(areaX, height-5, areaX-20, 4.75, areaX, 4.75)
        path.lineTo(areaX, height-5)
        painter.drawPath(path)

        painter.setPen(self.fColorSeprtr)
        painter.setRenderHint(QPainter.Antialiasing, False)

        # separator lines
        painter.drawLine(0, height-5, areaX-20, height-5)
        painter.drawLine(areaX, 4, width, 4)

        painter.setPen(self.fColorBottom)
        painter.setBrush(self.fColorBottom)

        # top, bottom and left lines
        painter.drawLine(0, 0, width, 0)
        painter.drawRect(0, height-4, areaX, 4)
        painter.drawRoundedRect(areaX-20, height-5, areaX, 5, 22, 22)
        painter.drawLine(0, 0, 0, height)

        # fill the rest
        painter.drawRect(areaX-1, 5, width, height)

        # bottom 1px line
        painter.setPen(self.fColorSeprtr)
        painter.drawLine(0, height-1, width, height-1)

        painter.restore()
        AbstractPluginSlot.paintEvent(self, event)

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

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()
        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)

        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;
            }
        """ % (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")

        # -------------------------------------------------------------
        # Set-up parameters

        parameterCount = self.host.get_parameter_count(self.fPluginId)

        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_ENABLED) == 0:
                continue

            paramName = getParameterShortName(paramInfo['name'])

            #if self.fPluginInfo['category'] == PLUGIN_CATEGORY_FILTER:
                #_r =  55 + float(i)/8*200
                #_g = 255 - float(i)/8*200
                #_b = 127 - r*2
            #elif self.fPluginInfo['category'] == PLUGIN_CATEGORY_DELAY:
                #_r = 127
                #_g =  55 + float(i)/8*200
                #_b = 255 - float(i)/8*200
            #elif r < b < g:
                #_r =  55 + float(i)/8*200
                #_g = 127
                #_b = 255 - float(i)/8*200
            #else:
            _r = 255 - float(index)/8*200
            _g =  55 + float(index)/8*200
            _b =  (r-40)*4

            #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

            self.fParameterList.append([i, widget])

        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.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.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 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(60, 60, 60), 1))
        painter.drawLine(0, 0, self.width(), 0)

        AbstractPluginSlot.paintEvent(self, event)

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

class PluginSlot_Calf(AbstractPluginSlot):
    def __init__(self, parent, host, pluginId):
        AbstractPluginSlot.__init__(self, parent, host, pluginId)
        self.ui = ui_carla_plugin_calf.Ui_PluginWidget()
        self.ui.setupUi(self)

        audioCount = self.host.get_audio_port_count_info(self.fPluginId)
        midiCount  = self.host.get_midi_port_count_info(self.fPluginId)

        # -------------------------------------------------------------
        # Internal stuff

        self.fButtonFont = self.ui.b_gui.font()
        self.fButtonFont.setBold(False)
        self.fButtonFont.setPointSize(8)

        # Use black for mono plugins
        self.fBackgroundBlack = audioCount['ins'] == 1

        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;
            }
            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.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)
        self.ui.b_remove.setTopText(self.tr("Remove"), self.fButtonColorOn, self.fButtonFont)

        if self.fPluginInfo['hints'] & PLUGIN_HAS_CUSTOM_UI:
            self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOn, self.fButtonFont)
        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)

        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()
            self.ui.led_midi.hide()

        if self.fIdleTimerId != 0:
            self.ui.b_remove.setEnabled(False)
            self.ui.b_remove.setVisible(False)

        # -------------------------------------------------------------
        # Set-up parameters

        parameterCount = self.host.get_parameter_count(self.fPluginId)

        index = 0
        limit = 7 if midiCount['ins'] == 0 else 6
        for i in range(parameterCount):
            if index >= limit:
                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_ENABLED) == 0:
                continue

            paramName = getParameterShortName(paramInfo['name'])

            widget = PixmapDial(self, i)
            widget.setPixmap(7)
            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.b_gui    = self.ui.b_gui
        self.b_edit   = self.ui.b_edit
        self.b_remove = self.ui.b_remove

        self.label_name = self.ui.label_name
        self.led_midi   = self.ui.led_midi

        self.peak_in  = self.ui.peak_in
        self.peak_out = self.ui.peak_out

        self.ready()

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

        self.customContextMenuRequested.connect(self.slot_showDefaultCustomMenu)

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

    def getFixedHeight(self):
        return 88

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

    def editDialogPluginHintsChanged(self, pluginId, hints):
        if hints & PLUGIN_HAS_CUSTOM_UI:
            self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOn, self.fButtonFont)
        else:
            self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOff, self.fButtonFont)

        AbstractPluginSlot.editDialogPluginHintsChanged(self, pluginId, hints)

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

    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)

        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_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)

        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.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 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(60, 60, 60), 1))
        painter.drawLine(0, 0, self.width(), 0)

        AbstractPluginSlot.paintEvent(self, event)

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

class PluginSlot_Nekobi(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

        self.fPixmapCenter = QPixmap(":/bitmaps/background_nekobi.png")

        self.fPixmapLeft     = QPixmap(":/bitmaps/background_nekobi_left.png")
        self.fPixmapLeftRect = QRectF(0, 0, self.fPixmapLeft.width(), self.fPixmapLeft.height())

        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):
        return 108

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

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

        # main bg (center)
        painter.drawTiledPixmap(0, 0, self.width(), self.height(), self.fPixmapCenter)

        # left side
        painter.drawPixmap(self.fPixmapLeftRect, self.fPixmapLeft, self.fPixmapLeftRect)

        # right side
        rightTarget = QRectF(self.fPixmapRightRect)
        rightTarget.moveLeft(self.width()-rightTarget.width())
        painter.drawPixmap(rightTarget, self.fPixmapRight, self.fPixmapRightRect)

        AbstractPluginSlot.paintEvent(self, event)

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

class PluginSlot_SF2(AbstractPluginSlot):
    def __init__(self, parent, host, pluginId):
        AbstractPluginSlot.__init__(self, parent, host, pluginId)
        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)

        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_ENABLED) == 0:
                continue

            paramName = getParameterShortName(paramInfo['name'])

            widget = PixmapDial(self, i)
            widget.setPixmap(3)
            widget.setLabel(paramName)
            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_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_VOLUME, self.ui.dial_vol])

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

        self.b_enable = self.ui.b_enable
        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_out = self.ui.led_audio_out

        self.peak_out = self.ui.peak_out

        self.ready()

        self.customContextMenuRequested.connect(self.slot_showDefaultCustomMenu)

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

    def getFixedHeight(self):
        return 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(60, 60, 60), 1))
        painter.drawLine(0, 0, self.width(), 0)

        AbstractPluginSlot.paintEvent(self, event)

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

class PluginSlot_ZitaRev(AbstractPluginSlot):
    def __init__(self, parent, host, pluginId):
        AbstractPluginSlot.__init__(self, parent, host, pluginId)
        self.ui = ui_carla_plugin_zita.Ui_PluginWidget()
        self.ui.setupUi(self)

        # -------------------------------------------------------------
        # Internal stuff

        audioCount = self.host.get_audio_port_count_info(self.fPluginId)

        # -------------------------------------------------------------
        # Set-up GUI

        self.setMinimumWidth(640)

        self.setStyleSheet("""
            PluginSlot_ZitaRev#PluginWidget {
                background-color: #404040;
                border: 2px solid transparent;
            }
            QWidget#w_revsect {
                background-image: url(:/bitmaps/zita-rev/revsect.png);
            }
            QWidget#w_eq1sect {
                background-image: url(:/bitmaps/zita-rev/eq1sect.png);
            }
            QWidget#w_eq2sect {
                background-image: url(:/bitmaps/zita-rev/eq2sect.png);
            }
            QWidget#w_ambmixsect {
                background-image: url(:/bitmaps/zita-rev/%s.png);
            }
            QWidget#w_redzita {
                background-image: url(:/bitmaps/zita-rev/redzita.png);
            }
        """ % ("mixsect" if audioCount['outs'] == 2 else "ambsect"))

        # -------------------------------------------------------------
        # Set-up Knobs

        self.fKnobDelay = PixmapDial(self, 0)
        self.fKnobDelay.setPixmap(6)
        self.fKnobDelay.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobDelay.setMinimum(0.02)
        self.fKnobDelay.setMaximum(0.10)

        self.fKnobXover = PixmapDial(self, 1)
        self.fKnobXover.setPixmap(6)
        self.fKnobXover.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobXover.setMinimum(50.0)
        self.fKnobXover.setMaximum(1000.0)

        self.fKnobRtLow = PixmapDial(self, 2)
        self.fKnobRtLow.setPixmap(6)
        self.fKnobRtLow.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobRtLow.setMinimum(1.0)
        self.fKnobRtLow.setMaximum(8.0)

        self.fKnobRtMid = PixmapDial(self, 3)
        self.fKnobRtMid.setPixmap(6)
        self.fKnobRtMid.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobRtMid.setMinimum(1.0)
        self.fKnobRtMid.setMaximum(8.0)

        self.fKnobDamping = PixmapDial(self, 4)
        self.fKnobDamping.setPixmap(6)
        self.fKnobDamping.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobDamping.setMinimum(1500.0)
        self.fKnobDamping.setMaximum(24000.0)

        self.fKnobEq1Freq = PixmapDial(self, 5)
        self.fKnobEq1Freq.setPixmap(6)
        self.fKnobEq1Freq.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobEq1Freq.setMinimum(40.0)
        self.fKnobEq1Freq.setMaximum(10000.0)

        self.fKnobEq1Gain = PixmapDial(self, 6)
        self.fKnobEq1Gain.setPixmap(6)
        self.fKnobEq1Gain.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobEq1Gain.setMinimum(-20.0)
        self.fKnobEq1Gain.setMaximum(20.0)

        self.fKnobEq2Freq = PixmapDial(self, 7)
        self.fKnobEq2Freq.setPixmap(6)
        self.fKnobEq2Freq.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobEq2Freq.setMinimum(40.0)
        self.fKnobEq2Freq.setMaximum(10000.0)

        self.fKnobEq2Gain = PixmapDial(self, 8)
        self.fKnobEq2Gain.setPixmap(6)
        self.fKnobEq2Gain.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobEq2Gain.setMinimum(-20.0)
        self.fKnobEq2Gain.setMaximum(20.0)

        self.fKnobMix = PixmapDial(self, 9)
        self.fKnobMix.setPixmap(6)
        self.fKnobMix.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_ZITA)
        self.fKnobMix.setMinimum(0.0)
        self.fKnobMix.setMaximum(1.0)

        self.fParameterList.append([0, self.fKnobDelay])
        self.fParameterList.append([1, self.fKnobXover])
        self.fParameterList.append([2, self.fKnobRtLow])
        self.fParameterList.append([3, self.fKnobRtMid])
        self.fParameterList.append([4, self.fKnobDamping])
        self.fParameterList.append([5, self.fKnobEq1Freq])
        self.fParameterList.append([6, self.fKnobEq1Gain])
        self.fParameterList.append([7, self.fKnobEq2Freq])
        self.fParameterList.append([8, self.fKnobEq2Gain])
        self.fParameterList.append([9, self.fKnobMix])

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

        self.ready()

        self.customContextMenuRequested.connect(self.slot_showDefaultCustomMenu)

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

    def getFixedHeight(self):
        return 79

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

    def paintEvent(self, event):
        AbstractPluginSlot.paintEvent(self, event)
        self.drawOutline()

    def resizeEvent(self, event):
        self.fKnobDelay.move(self.ui.w_revsect.x()+31, self.ui.w_revsect.y()+33)
        self.fKnobXover.move(self.ui.w_revsect.x()+93, self.ui.w_revsect.y()+18)
        self.fKnobRtLow.move(self.ui.w_revsect.x()+148, self.ui.w_revsect.y()+18)
        self.fKnobRtMid.move(self.ui.w_revsect.x()+208, self.ui.w_revsect.y()+18)
        self.fKnobDamping.move(self.ui.w_revsect.x()+268, self.ui.w_revsect.y()+18)
        self.fKnobEq1Freq.move(self.ui.w_eq1sect.x()+20, self.ui.w_eq1sect.y()+33)
        self.fKnobEq1Gain.move(self.ui.w_eq1sect.x()+69, self.ui.w_eq1sect.y()+18)
        self.fKnobEq2Freq.move(self.ui.w_eq2sect.x()+20, self.ui.w_eq2sect.y()+33)
        self.fKnobEq2Gain.move(self.ui.w_eq2sect.x()+69, self.ui.w_eq2sect.y()+18)
        self.fKnobMix.move(self.ui.w_ambmixsect.x()+24, self.ui.w_ambmixsect.y()+33)
        AbstractPluginSlot.resizeEvent(self, event)

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

class PluginSlot_ZynFX(AbstractPluginSlot):
    def __init__(self, parent, host, pluginId):
        AbstractPluginSlot.__init__(self, parent, host, pluginId)
        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)

        index = 0
        for i in range(parameterCount):
            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_ENABLED) == 0:
                continue

            paramName = paramInfo['name']

            # real zyn fx plugins
            if self.fPluginInfo['label'] == "zynalienwah":
                if   i == 0: paramName = "Freq"
                elif i == 1: paramName = "Rnd"
                elif i == 2: paramName = "L type" # combobox
                elif i == 3: paramName = "St.df"
                elif i == 5: paramName = "Fb"
                elif i == 7: paramName = "L/R"

            elif self.fPluginInfo['label'] == "zynchorus":
                if   i == 0: paramName = "Freq"
                elif i == 1: paramName = "Rnd"
                elif i == 2: paramName = "L type" # combobox
                elif i == 3: paramName = "St.df"
                elif i == 6: paramName = "Fb"
                elif i == 7: paramName = "L/R"
                elif i == 8: paramName = "Flngr" # button
                elif i == 9: paramName = "Subst" # button

            elif self.fPluginInfo['label'] == "zyndistortion":
                if   i == 0: paramName = "LRc."
                elif i == 4: paramName = "Neg." # button
                elif i == 5: paramName = "LPF"
                elif i == 6: paramName = "HPF"
                elif i == 7: paramName = "St." # button
                elif i == 8: paramName = "PF"  # button

            elif self.fPluginInfo['label'] == "zyndynamicfilter":
                if   i == 0: paramName = "Freq"
                elif i == 1: paramName = "Rnd"
                elif i == 2: paramName = "L type" # combobox
                elif i == 3: paramName = "St.df"
                elif i == 4: paramName = "LfoD"
                elif i == 5: paramName = "A.S."
                elif i == 6: paramName = "A.Inv." # button
                elif i == 7: paramName = "A.M."

            elif self.fPluginInfo['label'] == "zynecho":
                if   i == 1: paramName = "LRdl."
                elif i == 2: paramName = "LRc."
                elif i == 3: paramName = "Fb."
                elif i == 4: paramName = "Damp"

            elif self.fPluginInfo['label'] == "zynphaser":
                if   i ==  0: paramName = "Freq"
                elif i ==  1: paramName = "Rnd"
                elif i ==  2: paramName = "L type" # combobox
                elif i ==  3: paramName = "St.df"
                elif i ==  5: paramName = "Fb"
                elif i ==  7: paramName = "L/R"
                elif i ==  8: paramName = "Subst" # button
                elif i ==  9: paramName = "Phase"
                elif i == 11: paramName = "Dist"

            elif self.fPluginInfo['label'] == "zynreverb":
                if   i ==  2: paramName = "I.delfb"
                elif i ==  5: paramName = "LPF"
                elif i ==  6: paramName = "HPF"
                elif i ==  9: paramName = "R.S."
                elif i == 10: paramName = "I.del"

            else:
                paramName = getParameterShortName(paramInfo['name'])

            widget = PixmapDial(self, i)

            widget.setPixmap(5)
            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(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

        midiProgramCount = self.host.get_midi_program_count(self.fPluginId)

        if midiProgramCount > 0:
            self.ui.cb_presets.setEnabled(True)
            self.ui.label_presets.setEnabled(True)

            for i in range(midiProgramCount):
                mpData = self.host.get_midi_program_data(self.fPluginId, i)
                mpName = mpData['name']

                self.ui.cb_presets.addItem(mpName)

            self.fCurrentMidiProgram = self.host.get_current_midi_program_index(self.fPluginId)
            self.ui.cb_presets.setCurrentIndex(self.fCurrentMidiProgram)

        else:
            self.fCurrentMidiProgram = -1
            self.ui.cb_presets.setEnabled(False)
            self.ui.cb_presets.setVisible(False)
            self.ui.label_presets.setEnabled(False)
            self.ui.label_presets.setVisible(False)

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

        self.b_enable = self.ui.b_enable
        self.b_edit   = self.ui.b_edit

        self.cb_presets = self.ui.cb_presets

        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.peak_in  = self.ui.peak_in
        self.peak_out = self.ui.peak_out

        self.ready()

        self.customContextMenuRequested.connect(self.slot_showDefaultCustomMenu)
        self.ui.cb_presets.currentIndexChanged.connect(self.slot_midiProgramChanged)

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

    def getFixedHeight(self):
        return 77

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

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setBrush(Qt.transparent)

        painter.setPen(QPen(QColor(60, 60, 60), 1))
        painter.drawRect(0, 1, self.width()-1, self.height()-3)

        painter.setPen(QPen(QColor(94, 94, 94), 1))
        painter.drawLine(0, 0, self.width(), 0)

        AbstractPluginSlot.paintEvent(self, event)

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

def createPluginSlot(parent, host, pluginId, useSkins):
    if not useSkins:
        return PluginSlot_Default(parent, host, pluginId)

    pluginInfo  = host.get_plugin_info(pluginId)
    pluginName  = host.get_real_plugin_name(pluginId)
    pluginLabel = pluginInfo['label']
    pluginMaker = pluginInfo['maker']
    uniqueId    = pluginInfo['uniqueId']

    #pluginIcon  = pluginInfo['iconName']

    if pluginInfo['type'] == PLUGIN_SF2:
        return PluginSlot_SF2(parent, host, pluginId)

    if pluginMaker == "OpenAV Productions":
        return PluginSlot_OpenAV(parent, host, pluginId)

    if pluginInfo['type'] == PLUGIN_INTERNAL:
        if pluginLabel.startswith("zyn") and pluginInfo['category'] != PLUGIN_CATEGORY_SYNTH:
            return PluginSlot_ZynFX(parent, host, pluginId)

    elif pluginInfo['type'] == PLUGIN_LADSPA:
        if (pluginLabel == "zita-reverb" and uniqueId == 3701) or (pluginLabel == "zita-reverb-amb" and uniqueId == 3702):
            return PluginSlot_ZitaRev(parent, host, pluginId)
        if pluginLabel.startswith("Zyn") and pluginMaker.startswith("Josep Andreu"):
            return PluginSlot_ZynFX(parent, host, pluginId)

    if pluginName.split(" ", 1)[0].lower() == "calf":
        return PluginSlot_Calf(parent, host, pluginId)

    #if pluginName.lower() == "nekobi":
        #return PluginSlot_Nekobi(parent, pluginId)

    return PluginSlot_BasicFX(parent, host, pluginId)

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

if __name__ == '__main__':
    from carla_app import CarlaApplication
    from carla_host import initHost, loadHostSettings
    import resources_rc

    app = CarlaApplication("Carla-Skins")
    host = initHost("Skins", None, False, False, False)
    loadHostSettings(host)

    host.engine_init("JACK", "Carla-Widgets")
    host.add_plugin(BINARY_NATIVE, PLUGIN_INTERNAL, "", "", "zynreverb", 0, None)
    #host.add_plugin(BINARY_NATIVE, PLUGIN_DSSI, "/usr/lib/dssi/karplong.so", "karplong", "karplong", 0, None)
    #host.add_plugin(BINARY_NATIVE, PLUGIN_LV2, "", "", "http://www.openavproductions.com/sorcer", 0, None)
    #host.add_plugin(BINARY_NATIVE, PLUGIN_LV2, "", "", "http://calf.sourceforge.net/plugins/Compressor", 0, None)
    host.set_active(0, True)

    gui = createPluginSlot(None, host, 0, True)
    gui.testTimer()
    gui.show()

    app.exec_()
