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.

448 lines
13KB

  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. #include "canvasport.h"
  18. #include <QtCore/QTimer>
  19. #include <QtGui/QCursor>
  20. #include <QtGui/QGraphicsSceneContextMenuEvent>
  21. #include <QtGui/QGraphicsSceneMouseEvent>
  22. #include <QtGui/QInputDialog>
  23. #include <QtGui/QMenu>
  24. #include <QtGui/QPainter>
  25. #include "canvaslinemov.h"
  26. #include "canvasbezierlinemov.h"
  27. #include "canvasbox.h"
  28. START_NAMESPACE_PATCHCANVAS
  29. CanvasPort::CanvasPort(int port_id, QString port_name, PortMode port_mode, PortType port_type, QGraphicsItem* parent) :
  30. QGraphicsItem(parent, canvas.scene)
  31. {
  32. // Save Variables, useful for later
  33. m_port_id = port_id;
  34. m_port_mode = port_mode;
  35. m_port_type = port_type;
  36. m_port_name = port_name;
  37. // Base Variables
  38. m_port_width = 15;
  39. m_port_height = 15;
  40. m_port_font = QFont(canvas.theme->port_font_name, canvas.theme->port_font_size, canvas.theme->port_font_state);
  41. m_line_mov = 0;
  42. m_hover_item = 0;
  43. m_last_selected_state = false;
  44. m_mouse_down = false;
  45. m_cursor_moving = false;
  46. setFlags(QGraphicsItem::ItemIsSelectable);
  47. }
  48. int CanvasPort::getPortId()
  49. {
  50. return m_port_id;
  51. }
  52. PortMode CanvasPort::getPortMode()
  53. {
  54. return m_port_mode;
  55. }
  56. PortType CanvasPort::getPortType()
  57. {
  58. return m_port_type;
  59. }
  60. QString CanvasPort::getPortName()
  61. {
  62. return m_port_name;
  63. }
  64. QString CanvasPort::getFullPortName()
  65. {
  66. return ((CanvasBox*)parentItem())->getGroupName()+":"+m_port_name;
  67. }
  68. int CanvasPort::getPortWidth()
  69. {
  70. return m_port_width;
  71. }
  72. int CanvasPort::getPortHeight()
  73. {
  74. return m_port_height;
  75. }
  76. void CanvasPort::setPortMode(PortMode port_mode)
  77. {
  78. m_port_mode = port_mode;
  79. update();
  80. }
  81. void CanvasPort::setPortType(PortType port_type)
  82. {
  83. m_port_type = port_type;
  84. update();
  85. }
  86. void CanvasPort::setPortName(QString port_name)
  87. {
  88. if (QFontMetrics(m_port_font).width(port_name) < QFontMetrics(m_port_font).width(m_port_name))
  89. QTimer::singleShot(0, canvas.scene, SLOT(update()));
  90. m_port_name = port_name;
  91. update();
  92. }
  93. void CanvasPort::setPortWidth(int port_width)
  94. {
  95. if (port_width < m_port_width)
  96. QTimer::singleShot(0, canvas.scene, SLOT(update()));
  97. m_port_width = port_width;
  98. update();
  99. }
  100. int CanvasPort::type() const
  101. {
  102. return CanvasPortType;
  103. }
  104. void CanvasPort::mousePressEvent(QGraphicsSceneMouseEvent* event)
  105. {
  106. m_hover_item = 0;
  107. m_mouse_down = (event->button() == Qt::LeftButton);
  108. m_cursor_moving = false;
  109. QGraphicsItem::mousePressEvent(event);
  110. }
  111. void CanvasPort::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
  112. {
  113. if (m_mouse_down)
  114. {
  115. if (m_cursor_moving == false)
  116. {
  117. setCursor(QCursor(Qt::CrossCursor));
  118. m_cursor_moving = true;
  119. foreach (const connection_dict_t& connection, canvas.connection_list)
  120. {
  121. if (connection.port_out_id == m_port_id || connection.port_in_id == m_port_id)
  122. connection.widget->setLocked(true);
  123. }
  124. }
  125. if (! m_line_mov)
  126. {
  127. if (options.use_bezier_lines)
  128. m_line_mov = new CanvasBezierLineMov(m_port_mode, m_port_type, this);
  129. else
  130. m_line_mov = new CanvasLineMov(m_port_mode, m_port_type, this);
  131. canvas.last_z_value += 1;
  132. m_line_mov->setZValue(canvas.last_z_value);
  133. canvas.last_z_value += 1;
  134. parentItem()->setZValue(canvas.last_z_value);
  135. }
  136. CanvasPort* item = 0;
  137. QList<QGraphicsItem*> items = canvas.scene->items(event->scenePos(), Qt::ContainsItemShape, Qt::AscendingOrder);
  138. for (int i=0; i < items.count(); i++)
  139. {
  140. if (items[i]->type() == CanvasPortType)
  141. {
  142. if (items[i] != this)
  143. {
  144. if (! item)
  145. item = (CanvasPort*)items[i];
  146. else if (items[i]->parentItem()->zValue() > item->parentItem()->zValue())
  147. item = (CanvasPort*)items[i];
  148. }
  149. }
  150. }
  151. if (m_hover_item and m_hover_item != item)
  152. m_hover_item->setSelected(false);
  153. if (item)
  154. {
  155. bool a2j_connection = (item->getPortType() == PORT_TYPE_MIDI_JACK && m_port_type == PORT_TYPE_MIDI_A2J) || (item->getPortType() == PORT_TYPE_MIDI_A2J && m_port_type == PORT_TYPE_MIDI_JACK);
  156. if (item->getPortMode() != m_port_mode && (item->getPortType() == m_port_type || a2j_connection))
  157. {
  158. item->setSelected(true);
  159. m_hover_item = item;
  160. }
  161. else
  162. m_hover_item = 0;
  163. }
  164. else
  165. m_hover_item = 0;
  166. m_line_mov->updateLinePos(event->scenePos());
  167. return event->accept();
  168. }
  169. QGraphicsItem::mouseMoveEvent(event);
  170. }
  171. void CanvasPort::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
  172. {
  173. if (m_mouse_down)
  174. {
  175. if (m_line_mov)
  176. {
  177. m_line_mov->deleteFromScene();
  178. m_line_mov = 0;
  179. }
  180. foreach (const connection_dict_t& connection, canvas.connection_list)
  181. {
  182. if (connection.port_out_id == m_port_id || connection.port_in_id == m_port_id)
  183. connection.widget->setLocked(false);
  184. }
  185. if (m_hover_item)
  186. {
  187. bool check = false;
  188. foreach (const connection_dict_t& connection, canvas.connection_list)
  189. {
  190. if ( (connection.port_out_id == m_port_id && connection.port_in_id == m_hover_item->getPortId()) ||
  191. (connection.port_out_id == m_hover_item->getPortId() && connection.port_in_id == m_port_id) )
  192. {
  193. canvas.callback(ACTION_PORTS_DISCONNECT, connection.connection_id, 0, "");
  194. check = true;
  195. break;
  196. }
  197. }
  198. if (check == false)
  199. {
  200. if (m_port_mode == PORT_MODE_OUTPUT)
  201. canvas.callback(ACTION_PORTS_CONNECT, m_port_id, m_hover_item->getPortId(), "");
  202. else
  203. canvas.callback(ACTION_PORTS_CONNECT, m_hover_item->getPortId(), m_port_id, "");
  204. }
  205. canvas.scene->clearSelection();
  206. }
  207. }
  208. if (m_cursor_moving)
  209. setCursor(QCursor(Qt::ArrowCursor));
  210. m_hover_item = 0;
  211. m_mouse_down = false;
  212. m_cursor_moving = false;
  213. QGraphicsItem::mouseReleaseEvent(event);
  214. }
  215. void CanvasPort::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
  216. {
  217. canvas.scene->clearSelection();
  218. setSelected(true);
  219. QMenu menu;
  220. QMenu discMenu("Disconnect", &menu);
  221. QList<int> port_con_list = CanvasGetPortConnectionList(m_port_id);
  222. if (port_con_list.count() > 0)
  223. {
  224. foreach (int port_id, port_con_list)
  225. {
  226. int port_con_id = CanvasGetConnectedPort(port_id, m_port_id);
  227. QAction* act_x_disc = discMenu.addAction(CanvasGetFullPortName(port_con_id));
  228. act_x_disc->setData(port_id);
  229. QObject::connect(act_x_disc, SIGNAL(triggered()), canvas.qobject, SLOT(PortContextMenuDisconnect()));
  230. }
  231. }
  232. else
  233. {
  234. QAction* act_x_disc = discMenu.addAction("No connections");
  235. act_x_disc->setEnabled(false);
  236. }
  237. menu.addMenu(&discMenu);
  238. QAction* act_x_disc_all = menu.addAction("Disconnect &All");
  239. QAction* act_x_sep_1 = menu.addSeparator();
  240. QAction* act_x_info = menu.addAction("Get &Info");
  241. QAction* act_x_rename = menu.addAction("&Rename");
  242. if (features.port_info == false)
  243. act_x_info->setVisible(false);
  244. if (features.port_rename == false)
  245. act_x_rename->setVisible(false);
  246. if (features.port_info == false && features.port_rename == false)
  247. act_x_sep_1->setVisible(false);
  248. QAction* act_selected = menu.exec(event->screenPos());
  249. if (act_selected == act_x_disc_all)
  250. {
  251. foreach (int port_id, port_con_list)
  252. canvas.callback(ACTION_PORTS_DISCONNECT, port_id, 0, "");
  253. }
  254. else if (act_selected == act_x_info)
  255. {
  256. canvas.callback(ACTION_PORT_INFO, m_port_id, 0, "");
  257. }
  258. else if (act_selected == act_x_rename)
  259. {
  260. bool ok_check;
  261. QString new_name = QInputDialog::getText(0, "Rename Port", "New name:", QLineEdit::Normal, m_port_name, &ok_check);
  262. if (ok_check and new_name.isEmpty() == false)
  263. {
  264. canvas.callback(ACTION_PORT_RENAME, m_port_id, 0, new_name);
  265. }
  266. }
  267. event->accept();
  268. }
  269. QRectF CanvasPort::boundingRect() const
  270. {
  271. return QRectF(0, 0, m_port_width+12, m_port_height);
  272. }
  273. void CanvasPort::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
  274. {
  275. painter->setRenderHint(QPainter::Antialiasing, (options.antialiasing == ANTIALIASING_FULL));
  276. QPointF text_pos;
  277. int poly_locx[5] = { 0 };
  278. if (m_port_mode == PORT_MODE_INPUT)
  279. {
  280. text_pos = QPointF(3, 12);
  281. if (canvas.theme->port_mode == Theme::THEME_PORT_POLYGON)
  282. {
  283. poly_locx[0] = 0;
  284. poly_locx[1] = m_port_width+5;
  285. poly_locx[2] = m_port_width+12;
  286. poly_locx[3] = m_port_width+5;
  287. poly_locx[4] = 0;
  288. }
  289. else if (canvas.theme->port_mode == Theme::THEME_PORT_SQUARE)
  290. {
  291. poly_locx[0] = 0;
  292. poly_locx[1] = m_port_width+5;
  293. poly_locx[2] = m_port_width+5;
  294. poly_locx[3] = m_port_width+5;
  295. poly_locx[4] = 0;
  296. }
  297. else
  298. {
  299. qCritical("PatchCanvas::CanvasPort->paint() - invalid theme port mode '%i'", canvas.theme->port_mode);
  300. return;
  301. }
  302. }
  303. else if (m_port_mode == PORT_MODE_OUTPUT)
  304. {
  305. text_pos = QPointF(9, 12);
  306. if (canvas.theme->port_mode == Theme::THEME_PORT_POLYGON)
  307. {
  308. poly_locx[0] = m_port_width+12;
  309. poly_locx[1] = 7;
  310. poly_locx[2] = 0;
  311. poly_locx[3] = 7;
  312. poly_locx[4] = m_port_width+12;
  313. }
  314. else if (canvas.theme->port_mode == Theme::THEME_PORT_SQUARE)
  315. {
  316. poly_locx[0] = m_port_width+12;
  317. poly_locx[1] = 5;
  318. poly_locx[2] = 5;
  319. poly_locx[3] = 5;
  320. poly_locx[4] = m_port_width+12;
  321. }
  322. else
  323. {
  324. qCritical("PatchCanvas::CanvasPort->paint() - invalid theme port mode '%i'", canvas.theme->port_mode);
  325. return;
  326. }
  327. }
  328. else
  329. {
  330. qCritical("PatchCanvas::CanvasPort->paint() - invalid port mode '%s'", port_mode2str(m_port_mode));
  331. return;
  332. }
  333. QColor poly_color;
  334. QPen poly_pen;
  335. if (m_port_type == PORT_TYPE_AUDIO_JACK)
  336. {
  337. poly_color = isSelected() ? canvas.theme->port_audio_jack_bg_sel : canvas.theme->port_audio_jack_bg;
  338. poly_pen = isSelected() ? canvas.theme->port_audio_jack_pen_sel : canvas.theme->port_audio_jack_pen;
  339. }
  340. else if (m_port_type == PORT_TYPE_MIDI_JACK)
  341. {
  342. poly_color = isSelected() ? canvas.theme->port_midi_jack_bg_sel : canvas.theme->port_midi_jack_bg;
  343. poly_pen = isSelected() ? canvas.theme->port_midi_jack_pen_sel : canvas.theme->port_midi_jack_pen;
  344. }
  345. else if (m_port_type == PORT_TYPE_MIDI_A2J)
  346. {
  347. poly_color = isSelected() ? canvas.theme->port_midi_a2j_bg_sel : canvas.theme->port_midi_a2j_bg;
  348. poly_pen = isSelected() ? canvas.theme->port_midi_a2j_pen_sel : canvas.theme->port_midi_a2j_pen;
  349. }
  350. else if (m_port_type == PORT_TYPE_MIDI_ALSA)
  351. {
  352. poly_color = isSelected() ? canvas.theme->port_midi_alsa_bg_sel : canvas.theme->port_midi_alsa_bg;
  353. poly_pen = isSelected() ? canvas.theme->port_midi_alsa_pen_sel : canvas.theme->port_midi_alsa_pen;
  354. }
  355. else
  356. {
  357. qCritical("PatchCanvas::CanvasPort->paint() - invalid port type '%s'", port_type2str(m_port_type));
  358. return;
  359. }
  360. QPolygonF polygon;
  361. polygon += QPointF(poly_locx[0], 0);
  362. polygon += QPointF(poly_locx[1], 0);
  363. polygon += QPointF(poly_locx[2], 7.5);
  364. polygon += QPointF(poly_locx[3], 15);
  365. polygon += QPointF(poly_locx[4], 15);
  366. painter->setBrush(poly_color);
  367. painter->setPen(poly_pen);
  368. painter->drawPolygon(polygon);
  369. painter->setPen(canvas.theme->port_text);
  370. painter->setFont(m_port_font);
  371. painter->drawText(text_pos, m_port_name);
  372. if (isSelected() != m_last_selected_state)
  373. {
  374. foreach (const connection_dict_t& connection, canvas.connection_list)
  375. {
  376. if (connection.port_out_id == m_port_id || connection.port_in_id == m_port_id)
  377. connection.widget->setLineSelected(isSelected());
  378. }
  379. }
  380. m_last_selected_state = isSelected();
  381. }
  382. END_NAMESPACE_PATCHCANVAS