1 /*
2 * Patchbay Canvas engine using QGraphicsView/Scene
3 * Copyright (C) 2010-2012 Filipe Coelho <falktx@falktx.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * For a full copy of the GNU General Public License see the COPYING file
16 */
17
18 #include "patchcanvas.h"
19 #include "patchscene.h"
20
21 #include <QtCore/QSettings>
22 #include <QtCore/QTimer>
23 #include <QtGui/QAction>
24
25 #include "canvasfadeanimation.h"
26 #include "canvasline.h"
27 #include "canvasbezierline.h"
28 #include "canvasport.h"
29 #include "canvasbox.h"
30
CanvasObject(QObject * parent)31 CanvasObject::CanvasObject(QObject* parent) : QObject(parent) {}
32
AnimationIdle()33 void CanvasObject::AnimationIdle()
34 {
35 PatchCanvas::CanvasFadeAnimation* animation = (PatchCanvas::CanvasFadeAnimation*)sender();
36 if (animation)
37 PatchCanvas::CanvasRemoveAnimation(animation);
38 }
39
AnimationHide()40 void CanvasObject::AnimationHide()
41 {
42 PatchCanvas::CanvasFadeAnimation* animation = (PatchCanvas::CanvasFadeAnimation*)sender();
43 if (animation)
44 {
45 if (animation->item())
46 animation->item()->hide();
47 PatchCanvas::CanvasRemoveAnimation(animation);
48 }
49 }
50
AnimationDestroy()51 void CanvasObject::AnimationDestroy()
52 {
53 PatchCanvas::CanvasFadeAnimation* animation = (PatchCanvas::CanvasFadeAnimation*)sender();
54 if (animation)
55 {
56 if (animation->item())
57 PatchCanvas::CanvasRemoveItemFX(animation->item());
58 PatchCanvas::CanvasRemoveAnimation(animation);
59 }
60 }
61
CanvasPostponedGroups()62 void CanvasObject::CanvasPostponedGroups()
63 {
64 PatchCanvas::CanvasPostponedGroups();
65 }
66
PortContextMenuDisconnect()67 void CanvasObject::PortContextMenuDisconnect()
68 {
69 bool ok;
70 int connection_id = ((QAction*)sender())->data().toInt(&ok);
71 if (ok)
72 PatchCanvas::CanvasCallback(PatchCanvas::ACTION_PORTS_DISCONNECT, connection_id, 0, "");
73 }
74
75 START_NAMESPACE_PATCHCANVAS
76
77 /* contructor and destructor */
Canvas()78 Canvas::Canvas()
79 {
80 qobject = 0;
81 settings = 0;
82 theme = 0;
83 initiated = false;
84 }
85
~Canvas()86 Canvas::~Canvas()
87 {
88 if (qobject)
89 delete qobject;
90 if (settings)
91 delete settings;
92 if (theme)
93 delete theme;
94 }
95
96 /* Global objects */
97 Canvas canvas;
98
99 options_t options = {
100 /* theme_name */ getDefaultThemeName(),
101 /* auto_hide_groups */ false,
102 /* use_bezier_lines */ true,
103 /* antialiasing */ ANTIALIASING_SMALL,
104 /* eyecandy */ EYECANDY_SMALL
105 };
106
107 features_t features = {
108 /* group_info */ false,
109 /* group_rename */ false,
110 /* port_info */ false,
111 /* port_rename */ false,
112 /* handle_group_pos */ false
113 };
114
115 /* Internal functions */
bool2str(bool check)116 const char* bool2str(bool check)
117 {
118 return check ? "true" : "false";
119 }
120
port_mode2str(PortMode port_mode)121 const char* port_mode2str(PortMode port_mode)
122 {
123 if (port_mode == PORT_MODE_NULL)
124 return "PORT_MODE_NULL";
125 else if (port_mode == PORT_MODE_INPUT)
126 return "PORT_MODE_INPUT";
127 else if (port_mode == PORT_MODE_OUTPUT)
128 return "PORT_MODE_OUTPUT";
129 else
130 return "PORT_MODE_???";
131 }
132
port_type2str(PortType port_type)133 const char* port_type2str(PortType port_type)
134 {
135 if (port_type == PORT_TYPE_NULL)
136 return "PORT_TYPE_NULL";
137 else if (port_type == PORT_TYPE_AUDIO_JACK)
138 return "PORT_TYPE_AUDIO_JACK";
139 else if (port_type == PORT_TYPE_MIDI_JACK)
140 return "PORT_TYPE_MIDI_JACK";
141 else if (port_type == PORT_TYPE_MIDI_A2J)
142 return "PORT_TYPE_MIDI_A2J";
143 else if (port_type == PORT_TYPE_MIDI_ALSA)
144 return "PORT_TYPE_MIDI_ALSA";
145 else
146 return "PORT_TYPE_???";
147 }
148
icon2str(Icon icon)149 const char* icon2str(Icon icon)
150 {
151 if (icon == ICON_HARDWARE)
152 return "ICON_HARDWARE";
153 else if (ICON_APPLICATION)
154 return "ICON_APPLICATION";
155 else if (ICON_LADISH_ROOM)
156 return "ICON_LADISH_ROOM";
157 else
158 return "ICON_???";
159 }
160
split2str(SplitOption split)161 const char* split2str(SplitOption split)
162 {
163 if (split == SPLIT_UNDEF)
164 return "SPLIT_UNDEF";
165 else if (split == SPLIT_NO)
166 return "SPLIT_NO";
167 else if (split == SPLIT_YES)
168 return "SPLIT_YES";
169 else
170 return "SPLIT_???";
171 }
172
173 /* PatchCanvas API */
setOptions(options_t * new_options)174 void setOptions(options_t* new_options)
175 {
176 if (canvas.initiated) return;
177 options.theme_name = new_options->theme_name;
178 options.auto_hide_groups = new_options->auto_hide_groups;
179 options.use_bezier_lines = new_options->use_bezier_lines;
180 options.antialiasing = new_options->antialiasing;
181 options.eyecandy = new_options->eyecandy;
182 }
183
setFeatures(features_t * new_features)184 void setFeatures(features_t* new_features)
185 {
186 if (canvas.initiated) return;
187 features.group_info = new_features->group_info;
188 features.group_rename = new_features->group_rename;
189 features.port_info = new_features->port_info;
190 features.port_rename = new_features->port_rename;
191 features.handle_group_pos = new_features->handle_group_pos;
192 }
193
init(PatchScene * scene,Callback callback,bool debug)194 void init(PatchScene* scene, Callback callback, bool debug)
195 {
196 if (debug)
197 qDebug("PatchCanvas::init(%p, %p, %s)", scene, callback, bool2str(debug));
198
199 if (canvas.initiated)
200 {
201 qCritical("PatchCanvas::init() - already initiated");
202 return;
203 }
204
205 if (!callback)
206 {
207 qFatal("PatchCanvas::init() - fatal error: callback not set");
208 return;
209 }
210
211 canvas.scene = scene;
212 canvas.callback = callback;
213 canvas.debug = debug;
214
215 canvas.last_z_value = 0;
216 canvas.last_connection_id = 0;
217 canvas.initial_pos = QPointF(0, 0);
218 canvas.size_rect = QRectF();
219
220 if (!canvas.qobject) canvas.qobject = new CanvasObject();
221 if (!canvas.settings) canvas.settings = new QSettings(PATCHCANVAS_ORGANISATION_NAME, "PatchCanvas");
222
223 if (canvas.theme)
224 {
225 delete canvas.theme;
226 canvas.theme = 0;
227 }
228
229 for (int i=0; i<Theme::THEME_MAX; i++)
230 {
231 QString this_theme_name = getThemeName(static_cast<Theme::List>(i));
232 if (this_theme_name == options.theme_name)
233 {
234 canvas.theme = new Theme(static_cast<Theme::List>(i));
235 break;
236 }
237 }
238
239 if (!canvas.theme)
240 canvas.theme = new Theme(getDefaultTheme());
241
242 canvas.scene->updateTheme();
243
244 canvas.initiated = true;
245 }
246
clear()247 void clear()
248 {
249 if (canvas.debug)
250 qDebug("PatchCanvas::clear()");
251
252 QList<int> group_list_ids;
253 QList<int> port_list_ids;
254 QList<int> connection_list_ids;
255
256 foreach (const group_dict_t& group, canvas.group_list)
257 group_list_ids.append(group.group_id);
258
259 foreach (const port_dict_t& port, canvas.port_list)
260 port_list_ids.append(port.port_id);
261
262 foreach (const connection_dict_t& connection, canvas.connection_list)
263 connection_list_ids.append(connection.connection_id);
264
265 foreach (const int& idx, connection_list_ids)
266 disconnectPorts(idx);
267
268 foreach (const int& idx, port_list_ids)
269 removePort(idx);
270
271 foreach (const int& idx, group_list_ids)
272 removeGroup(idx);
273
274 canvas.last_z_value = 0;
275 canvas.last_connection_id = 0;
276
277 canvas.group_list.clear();
278 canvas.port_list.clear();
279 canvas.connection_list.clear();
280
281 canvas.initiated = false;
282 }
283
setInitialPos(int x,int y)284 void setInitialPos(int x, int y)
285 {
286 if (canvas.debug)
287 qDebug("PatchCanvas::setInitialPos(%i, %i)", x, y);
288
289 canvas.initial_pos.setX(x);
290 canvas.initial_pos.setY(y);
291 }
292
setCanvasSize(int x,int y,int width,int height)293 void setCanvasSize(int x, int y, int width, int height)
294 {
295 if (canvas.debug)
296 qDebug("PatchCanvas::setCanvasSize(%i, %i, %i, %i)", x, y, width, height);
297
298 canvas.size_rect.setX(x);
299 canvas.size_rect.setY(y);
300 canvas.size_rect.setWidth(width);
301 canvas.size_rect.setHeight(height);
302 }
303
addGroup(int group_id,QString group_name,SplitOption split,Icon icon)304 void addGroup(int group_id, QString group_name, SplitOption split, Icon icon)
305 {
306 if (canvas.debug)
307 qDebug("PatchCanvas::addGroup(%i, %s, %s, %s)", group_id, group_name.toUtf8().constData(), split2str(split), icon2str(icon));
308
309 foreach (const group_dict_t& group, canvas.group_list)
310 {
311 if (group.group_id == group_id)
312 {
313 qWarning("PatchCanvas::addGroup(%i, %s, %s, %s) - group already exists", group_id, group_name.toUtf8().constData(), split2str(split), icon2str(icon));
314 return;
315 }
316 }
317
318 if (split == SPLIT_UNDEF && features.handle_group_pos)
319 split = static_cast<SplitOption>(canvas.settings->value(QString("CanvasPositions/%1_SPLIT").arg(group_name), split).toInt());
320
321 CanvasBox* group_box = new CanvasBox(group_id, group_name, icon);
322
323 group_dict_t group_dict;
324 group_dict.group_id = group_id;
325 group_dict.group_name = group_name;
326 group_dict.split = (split == SPLIT_YES);
327 group_dict.icon = icon;
328 group_dict.widgets[0] = group_box;
329 group_dict.widgets[1] = 0;
330
331 if (split == SPLIT_YES)
332 {
333 group_box->setSplit(true, PORT_MODE_OUTPUT);
334
335 if (features.handle_group_pos)
336 group_box->setPos(canvas.settings->value(QString("CanvasPositions/%1_OUTPUT").arg(group_name), CanvasGetNewGroupPos()).toPointF());
337 else
338 group_box->setPos(CanvasGetNewGroupPos());
339
340 CanvasBox* group_sbox = new CanvasBox(group_id, group_name, icon);
341 group_sbox->setSplit(true, PORT_MODE_INPUT);
342
343 group_dict.widgets[1] = group_sbox;
344
345 if (features.handle_group_pos)
346 group_sbox->setPos(canvas.settings->value(QString("CanvasPositions/%1_INPUT").arg(group_name), CanvasGetNewGroupPos(true)).toPointF());
347 else
348 group_sbox->setPos(CanvasGetNewGroupPos(true));
349
350 canvas.last_z_value += 1;
351 group_sbox->setZValue(canvas.last_z_value);
352
353 if (options.auto_hide_groups == false && options.eyecandy == EYECANDY_FULL)
354 CanvasItemFX(group_sbox, true);
355 }
356 else
357 {
358 group_box->setSplit(false);
359
360 if (features.handle_group_pos)
361 group_box->setPos(canvas.settings->value(QString("CanvasPositions/%1").arg(group_name), CanvasGetNewGroupPos()).toPointF());
362 else
363 {
364 // Special ladish fake-split groups
365 bool horizontal = (icon == ICON_HARDWARE || icon == ICON_LADISH_ROOM);
366 group_box->setPos(CanvasGetNewGroupPos(horizontal));
367 }
368 }
369
370 canvas.last_z_value += 1;
371 group_box->setZValue(canvas.last_z_value);
372
373 canvas.group_list.append(group_dict);
374
375 if (options.auto_hide_groups == false && options.eyecandy == EYECANDY_FULL)
376 CanvasItemFX(group_box, true);
377
378 QTimer::singleShot(0, canvas.scene, SLOT(update()));
379 }
380
removeGroup(int group_id)381 void removeGroup(int group_id)
382 {
383 if (canvas.debug)
384 qDebug("PatchCanvas::removeGroup(%i)", group_id);
385
386 foreach2 (const group_dict_t& group, canvas.group_list)
387 if (group.group_id == group_id)
388 {
389 CanvasBox* item = group.widgets[0];
390 QString group_name = group.group_name;
391
392 if (group.split)
393 {
394 CanvasBox* s_item = group.widgets[1];
395 if (features.handle_group_pos)
396 {
397 canvas.settings->setValue(QString("CanvasPositions/%1_OUTPUT").arg(group_name), item->pos());
398 canvas.settings->setValue(QString("CanvasPositions/%1_INPUT").arg(group_name), s_item->pos());
399 canvas.settings->setValue(QString("CanvasPositions/%1_SPLIT").arg(group_name), SPLIT_YES);
400 }
401
402 if (options.eyecandy == EYECANDY_FULL)
403 {
404 CanvasItemFX(s_item, false, true);
405 }
406 else
407 {
408 s_item->removeIconFromScene();
409 canvas.scene->removeItem(s_item);
410 delete s_item;
411 }
412 }
413 else
414 {
415 if (features.handle_group_pos)
416 {
417 canvas.settings->setValue(QString("CanvasPositions/%1").arg(group_name), item->pos());
418 canvas.settings->setValue(QString("CanvasPositions/%1_SPLIT").arg(group_name), SPLIT_NO);
419 }
420 }
421
422 if (options.eyecandy == EYECANDY_FULL)
423 {
424 CanvasItemFX(item, false, true);
425 }
426 else
427 {
428 item->removeIconFromScene();
429 canvas.scene->removeItem(item);
430 delete item;
431 }
432
433 canvas.group_list.takeAt(i);
434
435 QTimer::singleShot(0, canvas.scene, SLOT(update()));
436 return;
437 }
438 }
439
440 qCritical("PatchCanvas::removeGroup(%i) - unable to find group to remove", group_id);
441 }
442
443 void renameGroup(int group_id, QString new_group_name)
444 {
445 if (canvas.debug)
446 qDebug("PatchCanvas::renameGroup(%i, %s)", group_id, new_group_name.toUtf8().constData());
447
448 foreach2 (group_dict_t& group, canvas.group_list)
449 if (group.group_id == group_id)
450 {
451 group.group_name = new_group_name;
452 group.widgets[0]->setGroupName(new_group_name);
453
454 if (group.split && group.widgets[1])
455 group.widgets[1]->setGroupName(new_group_name);
456
457 QTimer::singleShot(0, canvas.scene, SLOT(update()));
458 return;
459 }
460 }
461
462 qCritical("PatchCanvas::renameGroup(%i, %s) - unable to find group to rename", group_id, new_group_name.toUtf8().constData());
463 }
464
465 void splitGroup(int group_id)
466 {
467 if (canvas.debug)
468 qDebug("PatchCanvas::splitGroup(%i)", group_id);
469
470 CanvasBox* item = 0;
471 QString group_name;
472 Icon group_icon = ICON_APPLICATION;
473 QList<port_dict_t> ports_data;
474 QList<connection_dict_t> conns_data;
475
476 // Step 1 - Store all Item data
477 foreach (const group_dict_t& group, canvas.group_list)
478 {
479 if (group.group_id == group_id)
480 {
481 if (group.split)
482 {
483 qCritical("PatchCanvas::splitGroup(%i) - group is already splitted", group_id);
484 return;
485 }
486
487 item = group.widgets[0];
488 group_name = group.group_name;
489 group_icon = group.icon;
490 break;
491 }
492 }
493
494 if (!item)
495 {
496 qCritical("PatchCanvas::splitGroup(%i) - unable to find group to split", group_id);
497 return;
498 }
499
500 QList<int> port_list_ids = QList<int>(item->getPortList());
501
502 foreach (const port_dict_t& port, canvas.port_list)
503 {
504 if (port_list_ids.contains(port.port_id))
505 {
506 port_dict_t port_dict;
507 port_dict.group_id = port.group_id;
508 port_dict.port_id = port.port_id;
509 port_dict.port_name = port.port_name;
510 port_dict.port_mode = port.port_mode;
511 port_dict.port_type = port.port_type;
512 port_dict.widget = 0;
513 ports_data.append(port_dict);
514 }
515 }
516
517 foreach (const connection_dict_t& connection, canvas.connection_list)
518 {
519 if (port_list_ids.contains(connection.port_out_id) || port_list_ids.contains(connection.port_in_id))
520 {
521 connection_dict_t connection_dict;
522 connection_dict.connection_id = connection.connection_id;
523 connection_dict.port_in_id = connection.port_in_id;
524 connection_dict.port_out_id = connection.port_out_id;
525 connection_dict.widget = 0;
526 conns_data.append(connection_dict);
527 }
528 }
529
530 // Step 2 - Remove Item and Children
531 foreach (const connection_dict_t& conn, conns_data)
532 disconnectPorts(conn.connection_id);
533
534 foreach (const int& port_id, port_list_ids)
535 removePort(port_id);
536
537 removeGroup(group_id);
538
539 // Step 3 - Re-create Item, now splitted
540 addGroup(group_id, group_name, SPLIT_YES, group_icon);
541
542 foreach (const port_dict_t& port, ports_data)
543 addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type);
544
545 foreach (const connection_dict_t& conn, conns_data)
546 connectPorts(conn.connection_id, conn.port_out_id, conn.port_in_id);
547
548 QTimer::singleShot(0, canvas.scene, SLOT(update()));
549 }
550
551 void joinGroup(int group_id)
552 {
553 if (canvas.debug)
554 qDebug("PatchCanvas::joinGroup(%i)", group_id);
555
556 CanvasBox* item = 0;
557 CanvasBox* s_item = 0;
558 QString group_name;
559 Icon group_icon = ICON_APPLICATION;
560 QList<port_dict_t> ports_data;
561 QList<connection_dict_t> conns_data;
562
563 // Step 1 - Store all Item data
564 foreach (const group_dict_t& group, canvas.group_list)
565 {
566 if (group.group_id == group_id)
567 {
568 if (group.split == false)
569 {
570 qCritical("PatchCanvas::joinGroup(%i) - group is not splitted", group_id);
571 return;
572 }
573
574 item = group.widgets[0];
575 s_item = group.widgets[1];
576 group_name = group.group_name;
577 group_icon = group.icon;
578 break;
579 }
580 }
581
582 if (!item || !s_item)
583 {
584 qCritical("PatchCanvas::joinGroup(%i) - Unable to find groups to join", group_id);
585 return;
586 }
587
588 QList<int> port_list_ids = QList<int>(item->getPortList());
589 QList<int> port_list_idss = s_item->getPortList();
590
591 foreach (const int& port_id, port_list_idss)
592 {
593 if (port_list_ids.contains(port_id) == false)
594 port_list_ids.append(port_id);
595 }
596
597 foreach (const port_dict_t& port, canvas.port_list)
598 {
599 if (port_list_ids.contains(port.port_id))
600 {
601 port_dict_t port_dict;
602 port_dict.group_id = port.group_id;
603 port_dict.port_id = port.port_id;
604 port_dict.port_name = port.port_name;
605 port_dict.port_mode = port.port_mode;
606 port_dict.port_type = port.port_type;
607 port_dict.widget = 0;
608 ports_data.append(port_dict);
609 }
610 }
611
612 foreach (const connection_dict_t& connection, canvas.connection_list)
613 {
614 if (port_list_ids.contains(connection.port_out_id) || port_list_ids.contains(connection.port_in_id))
615 {
616 connection_dict_t connection_dict;
617 connection_dict.connection_id = connection.connection_id;
618 connection_dict.port_in_id = connection.port_in_id;
619 connection_dict.port_out_id = connection.port_out_id;
620 connection_dict.widget = 0;
621 conns_data.append(connection_dict);
622 }
623 }
624
625 // Step 2 - Remove Item and Children
626 foreach (const connection_dict_t& conn, conns_data)
627 disconnectPorts(conn.connection_id);
628
629 foreach (const int& port_id, port_list_ids)
630 removePort(port_id);
631
632 removeGroup(group_id);
633
634 // Step 3 - Re-create Item, now together
635 addGroup(group_id, group_name, SPLIT_NO, group_icon);
636
637 foreach (const port_dict_t& port, ports_data)
638 addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type);
639
640 foreach (const connection_dict_t& conn, conns_data)
641 connectPorts(conn.connection_id, conn.port_out_id, conn.port_in_id);
642
643 QTimer::singleShot(0, canvas.scene, SLOT(update()));
644 }
645
646 QPointF getGroupPos(int group_id, PortMode port_mode)
647 {
648 if (canvas.debug)
649 qDebug("PatchCanvas::getGroupPos(%i, %s)", group_id, port_mode2str(port_mode));
650
651 foreach (const group_dict_t& group, canvas.group_list)
652 {
653 if (group.group_id == group_id)
654 {
655 if (group.split)
656 {
657 if (port_mode == PORT_MODE_OUTPUT)
658 return group.widgets[0]->pos();
659 else if (port_mode == PORT_MODE_INPUT)
660 return group.widgets[1]->pos();
661 else
662 return QPointF(0, 0);
663 }
664 else
665 return group.widgets[0]->pos();
666 }
667 }
668
669 qCritical("PatchCanvas::getGroupPos(%i, %s) - unable to find group", group_id, port_mode2str(port_mode));
670 return QPointF(0,0);
671 }
672
673 void setGroupPos(int group_id, int group_pos_x, int group_pos_y)
674 {
675 setGroupPos(group_id, group_pos_x, group_pos_y, group_pos_x, group_pos_y);
676 }
677
678 void setGroupPos(int group_id, int group_pos_x, int group_pos_y, int group_pos_xs, int group_pos_ys)
679 {
680 if (canvas.debug)
681 qDebug("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i)", group_id, group_pos_x, group_pos_y, group_pos_xs, group_pos_ys);
682
683 foreach (const group_dict_t& group, canvas.group_list)
684 {
685 if (group.group_id == group_id)
686 {
687 group.widgets[0]->setPos(group_pos_x, group_pos_y);
688
689 if (group.split && group.widgets[1])
690 {
691 group.widgets[1]->setPos(group_pos_xs, group_pos_ys);
692 }
693
694 QTimer::singleShot(0, canvas.scene, SLOT(update()));
695 return;
696 }
697 }
698
699 qCritical("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i) - unable to find group to reposition", group_id, group_pos_x, group_pos_y, group_pos_xs, group_pos_ys);
700 }
701
702 void setGroupIcon(int group_id, Icon icon)
703 {
704 if (canvas.debug)
705 qDebug("PatchCanvas::setGroupIcon(%i, %s)", group_id, icon2str(icon));
706
707 foreach2 (group_dict_t& group, canvas.group_list)
708 if (group.group_id == group_id)
709 {
710 group.icon = icon;
711 group.widgets[0]->setIcon(icon);
712
713 if (group.split && group.widgets[1])
714 group.widgets[1]->setIcon(icon);
715
716 QTimer::singleShot(0, canvas.scene, SLOT(update()));
717 return;
718 }
719 }
720
721 qCritical("PatchCanvas::setGroupIcon(%i, %s) - unable to find group to change icon", group_id, icon2str(icon));
722 }
723
724 void addPort(int group_id, int port_id, QString port_name, PortMode port_mode, PortType port_type)
725 {
726 if (canvas.debug)
727 qDebug("PatchCanvas::addPort(%i, %i, %s, %s, %s)", group_id, port_id, port_name.toUtf8().constData(), port_mode2str(port_mode), port_type2str(port_type));
728
729 foreach (const port_dict_t& port, canvas.port_list)
730 {
731 if (port.group_id == group_id and port.port_id == port_id)
732 {
733 qWarning("PatchCanvas::addPort(%i, %i, %s, %s, %s) - port already exists" , group_id, port_id, port_name.toUtf8().constData(), port_mode2str(port_mode), port_type2str(port_type));
734 return;
735 }
736 }
737
738 CanvasBox* box_widget = 0;
739 CanvasPort* port_widget = 0;
740
741 foreach (const group_dict_t& group, canvas.group_list)
742 {
743 if (group.group_id == group_id)
744 {
745 int n;
746 if (group.split && group.widgets[0]->getSplittedMode() != port_mode && group.widgets[1])
747 n = 1;
748 else
749 n = 0;
750 box_widget = group.widgets[n];
751 port_widget = box_widget->addPortFromGroup(port_id, port_name, port_mode, port_type);
752 break;
753 }
754 }
755
756 if (!box_widget || !port_widget)
757 {
758 qCritical("PatchCanvas::addPort(%i, %i, %s, %s, %s) - unable to find parent group", group_id, port_id, port_name.toUtf8().constData(), port_mode2str(port_mode), port_type2str(port_type));
759 return;
760 }
761
762 if (options.eyecandy == EYECANDY_FULL)
763 CanvasItemFX(port_widget, true);
764
765 port_dict_t port_dict;
766 port_dict.group_id = group_id;
767 port_dict.port_id = port_id;
768 port_dict.port_name = port_name;
769 port_dict.port_mode = port_mode;
770 port_dict.port_type = port_type;
771 port_dict.widget = port_widget;
772 canvas.port_list.append(port_dict);
773
774 box_widget->updatePositions();
775
776 QTimer::singleShot(0, canvas.scene, SLOT(update()));
777 }
778
779 void removePort(int port_id)
780 {
781 if (canvas.debug)
782 qDebug("PatchCanvas::removePort(%i)", port_id);
783
784 foreach2 (const port_dict_t& port, canvas.port_list)
785 if (port.port_id == port_id)
786 {
787 CanvasPort* item = port.widget;
788 ((CanvasBox*)item->parentItem())->removePortFromGroup(port_id);
789 canvas.scene->removeItem(item);
790 delete item;
791
792 canvas.port_list.takeAt(i);
793
794 QTimer::singleShot(0, canvas.scene, SLOT(update()));
795 return;
796 }
797 }
798
799 qCritical("PatchCanvas::removePort(%i) - unable to find port to remove", port_id);
800 }
801
802 void renamePort(int port_id, QString new_port_name)
803 {
804 if (canvas.debug)
805 qDebug("PatchCanvas::renamePort(%i, %s)", port_id, new_port_name.toUtf8().constData());
806
807 foreach2 (port_dict_t& port, canvas.port_list)
808 if (port.port_id == port_id)
809 {
810 port.port_name = new_port_name;
811 port.widget->setPortName(new_port_name);
812 ((CanvasBox*)port.widget->parentItem())->updatePositions();
813
814 QTimer::singleShot(0, canvas.scene, SLOT(update()));
815 return;
816 }
817 }
818
819 qCritical("PatchCanvas::renamePort(%i, %s) - unable to find port to rename", port_id, new_port_name.toUtf8().constData());
820 }
821
822 void connectPorts(int connection_id, int port_out_id, int port_in_id)
823 {
824 if (canvas.debug)
825 qDebug("PatchCanvas::connectPorts(%i, %i, %i)", connection_id, port_out_id, port_in_id);
826
827 CanvasPort* port_out = 0;
828 CanvasPort* port_in = 0;
829 CanvasBox* port_out_parent = 0;
830 CanvasBox* port_in_parent = 0;
831
832 foreach (const port_dict_t& port, canvas.port_list)
833 {
834 if (port.port_id == port_out_id)
835 {
836 port_out = port.widget;
837 port_out_parent = (CanvasBox*)port_out->parentItem();
838 }
839 else if (port.port_id == port_in_id)
840 {
841 port_in = port.widget;
842 port_in_parent = (CanvasBox*)port_in->parentItem();
843 }
844 }
845
846 if (!port_out || !port_in)
847 {
848 qCritical("PatchCanvas::connectPorts(%i, %i, %i) - Unable to find ports to connect", connection_id, port_out_id, port_in_id);
849 return;
850 }
851
852 connection_dict_t connection_dict;
853 connection_dict.connection_id = connection_id;
854 connection_dict.port_out_id = port_out_id;
855 connection_dict.port_in_id = port_in_id;
856
857 if (options.use_bezier_lines)
858 connection_dict.widget = new CanvasBezierLine(port_out, port_in, 0);
859 else
860 connection_dict.widget = new CanvasLine(port_out, port_in, 0);
861
862 port_out_parent->addLineFromGroup(connection_dict.widget, connection_id);
863 port_in_parent->addLineFromGroup(connection_dict.widget, connection_id);
864
865 canvas.last_z_value += 1;
866 port_out_parent->setZValue(canvas.last_z_value);
867 port_in_parent->setZValue(canvas.last_z_value);
868
869 canvas.last_z_value += 1;
870 connection_dict.widget->setZValue(canvas.last_z_value);
871
872 canvas.connection_list.append(connection_dict);
873
874 if (options.eyecandy == EYECANDY_FULL)
875 {
876 QGraphicsItem* item = (options.use_bezier_lines) ? (QGraphicsItem*)(CanvasBezierLine*)connection_dict.widget : (QGraphicsItem*)(CanvasLine*)connection_dict.widget;
877 CanvasItemFX(item, true);
878 }
879
880 QTimer::singleShot(0, canvas.scene, SLOT(update()));
881 }
882
883 void disconnectPorts(int connection_id)
884 {
885 if (canvas.debug)
886 qDebug("PatchCanvas::disconnectPorts(%i)", connection_id);
887
888 int port_1_id, port_2_id;
889 AbstractCanvasLine* line = 0;
890 QGraphicsItem* item1 = 0;
891 QGraphicsItem* item2 = 0;
892
893 foreach2 (const connection_dict_t& connection, canvas.connection_list)
894 if (connection.connection_id == connection_id)
895 {
896 port_1_id = connection.port_out_id;
897 port_2_id = connection.port_in_id;
898 line = connection.widget;
899 canvas.connection_list.takeAt(i);
900 break;
901 }
902 }
903
904 if (!line)
905 {
906 qCritical("PatchCanvas::disconnectPorts(%i) - unable to find connection ports", connection_id);
907 return;
908 }
909
910 foreach (const port_dict_t& port, canvas.port_list)
911 {
912 if (port.port_id == port_1_id)
913 {
914 item1 = port.widget;
915 break;
916 }
917 }
918
919 if (!item1)
920 {
921 qCritical("PatchCanvas::disconnectPorts(%i) - unable to find output port", connection_id);
922 return;
923 }
924
925 foreach (const port_dict_t& port, canvas.port_list)
926 {
927 if (port.port_id == port_2_id)
928 {
929 item2 = port.widget;
930 break;
931 }
932 }
933
934 if (!item2)
935 {
936 qCritical("PatchCanvas::disconnectPorts(%i) - unable to find input port", connection_id);
937 return;
938 }
939
940 ((CanvasBox*)item1->parentItem())->removeLineFromGroup(connection_id);
941 ((CanvasBox*)item2->parentItem())->removeLineFromGroup(connection_id);
942
943 if (options.eyecandy == EYECANDY_FULL)
944 {
945 QGraphicsItem* item = (options.use_bezier_lines) ? (QGraphicsItem*)(CanvasBezierLine*)line : (QGraphicsItem*)(CanvasLine*)line;
946 CanvasItemFX(item, false, true);
947 }
948 else
949 line->deleteFromScene();
950
951 QTimer::singleShot(0, canvas.scene, SLOT(update()));
952 }
953
954 void arrange()
955 {
956 if (canvas.debug)
957 qDebug("PatchCanvas::Arrange()");
958 }
959
960 void updateZValues()
961 {
962 if (canvas.debug)
963 qDebug("PatchCanvas::updateZValues()");
964
965
966 foreach (const group_dict_t& group, canvas.group_list)
967 {
968 group.widgets[0]->resetLinesZValue();
969
970 if (group.split and group.widgets[1])
971 group.widgets[1]->resetLinesZValue();
972 }
973 }
974
975 /* Extra Internal functions */
976
977 QString CanvasGetGroupName(int group_id)
978 {
979 if (canvas.debug)
980 qDebug("PatchCanvas::CanvasGetGroupName(%i)", group_id);
981
982 foreach (const group_dict_t& group, canvas.group_list)
983 {
984 if (group.group_id == group_id)
985 return group.group_name;
986 }
987
988 qCritical("PatchCanvas::CanvasGetGroupName(%i) - unable to find group", group_id);
989 return "";
990 }
991
992 int CanvasGetGroupPortCount(int group_id)
993 {
994 if (canvas.debug)
995 qDebug("PatchCanvas::CanvasGetGroupPortCount(%i)", group_id);
996
997 int port_count = 0;
998 foreach (const port_dict_t& port, canvas.port_list)
999 {
1000 if (port.group_id == group_id)
1001 port_count += 1;
1002 }
1003
1004 return port_count;
1005 }
1006
1007 QPointF CanvasGetNewGroupPos(bool horizontal)
1008 {
1009 if (canvas.debug)
1010 qDebug("PatchCanvas::CanvasGetNewGroupPos(%s)", bool2str(horizontal));
1011
1012 QPointF new_pos(canvas.initial_pos.x(), canvas.initial_pos.y());
1013 QList<QGraphicsItem*> items = canvas.scene->items();
1014
1015 bool break_loop = false;
1016 while (break_loop == false)
1017 {
1018 bool break_for = false;
1019 for (int i=0; i < items.count(); i++)
1020 {
1021 QGraphicsItem* item = items[i];
1022 if (item && item->type() == CanvasBoxType)
1023 {
1024 if (item->sceneBoundingRect().contains(new_pos))
1025 {
1026 if (horizontal)
1027 new_pos += QPointF(item->boundingRect().width()+15, 0);
1028 else
1029 new_pos += QPointF(0, item->boundingRect().height()+15);
1030 break;
1031 }
1032 }
1033 if (i >= items.count()-1 && break_for == false)
1034 break_loop = true;
1035 }
1036 }
1037
1038 return new_pos;
1039 }
1040
1041 QString CanvasGetFullPortName(int port_id)
1042 {
1043 if (canvas.debug)
1044 qDebug("PatchCanvas::CanvasGetFullPortName(%i)", port_id);
1045
1046 foreach (const port_dict_t& port, canvas.port_list)
1047 {
1048 if (port.port_id == port_id)
1049 {
1050 int group_id = port.group_id;
1051 foreach (const group_dict_t& group, canvas.group_list)
1052 {
1053 if (group.group_id == group_id)
1054 return group.group_name + ":" + port.port_name;
1055 }
1056 break;
1057 }
1058 }
1059
1060 qCritical("PatchCanvas::CanvasGetFullPortName(%i) - unable to find port", port_id);
1061 return "";
1062 }
1063
1064 QList<int> CanvasGetPortConnectionList(int port_id)
1065 {
1066 if (canvas.debug)
1067 qDebug("PatchCanvas::CanvasGetPortConnectionList(%i)", port_id);
1068
1069 QList<int> port_con_list;
1070
1071 foreach (const connection_dict_t& connection, canvas.connection_list)
1072 {
1073 if (connection.port_out_id == port_id || connection.port_in_id == port_id)
1074 port_con_list.append(connection.connection_id);
1075 }
1076
1077 return port_con_list;
1078 }
1079
1080 int CanvasGetConnectedPort(int connection_id, int port_id)
1081 {
1082 if (canvas.debug)
1083 qDebug("PatchCanvas::CanvasGetConnectedPort(%i, %i)", connection_id, port_id);
1084
1085 foreach (const connection_dict_t& connection, canvas.connection_list)
1086 {
1087 if (connection.connection_id == connection_id)
1088 {
1089 if (connection.port_out_id == port_id)
1090 return connection.port_in_id;
1091 else
1092 return connection.port_out_id;
1093 }
1094 }
1095
1096 qCritical("PatchCanvas::CanvasGetConnectedPort(%i, %i) - unable to find connection", connection_id, port_id);
1097 return 0;
1098 }
1099
1100 void CanvasRemoveAnimation(CanvasFadeAnimation* f_animation)
1101 {
1102 if (canvas.debug)
1103 qDebug("PatchCanvas::CanvasRemoveAnimation(%p)", f_animation);
1104
1105 foreach2 (const animation_dict_t& animation, canvas.animation_list)
1106 if (animation.animation == f_animation)
1107 {
1108 delete animation.animation;
1109 canvas.animation_list.takeAt(i);
1110 break;
1111 }
1112 }
1113 }
1114
1115 void CanvasPostponedGroups()
1116 {
1117 if (canvas.debug)
1118 qDebug("PatchCanvas::CanvasPostponedGroups()");
1119 }
1120
1121 void CanvasCallback(CallbackAction action, int value1, int value2, QString value_str)
1122 {
1123 if (canvas.debug)
1124 qDebug("PatchCanvas::CanvasCallback(%i, %i, %i, %s)", action, value1, value2, value_str.toStdString().data());
1125
1126 canvas.callback(action, value1, value2, value_str);
1127 }
1128
1129 void CanvasItemFX(QGraphicsItem* item, bool show, bool destroy)
1130 {
1131 if (canvas.debug)
1132 qDebug("PatchCanvas::CanvasItemFX(%p, %s, %s)", item, bool2str(show), bool2str(destroy));
1133
1134 // Check if item already has an animationItemFX
1135 foreach2 (const animation_dict_t& animation, canvas.animation_list)
1136 if (animation.item == item)
1137 {
1138 if (animation.animation)
1139 {
1140 animation.animation->stop();
1141 delete animation.animation;
1142 }
1143 canvas.animation_list.takeAt(i);
1144 break;
1145 }
1146 }
1147
1148 CanvasFadeAnimation* animation = new CanvasFadeAnimation(item, show);
1149 animation->setDuration(show ? 750 : 500);
1150
1151 animation_dict_t animation_dict;
1152 animation_dict.animation = animation;
1153 animation_dict.item = item;
1154 canvas.animation_list.append(animation_dict);
1155
1156 if (show)
1157 {
1158 QObject::connect(animation, SIGNAL(finished()), canvas.qobject, SLOT(AnimationIdle()));
1159 }
1160 else
1161 {
1162 if (destroy)
1163 QObject::connect(animation, SIGNAL(finished()), canvas.qobject, SLOT(AnimationDestroy()));
1164 else
1165 QObject::connect(animation, SIGNAL(finished()), canvas.qobject, SLOT(AnimationHide()));
1166 }
1167
1168 animation->start();
1169 }
1170
1171 void CanvasRemoveItemFX(QGraphicsItem* item)
1172 {
1173 if (canvas.debug)
1174 qDebug("PatchCanvas::CanvasRemoveItemFX(%p)", item);
1175
1176 switch (item->type())
1177 {
1178 case CanvasBoxType:
1179 {
1180 CanvasBox* box = (CanvasBox*)item;
1181 box->removeIconFromScene();
1182 canvas.scene->removeItem(box);
1183 delete box;
1184 }
1185 case CanvasPortType:
1186 {
1187 CanvasPort* port = (CanvasPort*)item;
1188 canvas.scene->removeItem(port);
1189 delete port;
1190 }
1191 case CanvasLineType:
1192 case CanvasBezierLineType:
1193 {
1194 AbstractCanvasLine* line = (AbstractCanvasLine*)item;
1195 line->deleteFromScene();
1196 }
1197 default:
1198 break;
1199 }
1200 }
1201
1202 END_NAMESPACE_PATCHCANVAS
1203