Signed-off-by: falkTX <falktx@falktx.com>tags/v2.1-rc1
| @@ -988,7 +988,13 @@ typedef enum { | |||
| /*! | |||
| * The engine has crashed or malfunctioned and will no longer work. | |||
| */ | |||
| ENGINE_CALLBACK_QUIT = 41 | |||
| ENGINE_CALLBACK_QUIT = 41, | |||
| /*! | |||
| * A plugin requested for its inline display to be redrawn. | |||
| * @a pluginId Plugin Id to redraw | |||
| */ | |||
| ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW = 42, | |||
| } EngineCallbackOpcode; | |||
| @@ -37,6 +37,7 @@ extern "C" { | |||
| } | |||
| #include "water/files/File.h" | |||
| #include "water/misc/Time.h" | |||
| #include <string> | |||
| #include <vector> | |||
| @@ -528,6 +529,8 @@ public: | |||
| fParamBuffers(nullptr), | |||
| fNeedsFixedBuffers(false), | |||
| fNeedsUiClose(false), | |||
| fInlineDisplayNeedsRedraw(false), | |||
| fInlineDisplayLastRedrawTime(0), | |||
| fLatencyIndex(-1), | |||
| fStrictBounds(-1), | |||
| fAtomBufferEvIn(), | |||
| @@ -1689,6 +1692,21 @@ public: | |||
| } | |||
| } | |||
| if (fInlineDisplayNeedsRedraw) | |||
| { | |||
| const int64_t timeNow = water::Time::currentTimeMillis(); | |||
| if (timeNow - fInlineDisplayLastRedrawTime > (1000 / 30)) | |||
| { | |||
| fInlineDisplayNeedsRedraw = false; | |||
| fInlineDisplayLastRedrawTime = timeNow; | |||
| pData->engine->callback(true, true, | |||
| ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW, | |||
| pData->id, | |||
| 0, 0, 0, 0.0f, nullptr); | |||
| } | |||
| } | |||
| CarlaPlugin::idle(); | |||
| } | |||
| @@ -2698,7 +2716,7 @@ public: | |||
| pData->options &= ~PLUGIN_OPTION_FORCE_STEREO; | |||
| // plugin hints | |||
| pData->hints = 0x0; | |||
| pData->hints = (pData->hints & PLUGIN_HAS_INLINE_DISPLAY) ? PLUGIN_HAS_INLINE_DISPLAY : 0; | |||
| if (isRealtimeSafe()) | |||
| pData->hints |= PLUGIN_IS_RTSAFE; | |||
| @@ -4677,8 +4695,11 @@ public: | |||
| if (pData->hints & PLUGIN_HAS_EXTENSION_WORKER) | |||
| fExt.worker = (const LV2_Worker_Interface*)fDescriptor->extension_data(LV2_WORKER__interface); | |||
| if (pData->hints & PLUGIN_HAS_EXTENSION_INLINE_DISPLAY) | |||
| // FIXME | |||
| // if (pData->hints & PLUGIN_HAS_EXTENSION_INLINE_DISPLAY) | |||
| { | |||
| fExt.inlineDisplay = (const LV2_Inline_Display_Interface*)fDescriptor->extension_data(LV2_INLINEDISPLAY__interface); | |||
| } | |||
| // check if invalid | |||
| if (fExt.options != nullptr && fExt.options->get == nullptr && fExt.options->set == nullptr) | |||
| @@ -4997,7 +5018,7 @@ public: | |||
| void handleInlineDisplayQueueRedraw() | |||
| { | |||
| // TODO | |||
| fInlineDisplayNeedsRedraw = true; | |||
| } | |||
| LV2_Inline_Display_Image_Surface* renderInlineDisplay(int width, int height) | |||
| @@ -6121,6 +6142,8 @@ private: | |||
| bool fNeedsFixedBuffers; | |||
| bool fNeedsUiClose; | |||
| bool fInlineDisplayNeedsRedraw; | |||
| int64_t fInlineDisplayLastRedrawTime; | |||
| int32_t fLatencyIndex; // -1 if invalid | |||
| int fStrictBounds; // -1 unsupported, 0 optional, 1 required | |||
| @@ -22,6 +22,8 @@ | |||
| from abc import ABCMeta, abstractmethod | |||
| from ctypes import * | |||
| from platform import architecture | |||
| from sip import voidptr | |||
| from struct import pack | |||
| from sys import platform, maxsize | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| @@ -726,6 +728,10 @@ ENGINE_CALLBACK_ERROR = 40 | |||
| # The engine has crashed or malfunctioned and will no longer work. | |||
| ENGINE_CALLBACK_QUIT = 41 | |||
| # A plugin requested for its inline display to be redrawn. | |||
| # @a pluginId Plugin Id to redraw | |||
| ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW = 42 | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # NSM Callback Opcode | |||
| # NSM callback opcodes. | |||
| @@ -2818,7 +2824,20 @@ class CarlaHostDLL(CarlaHostMeta): | |||
| return float(self.lib.carla_get_output_peak_value(pluginId, isLeft)) | |||
| def render_inline_display(self, pluginId, width, height): | |||
| return structToDict(self.lib.carla_render_inline_display(pluginId, width, height)) | |||
| ptr = self.lib.carla_render_inline_display(pluginId, width, height) | |||
| if not ptr or not ptr.contents: | |||
| return None | |||
| contents = ptr.contents | |||
| datalen = contents.height * contents.stride | |||
| unpacked = tuple(contents.data[i] for i in range(datalen)) | |||
| packed = pack("%iB" % datalen, *unpacked) | |||
| data = { | |||
| 'data': voidptr(packed), | |||
| 'width': contents.width, | |||
| 'height': contents.height, | |||
| 'stride': contents.stride, | |||
| } | |||
| return data | |||
| def set_option(self, pluginId, option, yesNo): | |||
| self.lib.carla_set_option(pluginId, option, yesNo) | |||
| @@ -72,6 +72,7 @@ class CarlaHostSignals(QObject): | |||
| InfoCallback = pyqtSignal(str) | |||
| ErrorCallback = pyqtSignal(str) | |||
| QuitCallback = pyqtSignal() | |||
| InlineDisplayRedrawCallback = pyqtSignal(int) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Carla Host object (dummy/null, does nothing) | |||
| @@ -526,6 +526,7 @@ class HostWindow(QMainWindow): | |||
| host.InfoCallback.connect(self.slot_handleInfoCallback) | |||
| host.ErrorCallback.connect(self.slot_handleErrorCallback) | |||
| host.QuitCallback.connect(self.slot_handleQuitCallback) | |||
| host.InlineDisplayRedrawCallback.connect(self.slot_handleInlineDisplayRedrawCallback) | |||
| # ---------------------------------------------------------------------------------------------------- | |||
| # Final setup | |||
| @@ -1550,7 +1551,7 @@ class HostWindow(QMainWindow): | |||
| if pluginId == MAIN_CARLA_PLUGIN_ID: | |||
| hasCustomUI = False | |||
| hasInlineDisplay = False | |||
| hasInlineDisplay = 69 #False | |||
| else: | |||
| hints = self.host.get_plugin_info(pluginId)['hints'] | |||
| hasCustomUI = bool(hints & PLUGIN_HAS_CUSTOM_UI) | |||
| @@ -2199,6 +2200,10 @@ class HostWindow(QMainWindow): | |||
| self.removeAllPlugins() | |||
| self.projectLoadingFinished() | |||
| @pyqtSlot(int) | |||
| def slot_handleInlineDisplayRedrawCallback(self, pluginId): | |||
| patchcanvas.redrawPluginGroup(pluginId) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| @pyqtSlot() | |||
| @@ -2597,6 +2602,13 @@ def canvasCallback(action, value1, value2, valueStr): | |||
| elif action == patchcanvas.ACTION_BG_RIGHT_CLICK: | |||
| gCarla.gui.showPluginActionsMenu() | |||
| elif action == patchcanvas.ACTION_INLINE_DISPLAY: | |||
| # FIXME | |||
| if gCarla.gui.fPluginCount == 0: return | |||
| pluginId = value1 | |||
| width, height = [int(v) for v in valueStr.split(":")] | |||
| return host.render_inline_display(pluginId, width, height) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Engine callback | |||
| @@ -2700,6 +2712,10 @@ def engineCallback(host, action, pluginId, value1, value2, value3, valuef, value | |||
| host.ErrorCallback.emit(valueStr) | |||
| elif action == ENGINE_CALLBACK_QUIT: | |||
| host.QuitCallback.emit() | |||
| elif action == ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW: | |||
| host.InlineDisplayRedrawCallback.emit(pluginId) | |||
| else: | |||
| print("unhandled action", action) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # File callback | |||
| @@ -60,6 +60,7 @@ ACTION_PLUGIN_REPLACE = 11 # plugin_id, N, N | |||
| ACTION_PLUGIN_REMOVE = 12 # plugin_id, N, N | |||
| ACTION_PLUGIN_SHOW_UI = 13 # plugin_id, N, N | |||
| ACTION_BG_RIGHT_CLICK = 14 # N, N, N | |||
| ACTION_INLINE_DISPLAY = 15 # plugin_id, N, N | |||
| # Icon | |||
| ICON_APPLICATION = 0 | |||
| @@ -20,7 +20,7 @@ | |||
| # Imports (Global) | |||
| from PyQt5.QtCore import qCritical, Qt, QPointF, QRectF, QTimer | |||
| from PyQt5.QtGui import QCursor, QFont, QFontMetrics, QLinearGradient, QPainter, QPen | |||
| from PyQt5.QtGui import QCursor, QFont, QFontMetrics, QImage, QLinearGradient, QPainter, QPen | |||
| from PyQt5.QtWidgets import QGraphicsItem, QMenu | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| @@ -44,6 +44,7 @@ from . import ( | |||
| ACTION_GROUP_SPLIT, | |||
| ACTION_GROUP_RENAME, | |||
| ACTION_PORTS_DISCONNECT, | |||
| ACTION_INLINE_DISPLAY, | |||
| EYECANDY_FULL, | |||
| PORT_MODE_NULL, | |||
| PORT_MODE_INPUT, | |||
| @@ -87,6 +88,8 @@ class CanvasBox(QGraphicsItem): | |||
| # Base Variables | |||
| self.p_width = 50 | |||
| self.p_width_in = 0 | |||
| self.p_width_out = 0 | |||
| self.p_height = canvas.theme.box_header_height + canvas.theme.box_header_spacing + 1 | |||
| self.m_last_pos = QPointF() | |||
| @@ -259,7 +262,7 @@ class CanvasBox(QGraphicsItem): | |||
| # Check Text Name size | |||
| app_name_size = QFontMetrics(self.m_font_name).width(self.m_group_name) + 30 | |||
| self.p_width = max(50, app_name_size) | |||
| self.p_width = max(200 if self.m_plugin_inline else 50, app_name_size) | |||
| # Get Port List | |||
| port_list = [] | |||
| @@ -269,6 +272,8 @@ class CanvasBox(QGraphicsItem): | |||
| if len(port_list) == 0: | |||
| self.p_height = canvas.theme.box_header_height | |||
| self.p_width_in = 0 | |||
| self.p_width_out = 0 | |||
| else: | |||
| max_in_width = max_out_width = 0 | |||
| port_spacing = canvas.theme.port_height + canvas.theme.port_spacing | |||
| @@ -303,7 +308,12 @@ class CanvasBox(QGraphicsItem): | |||
| port.widget.setY(last_out_pos) | |||
| last_out_pos += port_spacing | |||
| self.p_width = max(self.p_width, 30 + max_in_width + max_out_width) | |||
| self.p_width = max(self.p_width, (100 if self.m_plugin_inline else 30) + max_in_width + max_out_width) | |||
| self.p_width_in = max_in_width | |||
| self.p_width_out = max_out_width | |||
| #if self.m_plugin_inline: | |||
| #self.p_width += 10 | |||
| # Horizontal ports re-positioning | |||
| inX = canvas.theme.port_offset | |||
| @@ -609,6 +619,19 @@ class CanvasBox(QGraphicsItem): | |||
| rect.adjust(lineHinting, lineHinting, -lineHinting, -lineHinting) | |||
| painter.drawRect(rect) | |||
| # Draw plugin inline display if supported | |||
| if self.m_plugin_id >= 0 and self.m_plugin_id <= MAX_PLUGIN_ID_ALLOWED and self.m_plugin_inline: | |||
| size = "%i:%i" % (self.p_width - self.p_width_in - self.p_width_out - 16, | |||
| self.p_height - canvas.theme.box_header_height) | |||
| data = canvas.callback(ACTION_INLINE_DISPLAY, self.m_plugin_id, 0, size) | |||
| if data is not None: | |||
| image = QImage(data['data'], data['width'], data['height'], data['stride'], QImage.Format_ARGB32) | |||
| painter.drawImage(self.p_width_in + 7, | |||
| canvas.theme.box_header_height | |||
| + (self.p_height - canvas.theme.box_header_height) / 2 | |||
| - data['height'] / 2 - 1, | |||
| image) | |||
| # Draw pixmap header | |||
| rect.setHeight(canvas.theme.box_header_height) | |||
| if canvas.theme.box_header_pixmap: | |||
| @@ -690,6 +690,18 @@ def setGroupAsPlugin(group_id, plugin_id, hasUI, hasInlineDisplay): | |||
| qCritical("PatchCanvas::setGroupAsPlugin(%i, %i, %s, %s) - unable to find group to set as plugin" % ( | |||
| group_id, plugin_id, bool2str(hasUI), bool2str(hasInlineDisplay))) | |||
| def redrawPluginGroup(plugin_id): | |||
| for group in canvas.group_list: | |||
| if group.plugin_id == plugin_id: | |||
| group.widgets[0].update() | |||
| if group.split and group.widgets[1]: | |||
| group.widgets[1].update() | |||
| return | |||
| qCritical("PatchCanvas::redrawPluginGroup(%i) - unable to find group" % plugin_id) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| def addPort(group_id, port_id, port_name, port_mode, port_type, is_alternate=False): | |||
| @@ -284,6 +284,8 @@ const char* EngineCallbackOpcode2Str(const EngineCallbackOpcode opcode) noexcept | |||
| return "ENGINE_CALLBACK_ERROR"; | |||
| case ENGINE_CALLBACK_QUIT: | |||
| return "ENGINE_CALLBACK_QUIT"; | |||
| case ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW: | |||
| return "ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW"; | |||
| } | |||
| carla_stderr("CarlaBackend::EngineCallbackOpcode2Str(%i) - invalid opcode", opcode); | |||