Cleanup
[carla.git] / source / frontend / patchcanvas / patchcanvas.py
blob695b1d5e8576709333ac71062d03f1709230bbb4
1 #!/usr/bin/env python3
2 # SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ------------------------------------------------------------------------------------------------------------
6 # Imports (Global)
8 from qt_compat import qt_config
10 if qt_config == 5:
11 from PyQt5.QtCore import pyqtSlot, qCritical, qFatal, qWarning, QObject
12 from PyQt5.QtCore import QPointF, QRectF, QTimer
13 from PyQt5.QtWidgets import QGraphicsObject
14 elif qt_config == 6:
15 from PyQt6.QtCore import pyqtSlot, qCritical, qFatal, qWarning, QObject
16 from PyQt6.QtCore import QPointF, QRectF, QTimer
17 from PyQt6.QtWidgets import QGraphicsObject
19 # ------------------------------------------------------------------------------------------------------------
20 # Imports (Custom)
22 from . import (
23 canvas,
24 features,
25 options,
26 group_dict_t,
27 port_dict_t,
28 connection_dict_t,
29 bool2str,
30 icon2str,
31 split2str,
32 port_mode2str,
33 port_type2str,
34 CanvasIconType,
35 CanvasRubberbandType,
36 ACTION_PORTS_DISCONNECT,
37 EYECANDY_FULL,
38 ICON_APPLICATION,
39 ICON_HARDWARE,
40 ICON_LADISH_ROOM,
41 PORT_MODE_INPUT,
42 PORT_MODE_OUTPUT,
43 SPLIT_YES,
44 SPLIT_NO,
45 SPLIT_UNDEF,
46 MAX_PLUGIN_ID_ALLOWED,
49 from .canvasbox import CanvasBox
50 from .canvasbezierline import CanvasBezierLine
51 from .canvasline import CanvasLine
52 from .theme import Theme, getDefaultTheme, getThemeName
53 from .utils import CanvasCallback, CanvasGetNewGroupPos, CanvasItemFX, CanvasRemoveItemFX
55 # FIXME
56 from . import *
57 from .scene import PatchScene
59 from utils import QSafeSettings
61 # ------------------------------------------------------------------------------------------------------------
63 class CanvasObject(QObject):
64 def __init__(self, parent=None):
65 QObject.__init__(self, parent)
67 @pyqtSlot()
68 def AnimationFinishedShow(self):
69 animation = self.sender()
70 if animation:
71 animation.forceStop()
72 canvas.animation_list.remove(animation)
74 @pyqtSlot()
75 def AnimationFinishedHide(self):
76 animation = self.sender()
77 if animation:
78 animation.forceStop()
79 canvas.animation_list.remove(animation)
80 item = animation.item()
81 if item:
82 if isinstance(item, QGraphicsObject):
83 item.blockSignals(True)
84 item.hide()
85 item.blockSignals(False)
86 else:
87 item.hide()
89 @pyqtSlot()
90 def AnimationFinishedDestroy(self):
91 animation = self.sender()
92 if animation:
93 animation.forceStop()
94 canvas.animation_list.remove(animation)
95 item = animation.item()
96 if item:
97 CanvasRemoveItemFX(item)
99 @pyqtSlot()
100 def PortContextMenuConnect(self):
101 try:
102 sources, targets = self.sender().data()
103 except:
104 return
106 for port_type in (PORT_TYPE_AUDIO_JACK, PORT_TYPE_MIDI_JACK, PORT_TYPE_MIDI_ALSA, PORT_TYPE_PARAMETER):
107 source_ports = sources[port_type]
108 target_ports = targets[port_type]
110 source_ports_len = len(source_ports)
111 target_ports_len = len(target_ports)
113 if source_ports_len == 0 or target_ports_len == 0:
114 continue
116 for i in range(min(source_ports_len, target_ports_len)):
117 data = "%i:%i:%i:%i" % (source_ports[i][0],
118 source_ports[i][1],
119 target_ports[i][0],
120 target_ports[i][1])
121 CanvasCallback(ACTION_PORTS_CONNECT, 0, 0, data)
123 if source_ports_len == 1 and target_ports_len > 1:
124 for i in range(1, target_ports_len):
125 data = "%i:%i:%i:%i" % (source_ports[0][0],
126 source_ports[0][1],
127 target_ports[i][0],
128 target_ports[i][1])
129 CanvasCallback(ACTION_PORTS_CONNECT, 0, 0, data)
131 @pyqtSlot()
132 def PortContextMenuDisconnect(self):
133 try:
134 connectionId = int(self.sender().data())
135 except:
136 return
138 CanvasCallback(ACTION_PORTS_DISCONNECT, connectionId, 0, "")
140 @pyqtSlot(int, bool, int, int)
141 def boxPositionChanged(self, groupId, split, x, y):
142 x2 = y2 = 0
144 if split:
145 for group in canvas.group_list:
146 if group.group_id == groupId:
147 if group.split:
148 pos = group.widgets[1].pos()
149 x2 = pos.x()
150 y2 = pos.y()
151 break
153 valueStr = "%i:%i:%i:%i" % (x, y, x2, y2)
154 CanvasCallback(ACTION_GROUP_POSITION, groupId, 0, valueStr)
156 @pyqtSlot(int, bool, int, int)
157 def sboxPositionChanged(self, groupId, split, x2, y2):
158 x = y = 0
160 for group in canvas.group_list:
161 if group.group_id == groupId:
162 pos = group.widgets[0].pos()
163 x = pos.x()
164 y = pos.y()
165 break
167 valueStr = "%i:%i:%i:%i" % (x, y, x2, y2)
168 CanvasCallback(ACTION_GROUP_POSITION, groupId, 0, valueStr)
170 # ------------------------------------------------------------------------------------------------------------
172 def getStoredCanvasPosition(key, fallback_pos):
173 try:
174 return canvas.settings.value("CanvasPositions/" + key, fallback_pos, type=QPointF)
175 except:
176 return fallback_pos
178 def getStoredCanvasSplit(group_name, fallback_split_mode):
179 try:
180 return canvas.settings.value("CanvasPositions/%s_SPLIT" % group_name, fallback_split_mode, type=int)
181 except:
182 return fallback_split_mode
184 # ------------------------------------------------------------------------------------------------------------
186 def init(appName, scene, callback, debug=False):
187 if debug:
188 print("PatchCanvas::init(\"%s\", %s, %s, %s)" % (appName, scene, callback, bool2str(debug)))
190 if canvas.initiated:
191 qCritical("PatchCanvas::init() - already initiated")
192 return
194 if not callback:
195 qFatal("PatchCanvas::init() - fatal error: callback not set")
196 return
198 canvas.callback = callback
199 canvas.debug = debug
200 canvas.scene = scene
202 canvas.last_z_value = 0
203 canvas.last_connection_id = 0
204 canvas.initial_pos = QPointF(0, 0)
205 canvas.size_rect = QRectF()
207 if not canvas.qobject:
208 canvas.qobject = CanvasObject()
209 if not canvas.settings:
210 canvas.settings = QSafeSettings("falkTX", appName)
212 if canvas.theme:
213 del canvas.theme
214 canvas.theme = None
216 for i in range(Theme.THEME_MAX):
217 this_theme_name = getThemeName(i)
218 if this_theme_name == options.theme_name:
219 canvas.theme = Theme(i)
220 break
222 if not canvas.theme:
223 canvas.theme = Theme(getDefaultTheme())
225 canvas.scene.updateTheme()
227 canvas.initiated = True
229 def clear():
230 if canvas.debug:
231 print("PatchCanvas::clear()")
233 group_pos = {}
234 group_list_ids = []
235 port_list_ids = []
236 connection_list_ids = []
238 for group in canvas.group_list:
239 group_pos[group.group_name] = (
240 group.split,
241 group.widgets[0].pos(),
242 group.widgets[1].pos() if group.split else None,
244 group_list_ids.append(group.group_id)
246 for port in canvas.port_list:
247 port_list_ids.append((port.group_id, port.port_id))
249 for connection in canvas.connection_list:
250 connection_list_ids.append(connection.connection_id)
252 for idx in connection_list_ids:
253 disconnectPorts(idx)
255 for group_id, port_id in port_list_ids:
256 removePort(group_id, port_id)
258 for idx in group_list_ids:
259 removeGroup(idx)
261 canvas.last_z_value = 0
262 canvas.last_connection_id = 0
264 canvas.group_list = []
265 canvas.port_list = []
266 canvas.connection_list = []
267 canvas.group_plugin_map = {}
268 canvas.old_group_pos = group_pos
270 canvas.scene.clearSelection()
272 animatedItems = []
273 for animation in canvas.animation_list:
274 animatedItems.append(animation.item())
276 for item in canvas.scene.items():
277 if item.type() in (CanvasIconType, CanvasRubberbandType) or item in animatedItems:
278 continue
279 canvas.scene.removeItem(item)
280 del item
282 canvas.initiated = False
284 QTimer.singleShot(0, canvas.scene.update)
286 # ------------------------------------------------------------------------------------------------------------
288 def setInitialPos(x, y):
289 if canvas.debug:
290 print("PatchCanvas::setInitialPos(%i, %i)" % (x, y))
292 canvas.initial_pos.setX(x)
293 canvas.initial_pos.setY(y)
295 def setCanvasSize(x, y, width, height):
296 if canvas.debug:
297 print("PatchCanvas::setCanvasSize(%i, %i, %i, %i)" % (x, y, width, height))
299 canvas.size_rect.setX(x)
300 canvas.size_rect.setY(y)
301 canvas.size_rect.setWidth(width)
302 canvas.size_rect.setHeight(height)
303 canvas.scene.updateLimits()
304 canvas.scene.fixScaleFactor()
306 def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):
307 if canvas.debug:
308 print("PatchCanvas::addGroup(%i, %s, %s, %s)" % (
309 group_id, group_name.encode(), split2str(split), icon2str(icon)))
311 for group in canvas.group_list:
312 if group.group_id == group_id:
313 qWarning("PatchCanvas::addGroup(%i, %s, %s, %s) - group already exists" % (
314 group_id, group_name.encode(), split2str(split), icon2str(icon)))
315 return None
317 old_matching_group = canvas.old_group_pos.pop(group_name, None)
319 if split == SPLIT_UNDEF:
320 isHardware = bool(icon == ICON_HARDWARE)
322 if features.handle_group_pos:
323 split = getStoredCanvasSplit(group_name, SPLIT_YES if isHardware else split)
324 elif isHardware:
325 split = SPLIT_YES
326 elif old_matching_group is not None and old_matching_group[0]:
327 split = SPLIT_YES
329 group_box = CanvasBox(group_id, group_name, icon)
330 group_box.positionChanged.connect(canvas.qobject.boxPositionChanged)
331 group_box.blockSignals(True)
333 group_dict = group_dict_t()
334 group_dict.group_id = group_id
335 group_dict.group_name = group_name
336 group_dict.split = bool(split == SPLIT_YES)
337 group_dict.icon = icon
338 group_dict.plugin_id = -1
339 group_dict.plugin_ui = False
340 group_dict.plugin_inline = False
341 group_dict.widgets = [group_box, None]
343 if split == SPLIT_YES:
344 group_box.setSplit(True, PORT_MODE_OUTPUT)
346 if features.handle_group_pos:
347 group_box.setPos(getStoredCanvasPosition(group_name + "_OUTPUT", CanvasGetNewGroupPos(False)))
348 elif old_matching_group is not None:
349 group_box.setPos(old_matching_group[1])
350 else:
351 group_box.setPos(CanvasGetNewGroupPos(False))
353 group_sbox = CanvasBox(group_id, group_name, icon)
354 group_sbox.positionChanged.connect(canvas.qobject.sboxPositionChanged)
355 group_sbox.blockSignals(True)
356 group_sbox.setSplit(True, PORT_MODE_INPUT)
358 group_dict.widgets[1] = group_sbox
360 if features.handle_group_pos:
361 group_sbox.setPos(getStoredCanvasPosition(group_name + "_INPUT", CanvasGetNewGroupPos(True)))
362 elif old_matching_group is not None and old_matching_group[0]:
363 group_sbox.setPos(old_matching_group[2])
364 else:
365 group_sbox.setPos(group_box.x() + group_box.boundingRect().width() + 300, group_box.y())
367 canvas.last_z_value += 1
368 group_sbox.setZValue(canvas.last_z_value)
370 if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
371 CanvasItemFX(group_sbox, True, False)
373 group_sbox.checkItemPos()
374 group_sbox.blockSignals(False)
376 else:
377 group_box.setSplit(False)
379 if features.handle_group_pos:
380 group_box.setPos(getStoredCanvasPosition(group_name, CanvasGetNewGroupPos(False)))
381 elif old_matching_group is not None:
382 group_box.setPos(old_matching_group[1])
383 else:
384 # Special ladish fake-split groups
385 horizontal = bool(icon == ICON_HARDWARE or icon == ICON_LADISH_ROOM)
386 group_box.setPos(CanvasGetNewGroupPos(horizontal))
388 canvas.last_z_value += 1
389 group_box.setZValue(canvas.last_z_value)
391 group_box.checkItemPos()
392 group_box.blockSignals(False)
394 canvas.group_list.append(group_dict)
396 if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
397 CanvasItemFX(group_box, True, False)
398 else:
399 QTimer.singleShot(0, canvas.scene.update)
401 return group_dict
403 def removeGroup(group_id):
404 if canvas.debug:
405 print("PatchCanvas::removeGroup(%i)" % group_id)
407 for group in canvas.group_list:
408 if group.group_id == group_id:
409 item = group.widgets[0]
410 group_name = group.group_name
412 if group.split:
413 s_item = group.widgets[1]
415 if features.handle_group_pos:
416 canvas.settings.setValue("CanvasPositions/%s_OUTPUT" % group_name, item.pos())
417 canvas.settings.setValue("CanvasPositions/%s_INPUT" % group_name, s_item.pos())
418 canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_YES)
420 if options.eyecandy == EYECANDY_FULL:
421 CanvasItemFX(s_item, False, True)
422 else:
423 s_item.removeIconFromScene()
424 canvas.scene.removeItem(s_item)
425 del s_item
427 else:
428 if features.handle_group_pos:
429 canvas.settings.setValue("CanvasPositions/%s" % group_name, item.pos())
430 canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_NO)
432 if options.eyecandy == EYECANDY_FULL:
433 CanvasItemFX(item, False, True)
434 else:
435 item.removeIconFromScene()
436 canvas.scene.removeItem(item)
437 del item
439 canvas.group_list.remove(group)
440 canvas.group_plugin_map.pop(group.plugin_id, None)
442 QTimer.singleShot(0, canvas.scene.update)
443 return
445 qCritical("PatchCanvas::removeGroup(%i) - unable to find group to remove" % group_id)
447 def renameGroup(group_id, new_group_name):
448 if canvas.debug:
449 print("PatchCanvas::renameGroup(%i, %s)" % (group_id, new_group_name.encode()))
451 for group in canvas.group_list:
452 if group.group_id == group_id:
453 group.group_name = new_group_name
454 group.widgets[0].setGroupName(new_group_name)
456 if group.split and group.widgets[1]:
457 group.widgets[1].setGroupName(new_group_name)
459 QTimer.singleShot(0, canvas.scene.update)
460 return
462 qCritical("PatchCanvas::renameGroup(%i, %s) - unable to find group to rename" % (group_id, new_group_name.encode()))
464 def splitGroup(group_id):
465 if canvas.debug:
466 print("PatchCanvas::splitGroup(%i)" % group_id)
468 item = None
469 group_name = ""
470 group_icon = ICON_APPLICATION
471 group_pos = None
472 plugin_id = -1
473 plugin_ui = False
474 plugin_inline = False
475 ports_data = []
476 conns_data = []
478 # Step 1 - Store all Item data
479 for group in canvas.group_list:
480 if group.group_id == group_id:
481 if group.split:
482 if canvas.debug:
483 print("PatchCanvas::splitGroup(%i) - group is already split" % group_id)
484 return
486 item = group.widgets[0]
487 group_name = group.group_name
488 group_icon = group.icon
489 group_pos = item.pos()
490 plugin_id = group.plugin_id
491 plugin_ui = group.plugin_ui
492 plugin_inline = group.plugin_inline
493 break
495 if not item:
496 qCritical("PatchCanvas::splitGroup(%i) - unable to find group to split" % group_id)
497 return
499 port_list_ids = list(item.getPortList())
501 for port in canvas.port_list:
502 if port.group_id == group_id and port.port_id in port_list_ids:
503 port_dict = port_dict_t()
504 port_dict.group_id = port.group_id
505 port_dict.port_id = port.port_id
506 port_dict.port_name = port.port_name
507 port_dict.port_mode = port.port_mode
508 port_dict.port_type = port.port_type
509 port_dict.is_alternate = port.is_alternate
510 port_dict.widget = None
511 ports_data.append(port_dict)
513 for connection in canvas.connection_list:
514 if (connection.group_in_id == group_id and connection.port_in_id in port_list_ids) or \
515 (connection.group_out_id == group_id and connection.port_out_id in port_list_ids):
516 connection_dict = connection_dict_t()
517 connection_dict.connection_id = connection.connection_id
518 connection_dict.group_in_id = connection.group_in_id
519 connection_dict.port_in_id = connection.port_in_id
520 connection_dict.group_out_id = connection.group_out_id
521 connection_dict.port_out_id = connection.port_out_id
522 connection_dict.widget = None
523 conns_data.append(connection_dict)
525 # Step 2 - Remove Item and Children
526 for conn in conns_data:
527 disconnectPorts(conn.connection_id)
529 for port_id in port_list_ids:
530 removePort(group_id, port_id)
532 removeGroup(group_id)
534 # Step 3 - Re-create Item, now split
535 group = addGroup(group_id, group_name, SPLIT_YES, group_icon)
537 if plugin_id >= 0:
538 setGroupAsPlugin(group_id, plugin_id, plugin_ui, plugin_inline)
540 for port in ports_data:
541 addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
543 for conn in conns_data:
544 connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id, True)
546 if group is not None:
547 pos1 = group.widgets[0].pos()
548 pos2 = group.widgets[1].pos()
549 group2_pos = QPointF(group_pos.x() + group.widgets[1].boundingRect().width() * 3/2, group_pos.y())
550 group.widgets[0].blockSignals(True)
551 group.widgets[0].setPos(group_pos)
552 group.widgets[0].blockSignals(False)
553 group.widgets[1].blockSignals(True)
554 group.widgets[1].setPos(group2_pos)
555 group.widgets[1].checkItemPos()
556 group.widgets[1].blockSignals(False)
557 valueStr = "%i:%i:%i:%i" % (group_pos.x(), group_pos.y(), group2_pos.x(), group2_pos.y())
558 CanvasCallback(ACTION_GROUP_POSITION, group_id, 0, valueStr)
560 QTimer.singleShot(0, canvas.scene.update)
562 def joinGroup(group_id):
563 if canvas.debug:
564 print("PatchCanvas::joinGroup(%i)" % group_id)
566 item = None
567 s_item = None
568 group_name = ""
569 group_icon = ICON_APPLICATION
570 group_pos = None
571 plugin_id = -1
572 plugin_ui = False
573 plugin_inline = False
574 ports_data = []
575 conns_data = []
577 # Step 1 - Store all Item data
578 for group in canvas.group_list:
579 if group.group_id == group_id:
580 if not group.split:
581 if canvas.debug:
582 print("PatchCanvas::joinGroup(%i) - group is not split" % group_id)
583 return
585 item = group.widgets[0]
586 s_item = group.widgets[1]
587 group_name = group.group_name
588 group_icon = group.icon
589 group_pos = item.pos()
590 plugin_id = group.plugin_id
591 plugin_ui = group.plugin_ui
592 plugin_inline = group.plugin_inline
593 break
595 # FIXME
596 if not (item and s_item):
597 qCritical("PatchCanvas::joinGroup(%i) - unable to find groups to join" % group_id)
598 return
600 port_list_ids = list(item.getPortList())
601 port_list_idss = s_item.getPortList()
603 for port_id in port_list_idss:
604 if port_id not in port_list_ids:
605 port_list_ids.append(port_id)
607 for port in canvas.port_list:
608 if port.group_id == group_id and port.port_id in port_list_ids:
609 port_dict = port_dict_t()
610 port_dict.group_id = port.group_id
611 port_dict.port_id = port.port_id
612 port_dict.port_name = port.port_name
613 port_dict.port_mode = port.port_mode
614 port_dict.port_type = port.port_type
615 port_dict.is_alternate = port.is_alternate
616 port_dict.widget = None
617 ports_data.append(port_dict)
619 for connection in canvas.connection_list:
620 if (connection.group_in_id == group_id and connection.port_in_id in port_list_ids) or \
621 (connection.group_out_id == group_id and connection.port_out_id in port_list_ids):
622 connection_dict = connection_dict_t()
623 connection_dict.connection_id = connection.connection_id
624 connection_dict.group_in_id = connection.group_in_id
625 connection_dict.port_in_id = connection.port_in_id
626 connection_dict.group_out_id = connection.group_out_id
627 connection_dict.port_out_id = connection.port_out_id
628 connection_dict.widget = None
629 conns_data.append(connection_dict)
631 # Step 2 - Remove Item and Children
632 for conn in conns_data:
633 disconnectPorts(conn.connection_id)
635 for port_id in port_list_ids:
636 removePort(group_id, port_id)
638 removeGroup(group_id)
640 # Step 3 - Re-create Item, now together
641 group = addGroup(group_id, group_name, SPLIT_NO, group_icon)
643 if plugin_id >= 0:
644 setGroupAsPlugin(group_id, plugin_id, plugin_ui, plugin_inline)
646 for port in ports_data:
647 addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
649 for conn in conns_data:
650 connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id, True)
652 if group is not None:
653 group.widgets[0].blockSignals(True)
654 group.widgets[0].setPos(group_pos)
655 group.widgets[0].checkItemPos()
656 group.widgets[0].blockSignals(False)
657 valueStr = "%i:%i:%i:%i" % (group_pos.x(), group_pos.y(), 0, 0)
658 CanvasCallback(ACTION_GROUP_POSITION, group_id, 0, valueStr)
660 QTimer.singleShot(0, canvas.scene.update)
662 # ------------------------------------------------------------------------------------------------------------
664 def getGroupPos(group_id, port_mode=PORT_MODE_OUTPUT):
665 if canvas.debug:
666 print("PatchCanvas::getGroupPos(%i, %s)" % (group_id, port_mode2str(port_mode)))
668 for group in canvas.group_list:
669 if group.group_id == group_id:
670 return group.widgets[1 if (group.split and port_mode == PORT_MODE_INPUT) else 0].pos()
672 qCritical("PatchCanvas::getGroupPos(%i, %s) - unable to find group" % (group_id, port_mode2str(port_mode)))
673 return QPointF(0, 0)
675 def saveGroupPositions():
676 if canvas.debug:
677 print("PatchCanvas::getGroupPositions()")
679 ret = []
681 for group in canvas.group_list:
682 if group.split:
683 pos1 = group.widgets[0].pos()
684 pos2 = group.widgets[1].pos()
685 else:
686 pos1 = group.widgets[0].pos()
687 pos2 = QPointF(0, 0)
689 ret.append({
690 "name" : group.group_name,
691 "pos1x": pos1.x(),
692 "pos1y": pos1.y(),
693 "pos2x": pos2.x(),
694 "pos2y": pos2.y(),
695 "split": group.split,
698 return ret
700 def restoreGroupPositions(dataList):
701 if canvas.debug:
702 print("PatchCanvas::restoreGroupPositions(...)")
704 mapping = {}
706 for group in canvas.group_list:
707 mapping[group.group_name] = group
709 for data in dataList:
710 name = data['name']
711 group = mapping.get(name, None)
713 if group is None:
714 continue
716 group.widgets[0].blockSignals(True)
717 group.widgets[0].setPos(data['pos1x'], data['pos1y'])
718 group.widgets[0].blockSignals(False)
720 if group.split and group.widgets[1]:
721 group.widgets[1].blockSignals(True)
722 group.widgets[1].setPos(data['pos2x'], data['pos2y'])
723 group.widgets[1].blockSignals(False)
725 def setGroupPos(group_id, group_pos_x, group_pos_y):
726 setGroupPosFull(group_id, group_pos_x, group_pos_y, group_pos_x, group_pos_y)
728 def setGroupPosFull(group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i):
729 if canvas.debug:
730 print("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i)" % (
731 group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
733 for group in canvas.group_list:
734 if group.group_id == group_id:
735 group.widgets[0].blockSignals(True)
736 group.widgets[0].setPos(group_pos_x_o, group_pos_y_o)
737 group.widgets[0].checkItemPos()
738 group.widgets[0].blockSignals(False)
740 if group.split and group.widgets[1]:
741 group.widgets[1].blockSignals(True)
742 group.widgets[1].setPos(group_pos_x_i, group_pos_y_i)
743 group.widgets[1].checkItemPos()
744 group.widgets[1].blockSignals(False)
746 QTimer.singleShot(0, canvas.scene.update)
747 return
749 qCritical("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i) - unable to find group to reposition" % (
750 group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
752 # ------------------------------------------------------------------------------------------------------------
754 def setGroupIcon(group_id, icon):
755 if canvas.debug:
756 print("PatchCanvas::setGroupIcon(%i, %s)" % (group_id, icon2str(icon)))
758 for group in canvas.group_list:
759 if group.group_id == group_id:
760 group.icon = icon
761 group.widgets[0].setIcon(icon)
763 if group.split and group.widgets[1]:
764 group.widgets[1].setIcon(icon)
766 QTimer.singleShot(0, canvas.scene.update)
767 return
769 qCritical("PatchCanvas::setGroupIcon(%i, %s) - unable to find group to change icon" % (group_id, icon2str(icon)))
771 def setGroupAsPlugin(group_id, plugin_id, hasUI, hasInlineDisplay):
772 if canvas.debug:
773 print("PatchCanvas::setGroupAsPlugin(%i, %i, %s, %s)" % (
774 group_id, plugin_id, bool2str(hasUI), bool2str(hasInlineDisplay)))
776 for group in canvas.group_list:
777 if group.group_id == group_id:
778 group.plugin_id = plugin_id
779 group.plugin_ui = hasUI
780 group.plugin_inline = hasInlineDisplay
781 group.widgets[0].setAsPlugin(plugin_id, hasUI, hasInlineDisplay)
783 if group.split and group.widgets[1]:
784 group.widgets[1].setAsPlugin(plugin_id, hasUI, hasInlineDisplay)
786 canvas.group_plugin_map[plugin_id] = group
787 return
789 qCritical("PatchCanvas::setGroupAsPlugin(%i, %i, %s, %s) - unable to find group to set as plugin" % (
790 group_id, plugin_id, bool2str(hasUI), bool2str(hasInlineDisplay)))
792 # ------------------------------------------------------------------------------------------------------------
794 def focusGroupUsingPluginId(plugin_id):
795 if canvas.debug:
796 print("PatchCanvas::focusGroupUsingPluginId(%i)" % (plugin_id,))
798 if plugin_id < 0 or plugin_id >= MAX_PLUGIN_ID_ALLOWED:
799 return False
801 for group in canvas.group_list:
802 if group.plugin_id == plugin_id:
803 item = group.widgets[0]
804 canvas.scene.clearSelection()
805 canvas.scene.getView().centerOn(item)
806 item.setSelected(True)
807 return True
809 def focusGroupUsingGroupName(group_name):
810 if canvas.debug:
811 print("PatchCanvas::focusGroupUsingGroupName(%s)" % (group_name,))
813 for group in canvas.group_list:
814 if group.group_name == group_name:
815 item = group.widgets[0]
816 canvas.scene.clearSelection()
817 canvas.scene.getView().centerOn(item)
818 item.setSelected(True)
819 return True
821 # ------------------------------------------------------------------------------------------------------------
823 def addPort(group_id, port_id, port_name, port_mode, port_type, is_alternate=False):
824 if canvas.debug:
825 print("PatchCanvas::addPort(%i, %i, %s, %s, %s, %s)" % (
826 group_id, port_id, port_name.encode(),
827 port_mode2str(port_mode), port_type2str(port_type), bool2str(is_alternate)))
829 for port in canvas.port_list:
830 if port.group_id == group_id and port.port_id == port_id:
831 qWarning("PatchCanvas::addPort(%i, %i, %s, %s, %s) - port already exists" % (
832 group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
833 return
835 box_widget = None
836 port_widget = None
838 for group in canvas.group_list:
839 if group.group_id == group_id:
840 if group.split and group.widgets[0].getSplitMode() != port_mode and group.widgets[1]:
841 n = 1
842 else:
843 n = 0
844 box_widget = group.widgets[n]
845 port_widget = box_widget.addPortFromGroup(port_id, port_mode, port_type, port_name, is_alternate)
846 break
848 if not (box_widget and port_widget):
849 qCritical("PatchCanvas::addPort(%i, %i, %s, %s, %s) - Unable to find parent group" % (
850 group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
851 return
853 port_dict = port_dict_t()
854 port_dict.group_id = group_id
855 port_dict.port_id = port_id
856 port_dict.port_name = port_name
857 port_dict.port_mode = port_mode
858 port_dict.port_type = port_type
859 port_dict.is_alternate = is_alternate
860 port_dict.widget = port_widget
861 canvas.port_list.append(port_dict)
863 box_widget.updatePositions()
865 if options.eyecandy == EYECANDY_FULL:
866 CanvasItemFX(port_widget, True, False)
867 return
869 QTimer.singleShot(0, canvas.scene.update)
871 def removePort(group_id, port_id):
872 if canvas.debug:
873 print("PatchCanvas::removePort(%i, %i)" % (group_id, port_id))
875 for port in canvas.port_list:
876 if port.group_id == group_id and port.port_id == port_id:
877 item = port.widget
878 try:
879 pitem = item.parentItem()
880 canvas.scene.removeItem(item)
881 except RuntimeError:
882 pass
883 else:
884 pitem.removePortFromGroup(port_id)
885 canvas.port_list.remove(port)
886 del item
888 QTimer.singleShot(0, canvas.scene.update)
889 return
891 qCritical("PatchCanvas::removePort(%i, %i) - Unable to find port to remove" % (group_id, port_id))
893 def renamePort(group_id, port_id, new_port_name):
894 if canvas.debug:
895 print("PatchCanvas::renamePort(%i, %i, %s)" % (group_id, port_id, new_port_name.encode()))
897 for port in canvas.port_list:
898 if port.group_id == group_id and port.port_id == port_id:
899 port.port_name = new_port_name
900 port.widget.setPortName(new_port_name)
901 port.widget.parentItem().updatePositions()
903 QTimer.singleShot(0, canvas.scene.update)
904 return
906 qCritical("PatchCanvas::renamePort(%i, %i, %s) - Unable to find port to rename" % (
907 group_id, port_id, new_port_name.encode()))
909 def connectPorts(connection_id, group_out_id, port_out_id, group_in_id, port_in_id, fromSplitOrJoin = False):
910 if canvas.last_connection_id >= connection_id and not fromSplitOrJoin:
911 print("PatchCanvas::connectPorts(%i, %i, %i, %i, %i) - invalid connection id received (last: %i)" % (
912 connection_id, group_out_id, port_out_id, group_in_id, port_in_id, canvas.last_connection_id))
913 return
915 canvas.last_connection_id = connection_id
917 if canvas.debug:
918 print("PatchCanvas::connectPorts(%i, %i, %i, %i, %i)" % (
919 connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
921 port_out = None
922 port_in = None
923 port_out_parent = None
924 port_in_parent = None
926 for port in canvas.port_list:
927 if port.group_id == group_out_id and port.port_id == port_out_id:
928 port_out = port.widget
929 port_out_parent = port_out.parentItem()
930 elif port.group_id == group_in_id and port.port_id == port_in_id:
931 port_in = port.widget
932 port_in_parent = port_in.parentItem()
934 # FIXME
935 if not (port_out and port_in):
936 qCritical("PatchCanvas::connectPorts(%i, %i, %i, %i, %i) - unable to find ports to connect" % (
937 connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
938 return
940 connection_dict = connection_dict_t()
941 connection_dict.connection_id = connection_id
942 connection_dict.group_in_id = group_in_id
943 connection_dict.port_in_id = port_in_id
944 connection_dict.group_out_id = group_out_id
945 connection_dict.port_out_id = port_out_id
947 if options.use_bezier_lines:
948 connection_dict.widget = CanvasBezierLine(port_out, port_in, None)
949 else:
950 connection_dict.widget = CanvasLine(port_out, port_in, None)
952 canvas.scene.addItem(connection_dict.widget)
954 port_out_parent.addLineFromGroup(connection_dict.widget, connection_id)
955 port_in_parent.addLineFromGroup(connection_dict.widget, connection_id)
957 canvas.last_z_value += 1
958 port_out_parent.setZValue(canvas.last_z_value)
959 port_in_parent.setZValue(canvas.last_z_value)
961 canvas.last_z_value += 1
962 connection_dict.widget.setZValue(canvas.last_z_value)
964 canvas.connection_list.append(connection_dict)
966 if options.eyecandy == EYECANDY_FULL:
967 item = connection_dict.widget
968 CanvasItemFX(item, True, False)
969 return
971 QTimer.singleShot(0, canvas.scene.update)
973 def disconnectPorts(connection_id):
974 if canvas.debug:
975 print("PatchCanvas::disconnectPorts(%i)" % connection_id)
977 line = None
978 item1 = None
979 item2 = None
980 group1id = port1id = 0
981 group2id = port2id = 0
983 for connection in canvas.connection_list:
984 if connection.connection_id == connection_id:
985 group1id = connection.group_out_id
986 group2id = connection.group_in_id
987 port1id = connection.port_out_id
988 port2id = connection.port_in_id
989 line = connection.widget
990 canvas.connection_list.remove(connection)
991 break
993 if not line:
994 qCritical("PatchCanvas::disconnectPorts(%i) - unable to find connection ports" % connection_id)
995 return
997 for port in canvas.port_list:
998 if port.group_id == group1id and port.port_id == port1id:
999 item1 = port.widget
1000 break
1002 if not item1:
1003 qCritical("PatchCanvas::disconnectPorts(%i) - unable to find output port" % connection_id)
1004 return
1006 for port in canvas.port_list:
1007 if port.group_id == group2id and port.port_id == port2id:
1008 item2 = port.widget
1009 break
1011 if not item2:
1012 qCritical("PatchCanvas::disconnectPorts(%i) - unable to find input port" % connection_id)
1013 return
1015 item1p = item1.parentItem()
1016 item2p = item2.parentItem()
1017 if item1p:
1018 item1p.removeLineFromGroup(connection_id)
1019 if item2p:
1020 item2p.removeLineFromGroup(connection_id)
1022 if options.eyecandy == EYECANDY_FULL:
1023 CanvasItemFX(line, False, True)
1024 return
1026 canvas.scene.removeItem(line)
1027 del line
1029 QTimer.singleShot(0, canvas.scene.update)
1031 # ------------------------------------------------------------------------------------------------------------
1033 def arrange():
1034 if canvas.debug:
1035 print("PatchCanvas::arrange()")
1037 # ------------------------------------------------------------------------------------------------------------
1039 def updateZValues():
1040 if canvas.debug:
1041 print("PatchCanvas::updateZValues()")
1043 for group in canvas.group_list:
1044 group.widgets[0].resetLinesZValue()
1046 if group.split and group.widgets[1]:
1047 group.widgets[1].resetLinesZValue()
1049 # ------------------------------------------------------------------------------------------------------------
1051 def redrawPluginGroup(plugin_id):
1052 group = canvas.group_plugin_map.get(plugin_id, None)
1054 if group is None:
1055 #qCritical("PatchCanvas::redrawPluginGroup(%i) - unable to find group" % plugin_id)
1056 return
1058 group.widgets[0].redrawInlineDisplay()
1060 if group.split and group.widgets[1]:
1061 group.widgets[1].redrawInlineDisplay()
1063 def handlePluginRemoved(plugin_id):
1064 if canvas.debug:
1065 print("PatchCanvas::handlePluginRemoved(%i)" % plugin_id)
1067 canvas.scene.clearSelection()
1069 group = canvas.group_plugin_map.pop(plugin_id, None)
1071 if group is not None:
1072 group.plugin_id = -1
1073 group.plugin_ui = False
1074 group.plugin_inline = False
1075 group.widgets[0].removeAsPlugin()
1077 if group.split and group.widgets[1]:
1078 group.widgets[1].removeAsPlugin()
1080 for group in canvas.group_list:
1081 if group.plugin_id < plugin_id or group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
1082 continue
1084 group.plugin_id -= 1
1085 group.widgets[0].m_plugin_id -= 1
1087 if group.split and group.widgets[1]:
1088 group.widgets[1].m_plugin_id -= 1
1090 canvas.group_plugin_map[plugin_id] = group
1092 def handleAllPluginsRemoved():
1093 if canvas.debug:
1094 print("PatchCanvas::handleAllPluginsRemoved()")
1096 canvas.group_plugin_map = {}
1098 for group in canvas.group_list:
1099 if group.plugin_id < 0:
1100 continue
1101 if group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
1102 continue
1104 group.plugin_id = -1
1105 group.plugin_ui = False
1106 group.plugin_inline = False
1107 group.widgets[0].removeAsPlugin()
1109 if group.split and group.widgets[1]:
1110 group.widgets[1].removeAsPlugin()
1112 # ------------------------------------------------------------------------------------------------------------