| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,287 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import QPointF, QRectF | ||
| from PyQt5.QtWidgets import QGraphicsItem | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Theme) | ||
|
|
||
| from .theme import getDefaultThemeName | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| # Maximum Id for a plugin, treated as invalid/zero if above this value | ||
| MAX_PLUGIN_ID_ALLOWED = 0x7FF | ||
|
|
||
| # Port Mode | ||
| PORT_MODE_NULL = 0 | ||
| PORT_MODE_INPUT = 1 | ||
| PORT_MODE_OUTPUT = 2 | ||
|
|
||
| # Port Type | ||
| PORT_TYPE_NULL = 0 | ||
| PORT_TYPE_AUDIO_JACK = 1 | ||
| PORT_TYPE_MIDI_JACK = 2 | ||
| PORT_TYPE_MIDI_ALSA = 3 | ||
| PORT_TYPE_PARAMETER = 4 | ||
|
|
||
| # Callback Action | ||
| ACTION_GROUP_INFO = 0 # group_id, N, N | ||
| ACTION_GROUP_RENAME = 1 # group_id, N, N | ||
| ACTION_GROUP_SPLIT = 2 # group_id, N, N | ||
| ACTION_GROUP_JOIN = 3 # group_id, N, N | ||
| ACTION_GROUP_POSITION = 4 # group_id, N, N, "x1:y1:x2:y2" | ||
| ACTION_PORT_INFO = 5 # group_id, port_id, N | ||
| ACTION_PORT_RENAME = 6 # group_id, port_id, N | ||
| ACTION_PORTS_CONNECT = 7 # N, N, "outG:outP:inG:inP" | ||
| ACTION_PORTS_DISCONNECT = 8 # conn_id, N, N | ||
| ACTION_PLUGIN_CLONE = 9 # plugin_id, N, N | ||
| ACTION_PLUGIN_EDIT = 10 # plugin_id, N, N | ||
| ACTION_PLUGIN_RENAME = 11 # plugin_id, N, N | ||
| ACTION_PLUGIN_REPLACE = 12 # plugin_id, N, N | ||
| ACTION_PLUGIN_REMOVE = 13 # plugin_id, N, N | ||
| ACTION_PLUGIN_SHOW_UI = 14 # plugin_id, N, N | ||
| ACTION_BG_RIGHT_CLICK = 15 # N, N, N | ||
| ACTION_INLINE_DISPLAY = 16 # plugin_id, N, N | ||
|
|
||
| # Icon | ||
| ICON_APPLICATION = 0 | ||
| ICON_HARDWARE = 1 | ||
| ICON_DISTRHO = 2 | ||
| ICON_FILE = 3 | ||
| ICON_PLUGIN = 4 | ||
| ICON_LADISH_ROOM = 5 | ||
|
|
||
| # Split Option | ||
| SPLIT_UNDEF = 0 | ||
| SPLIT_NO = 1 | ||
| SPLIT_YES = 2 | ||
|
|
||
| # Antialiasing Option | ||
| ANTIALIASING_NONE = 0 | ||
| ANTIALIASING_SMALL = 1 | ||
| ANTIALIASING_FULL = 2 | ||
|
|
||
| # Eye-Candy Option | ||
| EYECANDY_NONE = 0 | ||
| EYECANDY_SMALL = 1 | ||
| EYECANDY_FULL = 2 | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| # object types | ||
| CanvasBoxType = QGraphicsItem.UserType + 1 | ||
| CanvasIconType = QGraphicsItem.UserType + 2 | ||
| CanvasPortType = QGraphicsItem.UserType + 3 | ||
| CanvasLineType = QGraphicsItem.UserType + 4 | ||
| CanvasBezierLineType = QGraphicsItem.UserType + 5 | ||
| CanvasLineMovType = QGraphicsItem.UserType + 6 | ||
| CanvasBezierLineMovType = QGraphicsItem.UserType + 7 | ||
| CanvasRubberbandType = QGraphicsItem.UserType + 8 | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| # Canvas options | ||
| class options_t(object): | ||
| __slots__ = [ | ||
| 'theme_name', | ||
| 'auto_hide_groups', | ||
| 'auto_select_items', | ||
| 'use_bezier_lines', | ||
| 'antialiasing', | ||
| 'eyecandy', | ||
| 'inline_displays' | ||
| ] | ||
|
|
||
| # Canvas features | ||
| class features_t(object): | ||
| __slots__ = [ | ||
| 'group_info', | ||
| 'group_rename', | ||
| 'port_info', | ||
| 'port_rename', | ||
| 'handle_group_pos' | ||
| ] | ||
|
|
||
| # Main Canvas object | ||
| class Canvas(object): | ||
| def __init__(self): | ||
| self.qobject = None | ||
| self.settings = None | ||
| self.theme = None | ||
| self.initiated = False | ||
|
|
||
| self.group_list = [] | ||
| self.port_list = [] | ||
| self.connection_list = [] | ||
| self.animation_list = [] | ||
| self.group_plugin_map = {} | ||
| self.old_group_pos = {} | ||
|
|
||
| self.callback = self.callback | ||
| self.debug = False | ||
| self.scene = None | ||
| self.last_z_value = 0 | ||
| self.last_connection_id = 0 | ||
| self.initial_pos = QPointF(0, 0) | ||
| self.size_rect = QRectF() | ||
|
|
||
| def callback(self, action, value1, value2, value_str): | ||
| print("Canvas::callback({}, {}, {}, {})".format(action, value1, value2, value_str)) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| # object lists | ||
| class group_dict_t(object): | ||
| __slots__ = [ | ||
| 'group_id', | ||
| 'group_name', | ||
| 'split', | ||
| 'icon', | ||
| 'plugin_id', | ||
| 'plugin_ui', | ||
| 'plugin_inline', | ||
| 'widgets' | ||
| ] | ||
|
|
||
| class port_dict_t(object): | ||
| __slots__ = [ | ||
| 'group_id', | ||
| 'port_id', | ||
| 'port_name', | ||
| 'port_mode', | ||
| 'port_type', | ||
| 'is_alternate', | ||
| 'widget' | ||
| ] | ||
|
|
||
| class connection_dict_t(object): | ||
| __slots__ = [ | ||
| 'connection_id', | ||
| 'group_in_id', | ||
| 'port_in_id', | ||
| 'group_out_id', | ||
| 'port_out_id', | ||
| 'widget' | ||
| ] | ||
|
|
||
| class animation_dict_t(object): | ||
| __slots__ = [ | ||
| 'animation', | ||
| 'item' | ||
| ] | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| # Internal functions | ||
| def bool2str(check): | ||
| return "True" if check else "False" | ||
|
|
||
| def port_mode2str(port_mode): | ||
| if port_mode == PORT_MODE_NULL: | ||
| return "PORT_MODE_NULL" | ||
| elif port_mode == PORT_MODE_INPUT: | ||
| return "PORT_MODE_INPUT" | ||
| elif port_mode == PORT_MODE_OUTPUT: | ||
| return "PORT_MODE_OUTPUT" | ||
| else: | ||
| return "PORT_MODE_???" | ||
|
|
||
| def port_type2str(port_type): | ||
| if port_type == PORT_TYPE_NULL: | ||
| return "PORT_TYPE_NULL" | ||
| elif port_type == PORT_TYPE_AUDIO_JACK: | ||
| return "PORT_TYPE_AUDIO_JACK" | ||
| elif port_type == PORT_TYPE_MIDI_JACK: | ||
| return "PORT_TYPE_MIDI_JACK" | ||
| elif port_type == PORT_TYPE_MIDI_ALSA: | ||
| return "PORT_TYPE_MIDI_ALSA" | ||
| elif port_type == PORT_TYPE_PARAMETER: | ||
| return "PORT_TYPE_MIDI_PARAMETER" | ||
| else: | ||
| return "PORT_TYPE_???" | ||
|
|
||
| def icon2str(icon): | ||
| if icon == ICON_APPLICATION: | ||
| return "ICON_APPLICATION" | ||
| elif icon == ICON_HARDWARE: | ||
| return "ICON_HARDWARE" | ||
| elif icon == ICON_DISTRHO: | ||
| return "ICON_DISTRHO" | ||
| elif icon == ICON_FILE: | ||
| return "ICON_FILE" | ||
| elif icon == ICON_PLUGIN: | ||
| return "ICON_PLUGIN" | ||
| elif icon == ICON_LADISH_ROOM: | ||
| return "ICON_LADISH_ROOM" | ||
| else: | ||
| return "ICON_???" | ||
|
|
||
| def split2str(split): | ||
| if split == SPLIT_UNDEF: | ||
| return "SPLIT_UNDEF" | ||
| elif split == SPLIT_NO: | ||
| return "SPLIT_NO" | ||
| elif split == SPLIT_YES: | ||
| return "SPLIT_YES" | ||
| else: | ||
| return "SPLIT_???" | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| # Global objects | ||
| canvas = Canvas() | ||
|
|
||
| options = options_t() | ||
| options.theme_name = getDefaultThemeName() | ||
| options.auto_hide_groups = False | ||
| options.auto_select_items = False | ||
| options.use_bezier_lines = True | ||
| options.antialiasing = ANTIALIASING_SMALL | ||
| options.eyecandy = EYECANDY_SMALL | ||
| options.inline_displays = False | ||
|
|
||
| features = features_t() | ||
| features.group_info = False | ||
| features.group_rename = False | ||
| features.port_info = False | ||
| features.port_rename = False | ||
| features.handle_group_pos = False | ||
|
|
||
| # PatchCanvas API | ||
| def setOptions(new_options): | ||
| if canvas.initiated: return | ||
| options.theme_name = new_options.theme_name | ||
| options.auto_hide_groups = new_options.auto_hide_groups | ||
| options.auto_select_items = new_options.auto_select_items | ||
| options.use_bezier_lines = new_options.use_bezier_lines | ||
| options.antialiasing = new_options.antialiasing | ||
| options.eyecandy = new_options.eyecandy | ||
| options.inline_displays = new_options.inline_displays | ||
|
|
||
| def setFeatures(new_features): | ||
| if canvas.initiated: return | ||
| features.group_info = new_features.group_info | ||
| features.group_rename = new_features.group_rename | ||
| features.port_info = new_features.port_info | ||
| features.port_rename = new_features.port_rename | ||
| features.handle_group_pos = new_features.handle_group_pos |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import Qt, QPointF | ||
| from PyQt5.QtGui import QColor, QLinearGradient, QPainter, QPainterPath, QPen | ||
| from PyQt5.QtWidgets import QGraphicsPathItem | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import ( | ||
| canvas, | ||
| options, | ||
| CanvasBezierLineType, | ||
| ACTION_PORTS_DISCONNECT, | ||
| EYECANDY_FULL, | ||
| PORT_MODE_OUTPUT, | ||
| PORT_TYPE_AUDIO_JACK, | ||
| PORT_TYPE_MIDI_ALSA, | ||
| PORT_TYPE_MIDI_JACK, | ||
| PORT_TYPE_PARAMETER, | ||
| ) | ||
|
|
||
| from .canvasportglow import CanvasPortGlow | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasBezierLine(QGraphicsPathItem): | ||
| def __init__(self, item1, item2, parent): | ||
| QGraphicsPathItem.__init__(self) | ||
| self.setParentItem(parent) | ||
|
|
||
| self.item1 = item1 | ||
| self.item2 = item2 | ||
|
|
||
| self.m_locked = False | ||
| self.m_lineSelected = False | ||
|
|
||
| self.setBrush(QColor(0, 0, 0, 0)) | ||
| self.setGraphicsEffect(None) | ||
| self.updateLinePos() | ||
|
|
||
| def isLocked(self): | ||
| return self.m_locked | ||
|
|
||
| def setLocked(self, yesno): | ||
| self.m_locked = yesno | ||
|
|
||
| def isLineSelected(self): | ||
| return self.m_lineSelected | ||
|
|
||
| def updateLineSelected(self): | ||
| if self.m_locked: | ||
| return | ||
|
|
||
| yesno = self.item1.isSelected() or self.item2.isSelected() | ||
| if yesno != self.m_lineSelected and options.eyecandy == EYECANDY_FULL: | ||
| if yesno: | ||
| self.setGraphicsEffect(CanvasPortGlow(self.item1.getPortType(), self.toGraphicsObject())) | ||
| else: | ||
| self.setGraphicsEffect(None) | ||
|
|
||
| self.m_lineSelected = yesno | ||
| self.updateLineGradient() | ||
|
|
||
| def triggerDisconnect(self): | ||
| for connection in canvas.connection_list: | ||
| if (connection.port_out_id == self.item1.getPortId() and connection.port_in_id == self.item2.getPortId()): | ||
| canvas.callback(ACTION_PORTS_DISCONNECT, connection.connection_id, 0, "") | ||
| break | ||
|
|
||
| def updateLinePos(self): | ||
| if self.item1.getPortMode() == PORT_MODE_OUTPUT: | ||
| rect1 = self.item1.sceneBoundingRect() | ||
| rect2 = self.item2.sceneBoundingRect() | ||
|
|
||
| item1_x = rect1.right() | ||
| item2_x = rect2.left() | ||
| item1_y = rect1.top() + float(canvas.theme.port_height)/2 | ||
| item2_y = rect2.top() + float(canvas.theme.port_height)/2 | ||
| item1_new_x = item1_x + abs(item1_x - item2_x) / 2 | ||
| item2_new_x = item2_x - abs(item1_x - item2_x) / 2 | ||
|
|
||
| path = QPainterPath(QPointF(item1_x, item1_y)) | ||
| path.cubicTo(item1_new_x, item1_y, item2_new_x, item2_y, item2_x, item2_y) | ||
| self.setPath(path) | ||
|
|
||
| self.m_lineSelected = False | ||
| self.updateLineGradient() | ||
|
|
||
| def type(self): | ||
| return CanvasBezierLineType | ||
|
|
||
| def updateLineGradient(self): | ||
| pos_top = self.boundingRect().top() | ||
| pos_bot = self.boundingRect().bottom() | ||
| if self.item2.scenePos().y() >= self.item1.scenePos().y(): | ||
| pos1 = 0 | ||
| pos2 = 1 | ||
| else: | ||
| pos1 = 1 | ||
| pos2 = 0 | ||
|
|
||
| port_type1 = self.item1.getPortType() | ||
| port_type2 = self.item2.getPortType() | ||
| port_gradient = QLinearGradient(0, pos_top, 0, pos_bot) | ||
|
|
||
| if port_type1 == PORT_TYPE_AUDIO_JACK: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack) | ||
| elif port_type1 == PORT_TYPE_MIDI_JACK: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack) | ||
| elif port_type1 == PORT_TYPE_MIDI_ALSA: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa) | ||
| elif port_type1 == PORT_TYPE_PARAMETER: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_parameter_sel if self.m_lineSelected else canvas.theme.line_parameter) | ||
|
|
||
| if port_type2 == PORT_TYPE_AUDIO_JACK: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack) | ||
| elif port_type2 == PORT_TYPE_MIDI_JACK: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack) | ||
| elif port_type2 == PORT_TYPE_MIDI_ALSA: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa) | ||
| elif port_type2 == PORT_TYPE_PARAMETER: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_parameter_sel if self.m_lineSelected else canvas.theme.line_parameter) | ||
|
|
||
| self.setPen(QPen(port_gradient, 2.00001, Qt.SolidLine, Qt.FlatCap)) | ||
|
|
||
| def paint(self, painter, option, widget): | ||
| painter.save() | ||
| painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing)) | ||
|
|
||
| pen = self.pen() | ||
| cosm_pen = QPen(pen) | ||
| cosm_pen.setCosmetic(True) | ||
| cosm_pen.setWidthF(1.00001) | ||
|
|
||
| QGraphicsPathItem.paint(self, painter, option, widget) | ||
|
|
||
| painter.setPen(cosm_pen) | ||
| painter.setBrush(Qt.NoBrush) | ||
| painter.setOpacity(0.2) | ||
| painter.drawPath(self.path()) | ||
|
|
||
| painter.restore() | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import qWarning, Qt, QPointF | ||
| from PyQt5.QtGui import QPainter, QPainterPath, QPen | ||
| from PyQt5.QtWidgets import QGraphicsPathItem | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import ( | ||
| canvas, | ||
| options, | ||
| port_mode2str, | ||
| port_type2str, | ||
| CanvasBezierLineMovType, | ||
| PORT_MODE_INPUT, | ||
| PORT_MODE_OUTPUT, | ||
| PORT_TYPE_AUDIO_JACK, | ||
| PORT_TYPE_MIDI_ALSA, | ||
| PORT_TYPE_MIDI_JACK, | ||
| PORT_TYPE_PARAMETER, | ||
| ) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasBezierLineMov(QGraphicsPathItem): | ||
| def __init__(self, port_mode, port_type, parent): | ||
| QGraphicsPathItem.__init__(self) | ||
| self.setParentItem(parent) | ||
|
|
||
| self.m_port_mode = port_mode | ||
| self.m_port_type = port_type | ||
|
|
||
| # Port position doesn't change while moving around line | ||
| self.p_itemX = self.scenePos().x() | ||
| self.p_itemY = self.scenePos().y() | ||
| self.p_width = parent.getPortWidth() | ||
|
|
||
| if port_type == PORT_TYPE_AUDIO_JACK: | ||
| pen = QPen(canvas.theme.line_audio_jack, 2) | ||
| elif port_type == PORT_TYPE_MIDI_JACK: | ||
| pen = QPen(canvas.theme.line_midi_jack, 2) | ||
| elif port_type == PORT_TYPE_MIDI_ALSA: | ||
| pen = QPen(canvas.theme.line_midi_alsa, 2) | ||
| elif port_type == PORT_TYPE_PARAMETER: | ||
| pen = QPen(canvas.theme.line_parameter, 2) | ||
| else: | ||
| qWarning("PatchCanvas::CanvasBezierLineMov({}, {}, {}) - invalid port type".format( | ||
| port_mode2str(port_mode), port_type2str(port_type), parent)) | ||
| pen = QPen(Qt.black) | ||
|
|
||
| pen.setCapStyle(Qt.FlatCap) | ||
| pen.setWidthF(pen.widthF() + 0.00001) | ||
| self.setPen(pen) | ||
|
|
||
| def updateLinePos(self, scenePos): | ||
| if self.m_port_mode == PORT_MODE_INPUT: | ||
| old_x = 0 | ||
| old_y = float(canvas.theme.port_height)/2 | ||
| mid_x = abs(scenePos.x() - self.p_itemX) / 2 | ||
| new_x = old_x - mid_x | ||
| elif self.m_port_mode == PORT_MODE_OUTPUT: | ||
| old_x = self.p_width + 12 | ||
| old_y = float(canvas.theme.port_height)/2 | ||
| mid_x = abs(scenePos.x() - (self.p_itemX + old_x)) / 2 | ||
| new_x = old_x + mid_x | ||
| else: | ||
| return | ||
|
|
||
| final_x = scenePos.x() - self.p_itemX | ||
| final_y = scenePos.y() - self.p_itemY | ||
|
|
||
| path = QPainterPath(QPointF(old_x, old_y)) | ||
| path.cubicTo(new_x, old_y, new_x, final_y, final_x, final_y) | ||
| self.setPath(path) | ||
|
|
||
| def type(self): | ||
| return CanvasBezierLineMovType | ||
|
|
||
| def paint(self, painter, option, widget): | ||
| painter.save() | ||
| painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing)) | ||
| QGraphicsPathItem.paint(self, painter, option, widget) | ||
| painter.restore() | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtGui import QColor | ||
| from PyQt5.QtWidgets import QGraphicsDropShadowEffect | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import canvas | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasBoxShadow(QGraphicsDropShadowEffect): | ||
| def __init__(self, parent): | ||
| QGraphicsDropShadowEffect.__init__(self, parent) | ||
|
|
||
| self.m_fakeParent = None | ||
|
|
||
| self.setBlurRadius(20) | ||
| self.setColor(canvas.theme.box_shadow) | ||
| self.setOffset(0, 0) | ||
|
|
||
| def setFakeParent(self, fakeParent): | ||
| self.m_fakeParent = fakeParent | ||
|
|
||
| def setOpacity(self, opacity): | ||
| color = QColor(canvas.theme.box_shadow) | ||
| color.setAlphaF(opacity) | ||
| self.setColor(color) | ||
|
|
||
| def draw(self, painter): | ||
| if self.m_fakeParent: | ||
| self.m_fakeParent.repaintLines() | ||
| QGraphicsDropShadowEffect.draw(self, painter) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import QAbstractAnimation | ||
| from PyQt5.QtWidgets import QGraphicsObject | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import canvas, CanvasBoxType | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasFadeAnimation(QAbstractAnimation): | ||
| def __init__(self, item, show): | ||
| QAbstractAnimation.__init__(self) | ||
|
|
||
| self.m_show = show | ||
| self.m_duration = 0 | ||
| self.m_item = item | ||
| self.m_item_is_object = isinstance(item, QGraphicsObject) | ||
|
|
||
| def item(self): | ||
| return self.m_item | ||
|
|
||
| def forceStop(self): | ||
| self.blockSignals(True) | ||
| self.stop() | ||
| self.blockSignals(False) | ||
|
|
||
| def setDuration(self, time): | ||
| if self.m_item.opacity() == 0 and not self.m_show: | ||
| self.m_duration = 0 | ||
| else: | ||
| if self.m_item_is_object: | ||
| self.m_item.blockSignals(True) | ||
| self.m_item.show() | ||
| self.m_item.blockSignals(False) | ||
| else: | ||
| self.m_item.show() | ||
| self.m_duration = time | ||
|
|
||
| def duration(self): | ||
| return self.m_duration | ||
|
|
||
| def updateCurrentTime(self, time): | ||
| if self.m_duration == 0: | ||
| return | ||
|
|
||
| if self.m_show: | ||
| value = float(time) / self.m_duration | ||
| else: | ||
| value = 1.0 - (float(time) / self.m_duration) | ||
|
|
||
| try: | ||
| self.m_item.setOpacity(value) | ||
| except RuntimeError: | ||
| print("CanvasFadeAnimation::updateCurrentTime() - failed to animate canvas item, already destroyed?") | ||
| self.forceStop() | ||
| canvas.animation_list.remove(self) | ||
| return | ||
|
|
||
| if self.m_item.type() == CanvasBoxType: | ||
| self.m_item.setShadowOpacity(value) | ||
|
|
||
| def updateDirection(self, direction): | ||
| pass | ||
|
|
||
| def updateState(self, oldState, newState): | ||
| pass | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import qCritical, QRectF | ||
| from PyQt5.QtGui import QPainter | ||
| from PyQt5.QtSvg import QGraphicsSvgItem, QSvgRenderer | ||
| from PyQt5.QtWidgets import QGraphicsColorizeEffect | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import ( | ||
| canvas, | ||
| icon2str, | ||
| CanvasIconType, | ||
| ICON_APPLICATION, | ||
| ICON_HARDWARE, | ||
| ICON_DISTRHO, | ||
| ICON_FILE, | ||
| ICON_PLUGIN, | ||
| ICON_LADISH_ROOM, | ||
| ) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasIcon(QGraphicsSvgItem): | ||
| def __init__(self, icon, name, parent): | ||
| QGraphicsSvgItem.__init__(self) | ||
| self.setParentItem(parent) | ||
|
|
||
| self.m_renderer = None | ||
| self.p_size = QRectF(0, 0, 0, 0) | ||
|
|
||
| self.m_colorFX = QGraphicsColorizeEffect(self) | ||
| self.m_colorFX.setColor(canvas.theme.box_text.color()) | ||
|
|
||
| self.setGraphicsEffect(self.m_colorFX) | ||
| self.setIcon(icon, name) | ||
|
|
||
| def setIcon(self, icon, name): | ||
| name = name.lower() | ||
| icon_path = "" | ||
|
|
||
| if icon == ICON_APPLICATION: | ||
| self.p_size = QRectF(3, 2, 19, 18) | ||
|
|
||
| if "audacious" in name: | ||
| icon_path = ":/scalable/pb_audacious.svg" | ||
| self.p_size = QRectF(5, 4, 16, 16) | ||
| elif "clementine" in name: | ||
| icon_path = ":/scalable/pb_clementine.svg" | ||
| self.p_size = QRectF(5, 4, 16, 16) | ||
| elif "distrho" in name: | ||
| icon_path = ":/scalable/pb_distrho.svg" | ||
| self.p_size = QRectF(5, 4, 16, 16) | ||
| elif "jamin" in name: | ||
| icon_path = ":/scalable/pb_jamin.svg" | ||
| self.p_size = QRectF(5, 3, 16, 16) | ||
| elif "mplayer" in name: | ||
| icon_path = ":/scalable/pb_mplayer.svg" | ||
| self.p_size = QRectF(5, 4, 16, 16) | ||
| elif "vlc" in name: | ||
| icon_path = ":/scalable/pb_vlc.svg" | ||
| self.p_size = QRectF(5, 3, 16, 16) | ||
|
|
||
| else: | ||
| icon_path = ":/scalable/pb_generic.svg" | ||
| self.p_size = QRectF(4, 3, 16, 16) | ||
|
|
||
| elif icon == ICON_HARDWARE: | ||
| icon_path = ":/scalable/pb_hardware.svg" | ||
| self.p_size = QRectF(5, 2, 16, 16) | ||
|
|
||
| elif icon == ICON_DISTRHO: | ||
| icon_path = ":/scalable/pb_distrho.svg" | ||
| self.p_size = QRectF(5, 4, 16, 16) | ||
|
|
||
| elif icon == ICON_FILE: | ||
| icon_path = ":/scalable/pb_file.svg" | ||
| self.p_size = QRectF(5, 4, 16, 16) | ||
|
|
||
| elif icon == ICON_PLUGIN: | ||
| icon_path = ":/scalable/pb_plugin.svg" | ||
| self.p_size = QRectF(5, 4, 16, 16) | ||
|
|
||
| elif icon == ICON_LADISH_ROOM: | ||
| # TODO - make a unique ladish-room icon | ||
| icon_path = ":/scalable/pb_hardware.svg" | ||
| self.p_size = QRectF(5, 2, 16, 16) | ||
|
|
||
| else: | ||
| self.p_size = QRectF(0, 0, 0, 0) | ||
| qCritical("PatchCanvas::CanvasIcon.setIcon(%s, %s) - unsupported icon requested" % ( | ||
| icon2str(icon), name.encode())) | ||
| return | ||
|
|
||
| self.m_renderer = QSvgRenderer(icon_path, canvas.scene) | ||
| self.setSharedRenderer(self.m_renderer) | ||
| self.update() | ||
|
|
||
| def type(self): | ||
| return CanvasIconType | ||
|
|
||
| def boundingRect(self): | ||
| return self.p_size | ||
|
|
||
| def paint(self, painter, option, widget): | ||
| if not self.m_renderer: | ||
| QGraphicsSvgItem.paint(self, painter, option, widget) | ||
| return | ||
|
|
||
| painter.save() | ||
| painter.setRenderHint(QPainter.Antialiasing, False) | ||
| painter.setRenderHint(QPainter.TextAntialiasing, False) | ||
| self.m_renderer.render(painter, self.p_size) | ||
| painter.restore() | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import Qt, QLineF | ||
| from PyQt5.QtGui import QLinearGradient, QPainter, QPen | ||
| from PyQt5.QtWidgets import QGraphicsLineItem | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import ( | ||
| canvas, | ||
| options, | ||
| CanvasLineType, | ||
| ACTION_PORTS_DISCONNECT, | ||
| EYECANDY_FULL, | ||
| PORT_MODE_OUTPUT, | ||
| PORT_TYPE_AUDIO_JACK, | ||
| PORT_TYPE_MIDI_ALSA, | ||
| PORT_TYPE_MIDI_JACK, | ||
| PORT_TYPE_PARAMETER, | ||
| ) | ||
|
|
||
| from .canvasportglow import CanvasPortGlow | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasLine(QGraphicsLineItem): | ||
| def __init__(self, item1, item2, parent): | ||
| QGraphicsLineItem.__init__(self) | ||
| self.setParentItem(parent) | ||
|
|
||
| self.item1 = item1 | ||
| self.item2 = item2 | ||
|
|
||
| self.m_locked = False | ||
| self.m_lineSelected = False | ||
|
|
||
| self.setGraphicsEffect(None) | ||
| self.updateLinePos() | ||
|
|
||
| def isLocked(self): | ||
| return self.m_locked | ||
|
|
||
| def setLocked(self, yesno): | ||
| self.m_locked = yesno | ||
|
|
||
| def isLineSelected(self): | ||
| return self.m_lineSelected | ||
|
|
||
| def updateLineSelected(self): | ||
| if self.m_locked: | ||
| return | ||
|
|
||
| yesno = self.item1.isSelected() or self.item2.isSelected() | ||
| if yesno != self.m_lineSelected and options.eyecandy == EYECANDY_FULL: | ||
| if yesno: | ||
| self.setGraphicsEffect(CanvasPortGlow(self.item1.getPortType(), self.toGraphicsObject())) | ||
| else: | ||
| self.setGraphicsEffect(None) | ||
|
|
||
| self.m_lineSelected = yesno | ||
| self.updateLineGradient() | ||
|
|
||
| def triggerDisconnect(self): | ||
| for connection in canvas.connection_list: | ||
| if (connection.port_out_id == self.item1.getPortId() and connection.port_in_id == self.item2.getPortId()): | ||
| canvas.callback(ACTION_PORTS_DISCONNECT, connection.connection_id, 0, "") | ||
| break | ||
|
|
||
| def updateLinePos(self): | ||
| if self.item1.getPortMode() == PORT_MODE_OUTPUT: | ||
| rect1 = self.item1.sceneBoundingRect() | ||
| rect2 = self.item2.sceneBoundingRect() | ||
| line = QLineF(rect1.right(), | ||
| rect1.top() + float(canvas.theme.port_height)/2, | ||
| rect2.left(), | ||
| rect2.top() + float(canvas.theme.port_height)/2) | ||
| self.setLine(line) | ||
|
|
||
| self.m_lineSelected = False | ||
| self.updateLineGradient() | ||
|
|
||
| def type(self): | ||
| return CanvasLineType | ||
|
|
||
| def updateLineGradient(self): | ||
| pos_top = self.boundingRect().top() | ||
| pos_bot = self.boundingRect().bottom() | ||
| if self.item2.scenePos().y() >= self.item1.scenePos().y(): | ||
| pos1 = 0 | ||
| pos2 = 1 | ||
| else: | ||
| pos1 = 1 | ||
| pos2 = 0 | ||
|
|
||
| port_type1 = self.item1.getPortType() | ||
| port_type2 = self.item2.getPortType() | ||
| port_gradient = QLinearGradient(0, pos_top, 0, pos_bot) | ||
|
|
||
| if port_type1 == PORT_TYPE_AUDIO_JACK: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack) | ||
| elif port_type1 == PORT_TYPE_MIDI_JACK: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack) | ||
| elif port_type1 == PORT_TYPE_MIDI_ALSA: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa) | ||
| elif port_type1 == PORT_TYPE_PARAMETER: | ||
| port_gradient.setColorAt(pos1, canvas.theme.line_parameter_sel if self.m_lineSelected else canvas.theme.line_parameter) | ||
|
|
||
| if port_type2 == PORT_TYPE_AUDIO_JACK: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack) | ||
| elif port_type2 == PORT_TYPE_MIDI_JACK: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack) | ||
| elif port_type2 == PORT_TYPE_MIDI_ALSA: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa) | ||
| elif port_type2 == PORT_TYPE_PARAMETER: | ||
| port_gradient.setColorAt(pos2, canvas.theme.line_parameter_sel if self.m_lineSelected else canvas.theme.line_parameter) | ||
|
|
||
| self.setPen(QPen(port_gradient, 2.00001, Qt.SolidLine, Qt.RoundCap)) | ||
|
|
||
| def paint(self, painter, option, widget): | ||
| painter.save() | ||
| painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing)) | ||
|
|
||
| pen = self.pen() | ||
| cosm_pen = QPen(pen) | ||
| cosm_pen.setCosmetic(True) | ||
| cosm_pen.setWidthF(1.00001) | ||
|
|
||
| QGraphicsLineItem.paint(self, painter, option, widget) | ||
|
|
||
| painter.setPen(cosm_pen) | ||
| painter.setBrush(Qt.NoBrush) | ||
| painter.setOpacity(0.2) | ||
| painter.drawLine(self.line()) | ||
|
|
||
| painter.restore() | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import qWarning, Qt, QLineF | ||
| from PyQt5.QtGui import QPainter, QPen | ||
| from PyQt5.QtWidgets import QGraphicsLineItem | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import ( | ||
| canvas, | ||
| options, | ||
| port_mode2str, | ||
| port_type2str, | ||
| CanvasLineMovType, | ||
| PORT_MODE_INPUT, | ||
| PORT_MODE_OUTPUT, | ||
| PORT_TYPE_AUDIO_JACK, | ||
| PORT_TYPE_MIDI_ALSA, | ||
| PORT_TYPE_MIDI_JACK, | ||
| PORT_TYPE_PARAMETER, | ||
| ) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasLineMov(QGraphicsLineItem): | ||
| def __init__(self, port_mode, port_type, parent): | ||
| QGraphicsLineItem.__init__(self) | ||
| self.setParentItem(parent) | ||
|
|
||
| self.m_port_mode = port_mode | ||
| self.m_port_type = port_type | ||
|
|
||
| # Port position doesn't change while moving around line | ||
| self.p_lineX = self.scenePos().x() | ||
| self.p_lineY = self.scenePos().y() | ||
| self.p_width = parent.getPortWidth() | ||
|
|
||
| if port_type == PORT_TYPE_AUDIO_JACK: | ||
| pen = QPen(canvas.theme.line_audio_jack, 2) | ||
| elif port_type == PORT_TYPE_MIDI_JACK: | ||
| pen = QPen(canvas.theme.line_midi_jack, 2) | ||
| elif port_type == PORT_TYPE_MIDI_ALSA: | ||
| pen = QPen(canvas.theme.line_midi_alsa, 2) | ||
| elif port_type == PORT_TYPE_PARAMETER: | ||
| pen = QPen(canvas.theme.line_parameter, 2) | ||
| else: | ||
| qWarning("PatchCanvas::CanvasLineMov({}, {}, {}) - invalid port type".format( | ||
| port_mode2str(port_mode), port_type2str(port_type), parent)) | ||
| pen = QPen(Qt.black) | ||
|
|
||
| pen.setCapStyle(Qt.RoundCap) | ||
| pen.setWidthF(pen.widthF() + 0.00001) | ||
| self.setPen(pen) | ||
|
|
||
| def updateLinePos(self, scenePos): | ||
| item_pos = [0, 0] | ||
|
|
||
| if self.m_port_mode == PORT_MODE_INPUT: | ||
| item_pos[0] = 0 | ||
| item_pos[1] = float(canvas.theme.port_height)/2 | ||
| elif self.m_port_mode == PORT_MODE_OUTPUT: | ||
| item_pos[0] = self.p_width + 12 | ||
| item_pos[1] = float(canvas.theme.port_height)/2 | ||
| else: | ||
| return | ||
|
|
||
| line = QLineF(item_pos[0], item_pos[1], scenePos.x() - self.p_lineX, scenePos.y() - self.p_lineY) | ||
| self.setLine(line) | ||
|
|
||
| def type(self): | ||
| return CanvasLineMovType | ||
|
|
||
| def paint(self, painter, option, widget): | ||
| painter.save() | ||
| painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing)) | ||
| QGraphicsLineItem.paint(self, painter, option, widget) | ||
| painter.restore() | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtWidgets import QGraphicsDropShadowEffect | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import ( | ||
| canvas, | ||
| PORT_TYPE_AUDIO_JACK, | ||
| PORT_TYPE_MIDI_ALSA, | ||
| PORT_TYPE_MIDI_JACK, | ||
| PORT_TYPE_PARAMETER, | ||
| ) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| class CanvasPortGlow(QGraphicsDropShadowEffect): | ||
| def __init__(self, port_type, parent): | ||
| QGraphicsDropShadowEffect.__init__(self, parent) | ||
|
|
||
| self.setBlurRadius(12) | ||
| self.setOffset(0, 0) | ||
|
|
||
| if port_type == PORT_TYPE_AUDIO_JACK: | ||
| self.setColor(canvas.theme.line_audio_jack_glow) | ||
| elif port_type == PORT_TYPE_MIDI_JACK: | ||
| self.setColor(canvas.theme.line_midi_jack_glow) | ||
| elif port_type == PORT_TYPE_MIDI_ALSA: | ||
| self.setColor(canvas.theme.line_midi_alsa_glow) | ||
| elif port_type == PORT_TYPE_PARAMETER: | ||
| self.setColor(canvas.theme.line_parameter_glow) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # PatchBay Canvas engine using QGraphicsView/Scene | ||
| # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> | ||
| # | ||
| # This program is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU General Public License as | ||
| # published by the Free Software Foundation; either version 2 of | ||
| # the License, or any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Global) | ||
|
|
||
| from PyQt5.QtCore import qCritical, QPointF, QTimer | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
| # Imports (Custom) | ||
|
|
||
| from . import bool2str, canvas, CanvasBoxType | ||
| from .canvasfadeanimation import CanvasFadeAnimation | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ | ||
|
|
||
| def CanvasGetNewGroupPos(horizontal): | ||
| if canvas.debug: | ||
| print("PatchCanvas::CanvasGetNewGroupPos(%s)" % bool2str(horizontal)) | ||
|
|
||
| new_pos = QPointF(canvas.initial_pos) | ||
| items = canvas.scene.items() | ||
|
|
||
| #break_loop = False | ||
| while True: | ||
| break_for = False | ||
| for i, item in enumerate(items): | ||
| if item and item.type() == CanvasBoxType: | ||
| if item.sceneBoundingRect().adjusted(-5, -5, 5, 5).contains(new_pos): | ||
| itemRect = item.boundingRect() | ||
| if horizontal: | ||
| new_pos += QPointF(itemRect.width() + 50, 0) | ||
| else: | ||
| itemHeight = itemRect.height() | ||
| if itemHeight < 30: | ||
| new_pos += QPointF(0, itemHeight + 50) | ||
| else: | ||
| new_pos.setY(item.scenePos().y() + itemHeight + 20) | ||
| break_for = True | ||
| break | ||
| else: | ||
| if not break_for: | ||
| break | ||
| #break_loop = True | ||
|
|
||
| return new_pos | ||
|
|
||
| def CanvasGetFullPortName(group_id, port_id): | ||
| if canvas.debug: | ||
| print("PatchCanvas::CanvasGetFullPortName(%i, %i)" % (group_id, port_id)) | ||
|
|
||
| for port in canvas.port_list: | ||
| if port.group_id == group_id and port.port_id == port_id: | ||
| group_id = port.group_id | ||
| for group in canvas.group_list: | ||
| if group.group_id == group_id: | ||
| return group.group_name + ":" + port.port_name | ||
| break | ||
|
|
||
| qCritical("PatchCanvas::CanvasGetFullPortName(%i, %i) - unable to find port" % (group_id, port_id)) | ||
| return "" | ||
|
|
||
| def CanvasGetPortConnectionList(group_id, port_id): | ||
| if canvas.debug: | ||
| print("PatchCanvas::CanvasGetPortConnectionList(%i, %i)" % (group_id, port_id)) | ||
|
|
||
| conn_list = [] | ||
|
|
||
| for connection in canvas.connection_list: | ||
| if connection.group_out_id == group_id and connection.port_out_id == port_id: | ||
| conn_list.append((connection.connection_id, connection.group_in_id, connection.port_in_id)) | ||
| elif connection.group_in_id == group_id and connection.port_in_id == port_id: | ||
| conn_list.append((connection.connection_id, connection.group_out_id, connection.port_out_id)) | ||
|
|
||
| return conn_list | ||
|
|
||
| def CanvasCallback(action, value1, value2, value_str): | ||
| if canvas.debug: | ||
| print("PatchCanvas::CanvasCallback(%i, %i, %i, %s)" % (action, value1, value2, value_str.encode())) | ||
|
|
||
| canvas.callback(action, value1, value2, value_str) | ||
|
|
||
| def CanvasItemFX(item, show, destroy): | ||
| if canvas.debug: | ||
| print("PatchCanvas::CanvasItemFX(%s, %s, %s)" % (item, bool2str(show), bool2str(destroy))) | ||
|
|
||
| # Check if the item already has an animation | ||
| for animation in canvas.animation_list: | ||
| if animation.item() == item: | ||
| animation.forceStop() | ||
| canvas.animation_list.remove(animation) | ||
| del animation | ||
| break | ||
|
|
||
| animation = CanvasFadeAnimation(item, show) | ||
| animation.setDuration(750 if show else 500) | ||
|
|
||
| if show: | ||
| animation.finished.connect(canvas.qobject.AnimationFinishedShow) | ||
| else: | ||
| if destroy: | ||
| animation.finished.connect(canvas.qobject.AnimationFinishedDestroy) | ||
| else: | ||
| animation.finished.connect(canvas.qobject.AnimationFinishedHide) | ||
|
|
||
| canvas.animation_list.append(animation) | ||
|
|
||
| animation.start() | ||
|
|
||
| def CanvasRemoveItemFX(item): | ||
| if canvas.debug: | ||
| print("PatchCanvas::CanvasRemoveItemFX(%s)" % item) | ||
|
|
||
| if item.type() == CanvasBoxType: | ||
| item.removeIconFromScene() | ||
|
|
||
| canvas.scene.removeItem(item) | ||
| del item | ||
|
|
||
| QTimer.singleShot(0, canvas.scene.update) | ||
|
|
||
| # ------------------------------------------------------------------------------------------------------------ |