1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3 4# PatchBay Canvas engine using QGraphicsView/Scene 5# Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com> 6# 7# This program is free software; you can redistribute it and/or 8# modify it under the terms of the GNU General Public License as 9# published by the Free Software Foundation; either version 2 of 10# the License, or any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# For a full copy of the GNU General Public License see the doc/GPL.txt file. 18 19# ------------------------------------------------------------------------------------------------------------ 20# Imports (Global) 21 22from PyQt5.QtCore import QPointF, QRectF 23from PyQt5.QtWidgets import QGraphicsItem 24 25# ------------------------------------------------------------------------------------------------------------ 26# Imports (Theme) 27 28from .theme import getDefaultThemeName 29 30# ------------------------------------------------------------------------------------------------------------ 31 32# Maximum Id for a plugin, treated as invalid/zero if above this value 33MAX_PLUGIN_ID_ALLOWED = 0x7FF 34 35# Port Mode 36PORT_MODE_NULL = 0 37PORT_MODE_INPUT = 1 38PORT_MODE_OUTPUT = 2 39 40# Port Type 41PORT_TYPE_NULL = 0 42PORT_TYPE_AUDIO_JACK = 1 43PORT_TYPE_MIDI_JACK = 2 44PORT_TYPE_MIDI_ALSA = 3 45PORT_TYPE_PARAMETER = 4 46 47# Callback Action 48ACTION_GROUP_INFO = 0 # group_id, N, N 49ACTION_GROUP_RENAME = 1 # group_id, N, N 50ACTION_GROUP_SPLIT = 2 # group_id, N, N 51ACTION_GROUP_JOIN = 3 # group_id, N, N 52ACTION_GROUP_POSITION = 4 # group_id, N, N, "x1:y1:x2:y2" 53ACTION_PORT_INFO = 5 # group_id, port_id, N 54ACTION_PORT_RENAME = 6 # group_id, port_id, N 55ACTION_PORTS_CONNECT = 7 # N, N, "outG:outP:inG:inP" 56ACTION_PORTS_DISCONNECT = 8 # conn_id, N, N 57ACTION_PLUGIN_CLONE = 9 # plugin_id, N, N 58ACTION_PLUGIN_EDIT = 10 # plugin_id, N, N 59ACTION_PLUGIN_RENAME = 11 # plugin_id, N, N 60ACTION_PLUGIN_REPLACE = 12 # plugin_id, N, N 61ACTION_PLUGIN_REMOVE = 13 # plugin_id, N, N 62ACTION_PLUGIN_SHOW_UI = 14 # plugin_id, N, N 63ACTION_BG_RIGHT_CLICK = 15 # N, N, N 64ACTION_INLINE_DISPLAY = 16 # plugin_id, N, N 65 66# Icon 67ICON_APPLICATION = 0 68ICON_HARDWARE = 1 69ICON_DISTRHO = 2 70ICON_FILE = 3 71ICON_PLUGIN = 4 72ICON_LADISH_ROOM = 5 73 74# Split Option 75SPLIT_UNDEF = 0 76SPLIT_NO = 1 77SPLIT_YES = 2 78 79# Antialiasing Option 80ANTIALIASING_NONE = 0 81ANTIALIASING_SMALL = 1 82ANTIALIASING_FULL = 2 83 84# Eye-Candy Option 85EYECANDY_NONE = 0 86EYECANDY_SMALL = 1 87EYECANDY_FULL = 2 88 89# ------------------------------------------------------------------------------------------------------------ 90 91# object types 92CanvasBoxType = QGraphicsItem.UserType + 1 93CanvasIconType = QGraphicsItem.UserType + 2 94CanvasPortType = QGraphicsItem.UserType + 3 95CanvasLineType = QGraphicsItem.UserType + 4 96CanvasBezierLineType = QGraphicsItem.UserType + 5 97CanvasLineMovType = QGraphicsItem.UserType + 6 98CanvasBezierLineMovType = QGraphicsItem.UserType + 7 99CanvasRubberbandType = QGraphicsItem.UserType + 8 100 101# ------------------------------------------------------------------------------------------------------------ 102 103# Canvas options 104class options_t(object): 105 __slots__ = [ 106 'theme_name', 107 'auto_hide_groups', 108 'auto_select_items', 109 'use_bezier_lines', 110 'antialiasing', 111 'eyecandy', 112 'inline_displays' 113 ] 114 115# Canvas features 116class features_t(object): 117 __slots__ = [ 118 'group_info', 119 'group_rename', 120 'port_info', 121 'port_rename', 122 'handle_group_pos' 123 ] 124 125# Main Canvas object 126class Canvas(object): 127 def __init__(self): 128 self.qobject = None 129 self.settings = None 130 self.theme = None 131 self.initiated = False 132 133 self.group_list = [] 134 self.port_list = [] 135 self.connection_list = [] 136 self.animation_list = [] 137 self.group_plugin_map = {} 138 self.old_group_pos = {} 139 140 self.callback = self.callback 141 self.debug = False 142 self.scene = None 143 self.last_z_value = 0 144 self.last_connection_id = 0 145 self.initial_pos = QPointF(0, 0) 146 self.size_rect = QRectF() 147 148 def callback(self, action, value1, value2, value_str): 149 print("Canvas::callback({}, {}, {}, {})".format(action, value1, value2, value_str)) 150 151# ------------------------------------------------------------------------------------------------------------ 152 153# object lists 154class group_dict_t(object): 155 __slots__ = [ 156 'group_id', 157 'group_name', 158 'split', 159 'icon', 160 'plugin_id', 161 'plugin_ui', 162 'plugin_inline', 163 'widgets' 164 ] 165 166class port_dict_t(object): 167 __slots__ = [ 168 'group_id', 169 'port_id', 170 'port_name', 171 'port_mode', 172 'port_type', 173 'is_alternate', 174 'widget' 175 ] 176 177class connection_dict_t(object): 178 __slots__ = [ 179 'connection_id', 180 'group_in_id', 181 'port_in_id', 182 'group_out_id', 183 'port_out_id', 184 'widget' 185 ] 186 187class animation_dict_t(object): 188 __slots__ = [ 189 'animation', 190 'item' 191 ] 192 193# ------------------------------------------------------------------------------------------------------------ 194 195# Internal functions 196def bool2str(check): 197 return "True" if check else "False" 198 199def port_mode2str(port_mode): 200 if port_mode == PORT_MODE_NULL: 201 return "PORT_MODE_NULL" 202 elif port_mode == PORT_MODE_INPUT: 203 return "PORT_MODE_INPUT" 204 elif port_mode == PORT_MODE_OUTPUT: 205 return "PORT_MODE_OUTPUT" 206 else: 207 return "PORT_MODE_???" 208 209def port_type2str(port_type): 210 if port_type == PORT_TYPE_NULL: 211 return "PORT_TYPE_NULL" 212 elif port_type == PORT_TYPE_AUDIO_JACK: 213 return "PORT_TYPE_AUDIO_JACK" 214 elif port_type == PORT_TYPE_MIDI_JACK: 215 return "PORT_TYPE_MIDI_JACK" 216 elif port_type == PORT_TYPE_MIDI_ALSA: 217 return "PORT_TYPE_MIDI_ALSA" 218 elif port_type == PORT_TYPE_PARAMETER: 219 return "PORT_TYPE_MIDI_PARAMETER" 220 else: 221 return "PORT_TYPE_???" 222 223def icon2str(icon): 224 if icon == ICON_APPLICATION: 225 return "ICON_APPLICATION" 226 elif icon == ICON_HARDWARE: 227 return "ICON_HARDWARE" 228 elif icon == ICON_DISTRHO: 229 return "ICON_DISTRHO" 230 elif icon == ICON_FILE: 231 return "ICON_FILE" 232 elif icon == ICON_PLUGIN: 233 return "ICON_PLUGIN" 234 elif icon == ICON_LADISH_ROOM: 235 return "ICON_LADISH_ROOM" 236 else: 237 return "ICON_???" 238 239def split2str(split): 240 if split == SPLIT_UNDEF: 241 return "SPLIT_UNDEF" 242 elif split == SPLIT_NO: 243 return "SPLIT_NO" 244 elif split == SPLIT_YES: 245 return "SPLIT_YES" 246 else: 247 return "SPLIT_???" 248 249# ------------------------------------------------------------------------------------------------------------ 250 251# Global objects 252canvas = Canvas() 253 254options = options_t() 255options.theme_name = getDefaultThemeName() 256options.auto_hide_groups = False 257options.auto_select_items = False 258options.use_bezier_lines = True 259options.antialiasing = ANTIALIASING_SMALL 260options.eyecandy = EYECANDY_SMALL 261options.inline_displays = False 262 263features = features_t() 264features.group_info = False 265features.group_rename = False 266features.port_info = False 267features.port_rename = False 268features.handle_group_pos = False 269 270# PatchCanvas API 271def setOptions(new_options): 272 if canvas.initiated: return 273 options.theme_name = new_options.theme_name 274 options.auto_hide_groups = new_options.auto_hide_groups 275 options.auto_select_items = new_options.auto_select_items 276 options.use_bezier_lines = new_options.use_bezier_lines 277 options.antialiasing = new_options.antialiasing 278 options.eyecandy = new_options.eyecandy 279 options.inline_displays = new_options.inline_displays 280 281def setFeatures(new_features): 282 if canvas.initiated: return 283 features.group_info = new_features.group_info 284 features.group_rename = new_features.group_rename 285 features.port_info = new_features.port_info 286 features.port_rename = new_features.port_rename 287 features.handle_group_pos = new_features.handle_group_pos 288