Collection of tools useful for audio production
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1169 lines
34KB

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