Audio plugin host https://kx.studio/carla
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.

932 lines
31KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # PatchBay Canvas engine using QGraphicsView/Scene
  4. # Copyright (C) 2010-2019 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the doc/GPL.txt file.
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. from PyQt5.QtCore import pyqtSlot, qCritical, qFatal, qWarning, QObject
  20. from PyQt5.QtCore import QPointF, QRectF, QSettings, QTimer
  21. # ------------------------------------------------------------------------------------------------------------
  22. # Imports (Custom)
  23. from . import (
  24. canvas,
  25. features,
  26. options,
  27. group_dict_t,
  28. port_dict_t,
  29. connection_dict_t,
  30. bool2str,
  31. icon2str,
  32. split2str,
  33. port_mode2str,
  34. port_type2str,
  35. CanvasIconType,
  36. CanvasRubberbandType,
  37. ACTION_PORTS_DISCONNECT,
  38. EYECANDY_FULL,
  39. ICON_APPLICATION,
  40. ICON_HARDWARE,
  41. ICON_LADISH_ROOM,
  42. PORT_MODE_INPUT,
  43. PORT_MODE_OUTPUT,
  44. SPLIT_YES,
  45. SPLIT_NO,
  46. SPLIT_UNDEF,
  47. MAX_PLUGIN_ID_ALLOWED,
  48. )
  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
  54. # FIXME
  55. from . import *
  56. from .scene import PatchScene
  57. # ------------------------------------------------------------------------------------------------------------
  58. class CanvasObject(QObject):
  59. def __init__(self, parent=None):
  60. QObject.__init__(self, parent)
  61. @pyqtSlot()
  62. def AnimationFinishedShow(self):
  63. animation = self.sender()
  64. if animation:
  65. animation.forceStop()
  66. canvas.animation_list.remove(animation)
  67. @pyqtSlot()
  68. def AnimationFinishedHide(self):
  69. animation = self.sender()
  70. if animation:
  71. animation.forceStop()
  72. canvas.animation_list.remove(animation)
  73. item = animation.item()
  74. if item:
  75. item.hide()
  76. @pyqtSlot()
  77. def AnimationFinishedDestroy(self):
  78. animation = self.sender()
  79. if animation:
  80. animation.forceStop()
  81. canvas.animation_list.remove(animation)
  82. item = animation.item()
  83. if item:
  84. CanvasRemoveItemFX(item)
  85. @pyqtSlot()
  86. def PortContextMenuConnect(self):
  87. try:
  88. sources, targets = self.sender().data()
  89. except:
  90. return
  91. for port_type in (PORT_TYPE_AUDIO_JACK, PORT_TYPE_MIDI_JACK, PORT_TYPE_MIDI_ALSA):
  92. source_ports = sources[port_type]
  93. target_ports = targets[port_type]
  94. source_ports_len = len(source_ports)
  95. target_ports_len = len(target_ports)
  96. if source_ports_len == 0 or target_ports_len == 0:
  97. continue
  98. for i in range(min(source_ports_len, target_ports_len)):
  99. data = "%i:%i:%i:%i" % (source_ports[i][0],
  100. source_ports[i][1],
  101. target_ports[i][0],
  102. target_ports[i][1])
  103. CanvasCallback(ACTION_PORTS_CONNECT, 0, 0, data)
  104. if source_ports_len == 1 and target_ports_len > 1:
  105. for i in range(1, target_ports_len):
  106. data = "%i:%i:%i:%i" % (source_ports[0][0],
  107. source_ports[0][1],
  108. target_ports[i][0],
  109. target_ports[i][1])
  110. CanvasCallback(ACTION_PORTS_CONNECT, 0, 0, data)
  111. @pyqtSlot()
  112. def PortContextMenuDisconnect(self):
  113. try:
  114. connectionId = int(self.sender().data())
  115. except:
  116. return
  117. CanvasCallback(ACTION_PORTS_DISCONNECT, connectionId, 0, "")
  118. # ------------------------------------------------------------------------------------------------------------
  119. def getStoredCanvasPosition(key, fallback_pos):
  120. try:
  121. return canvas.settings.value("CanvasPositions/" + key, fallback_pos, type=QPointF)
  122. except:
  123. return fallback_pos
  124. def getStoredCanvasSplit(group_name, fallback_split_mode):
  125. try:
  126. return canvas.settings.value("CanvasPositions/%s_SPLIT" % group_name, fallback_split_mode, type=int)
  127. except:
  128. return fallback_split_mode
  129. # ------------------------------------------------------------------------------------------------------------
  130. def init(appName, scene, callback, debug=False):
  131. if debug:
  132. print("PatchCanvas::init(\"%s\", %s, %s, %s)" % (appName, scene, callback, bool2str(debug)))
  133. if canvas.initiated:
  134. qCritical("PatchCanvas::init() - already initiated")
  135. return
  136. if not callback:
  137. qFatal("PatchCanvas::init() - fatal error: callback not set")
  138. return
  139. canvas.callback = callback
  140. canvas.debug = debug
  141. canvas.scene = scene
  142. canvas.last_z_value = 0
  143. canvas.last_connection_id = 0
  144. canvas.initial_pos = QPointF(0, 0)
  145. canvas.size_rect = QRectF()
  146. if not canvas.qobject:
  147. canvas.qobject = CanvasObject()
  148. if not canvas.settings:
  149. canvas.settings = QSettings("falkTX", appName)
  150. if canvas.theme:
  151. del canvas.theme
  152. canvas.theme = None
  153. for i in range(Theme.THEME_MAX):
  154. this_theme_name = getThemeName(i)
  155. if this_theme_name == options.theme_name:
  156. canvas.theme = Theme(i)
  157. break
  158. if not canvas.theme:
  159. canvas.theme = Theme(getDefaultTheme())
  160. canvas.scene.updateTheme()
  161. canvas.initiated = True
  162. def clear():
  163. if canvas.debug:
  164. print("PatchCanvas::clear()")
  165. group_list_ids = []
  166. port_list_ids = []
  167. connection_list_ids = []
  168. for group in canvas.group_list:
  169. group_list_ids.append(group.group_id)
  170. for port in canvas.port_list:
  171. port_list_ids.append((port.group_id, port.port_id))
  172. for connection in canvas.connection_list:
  173. connection_list_ids.append(connection.connection_id)
  174. for idx in connection_list_ids:
  175. disconnectPorts(idx)
  176. for group_id, port_id in port_list_ids:
  177. removePort(group_id, port_id)
  178. for idx in group_list_ids:
  179. removeGroup(idx)
  180. canvas.last_z_value = 0
  181. canvas.last_connection_id = 0
  182. canvas.group_list = []
  183. canvas.port_list = []
  184. canvas.connection_list = []
  185. canvas.scene.clearSelection()
  186. animatedItems = []
  187. for animation in canvas.animation_list:
  188. animatedItems.append(animation.item())
  189. for item in canvas.scene.items():
  190. if item.type() in (CanvasIconType, CanvasRubberbandType) or item in animatedItems:
  191. continue
  192. canvas.scene.removeItem(item)
  193. del item
  194. canvas.initiated = False
  195. QTimer.singleShot(0, canvas.scene.update)
  196. # ------------------------------------------------------------------------------------------------------------
  197. def setInitialPos(x, y):
  198. if canvas.debug:
  199. print("PatchCanvas::setInitialPos(%i, %i)" % (x, y))
  200. canvas.initial_pos.setX(x)
  201. canvas.initial_pos.setY(y)
  202. def setCanvasSize(x, y, width, height):
  203. if canvas.debug:
  204. print("PatchCanvas::setCanvasSize(%i, %i, %i, %i)" % (x, y, width, height))
  205. canvas.size_rect.setX(x)
  206. canvas.size_rect.setY(y)
  207. canvas.size_rect.setWidth(width)
  208. canvas.size_rect.setHeight(height)
  209. canvas.scene.updateLimits()
  210. canvas.scene.fixScaleFactor()
  211. def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):
  212. if canvas.debug:
  213. print("PatchCanvas::addGroup(%i, %s, %s, %s)" % (
  214. group_id, group_name.encode(), split2str(split), icon2str(icon)))
  215. for group in canvas.group_list:
  216. if group.group_id == group_id:
  217. qWarning("PatchCanvas::addGroup(%i, %s, %s, %s) - group already exists" % (
  218. group_id, group_name.encode(), split2str(split), icon2str(icon)))
  219. return
  220. if split == SPLIT_UNDEF:
  221. isHardware = bool(icon == ICON_HARDWARE)
  222. if features.handle_group_pos:
  223. split = getStoredCanvasSplit(group_name, SPLIT_YES if isHardware else split)
  224. elif isHardware:
  225. split = SPLIT_YES
  226. group_box = CanvasBox(group_id, group_name, icon)
  227. group_dict = group_dict_t()
  228. group_dict.group_id = group_id
  229. group_dict.group_name = group_name
  230. group_dict.split = bool(split == SPLIT_YES)
  231. group_dict.icon = icon
  232. group_dict.plugin_id = -1
  233. group_dict.plugin_ui = False
  234. group_dict.widgets = [group_box, None]
  235. if split == SPLIT_YES:
  236. group_box.setSplit(True, PORT_MODE_OUTPUT)
  237. if features.handle_group_pos:
  238. group_box.setPos(getStoredCanvasPosition(group_name + "_OUTPUT", CanvasGetNewGroupPos(False)))
  239. else:
  240. group_box.setPos(CanvasGetNewGroupPos(False))
  241. group_sbox = CanvasBox(group_id, group_name, icon)
  242. group_sbox.setSplit(True, PORT_MODE_INPUT)
  243. group_dict.widgets[1] = group_sbox
  244. if features.handle_group_pos:
  245. group_sbox.setPos(getStoredCanvasPosition(group_name + "_INPUT", CanvasGetNewGroupPos(True)))
  246. else:
  247. group_sbox.setPos(CanvasGetNewGroupPos(True))
  248. canvas.last_z_value += 1
  249. group_sbox.setZValue(canvas.last_z_value)
  250. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  251. CanvasItemFX(group_sbox, True, False)
  252. group_sbox.checkItemPos()
  253. else:
  254. group_box.setSplit(False)
  255. if features.handle_group_pos:
  256. group_box.setPos(getStoredCanvasPosition(group_name, CanvasGetNewGroupPos(False)))
  257. else:
  258. # Special ladish fake-split groups
  259. horizontal = bool(icon == ICON_HARDWARE or icon == ICON_LADISH_ROOM)
  260. group_box.setPos(CanvasGetNewGroupPos(horizontal))
  261. group_box.checkItemPos()
  262. canvas.last_z_value += 1
  263. group_box.setZValue(canvas.last_z_value)
  264. canvas.group_list.append(group_dict)
  265. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  266. CanvasItemFX(group_box, True, False)
  267. return
  268. QTimer.singleShot(0, canvas.scene.update)
  269. def removeGroup(group_id):
  270. if canvas.debug:
  271. print("PatchCanvas::removeGroup(%i)" % group_id)
  272. for group in canvas.group_list:
  273. if group.group_id == group_id:
  274. item = group.widgets[0]
  275. group_name = group.group_name
  276. if group.split:
  277. s_item = group.widgets[1]
  278. if features.handle_group_pos:
  279. canvas.settings.setValue("CanvasPositions/%s_OUTPUT" % group_name, item.pos())
  280. canvas.settings.setValue("CanvasPositions/%s_INPUT" % group_name, s_item.pos())
  281. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_YES)
  282. if options.eyecandy == EYECANDY_FULL:
  283. CanvasItemFX(s_item, False, True)
  284. else:
  285. s_item.removeIconFromScene()
  286. canvas.scene.removeItem(s_item)
  287. del s_item
  288. else:
  289. if features.handle_group_pos:
  290. canvas.settings.setValue("CanvasPositions/%s" % group_name, item.pos())
  291. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_NO)
  292. if options.eyecandy == EYECANDY_FULL:
  293. CanvasItemFX(item, False, True)
  294. else:
  295. item.removeIconFromScene()
  296. canvas.scene.removeItem(item)
  297. del item
  298. canvas.group_list.remove(group)
  299. QTimer.singleShot(0, canvas.scene.update)
  300. return
  301. qCritical("PatchCanvas::removeGroup(%i) - unable to find group to remove" % group_id)
  302. def renameGroup(group_id, new_group_name):
  303. if canvas.debug:
  304. print("PatchCanvas::renameGroup(%i, %s)" % (group_id, new_group_name.encode()))
  305. for group in canvas.group_list:
  306. if group.group_id == group_id:
  307. group.group_name = new_group_name
  308. group.widgets[0].setGroupName(new_group_name)
  309. if group.split and group.widgets[1]:
  310. group.widgets[1].setGroupName(new_group_name)
  311. QTimer.singleShot(0, canvas.scene.update)
  312. return
  313. qCritical("PatchCanvas::renameGroup(%i, %s) - unable to find group to rename" % (group_id, new_group_name.encode()))
  314. def splitGroup(group_id):
  315. if canvas.debug:
  316. print("PatchCanvas::splitGroup(%i)" % group_id)
  317. item = None
  318. group_name = ""
  319. group_icon = ICON_APPLICATION
  320. plugin_id = -1
  321. plugin_ui = False
  322. ports_data = []
  323. conns_data = []
  324. # Step 1 - Store all Item data
  325. for group in canvas.group_list:
  326. if group.group_id == group_id:
  327. if group.split:
  328. qCritical("PatchCanvas::splitGroup(%i) - group is already splitted" % group_id)
  329. return
  330. item = group.widgets[0]
  331. group_name = group.group_name
  332. group_icon = group.icon
  333. plugin_id = group.plugin_id
  334. plugin_ui = group.plugin_ui
  335. break
  336. if not item:
  337. qCritical("PatchCanvas::splitGroup(%i) - unable to find group to split" % group_id)
  338. return
  339. port_list_ids = list(item.getPortList())
  340. for port in canvas.port_list:
  341. if port.port_id in port_list_ids:
  342. port_dict = port_dict_t()
  343. port_dict.group_id = port.group_id
  344. port_dict.port_id = port.port_id
  345. port_dict.port_name = port.port_name
  346. port_dict.port_mode = port.port_mode
  347. port_dict.port_type = port.port_type
  348. port_dict.is_alternate = port.is_alternate
  349. port_dict.widget = None
  350. ports_data.append(port_dict)
  351. for connection in canvas.connection_list:
  352. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  353. connection_dict = connection_dict_t()
  354. connection_dict.connection_id = connection.connection_id
  355. connection_dict.group_in_id = connection.group_in_id
  356. connection_dict.port_in_id = connection.port_in_id
  357. connection_dict.group_out_id = connection.group_out_id
  358. connection_dict.port_out_id = connection.port_out_id
  359. connection_dict.widget = None
  360. conns_data.append(connection_dict)
  361. # Step 2 - Remove Item and Children
  362. for conn in conns_data:
  363. disconnectPorts(conn.connection_id)
  364. for port_id in port_list_ids:
  365. removePort(group_id, port_id)
  366. removeGroup(group_id)
  367. # Step 3 - Re-create Item, now splitted
  368. addGroup(group_id, group_name, SPLIT_YES, group_icon)
  369. if plugin_id >= 0:
  370. setGroupAsPlugin(group_id, plugin_id, plugin_ui)
  371. for port in ports_data:
  372. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
  373. for conn in conns_data:
  374. connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id)
  375. QTimer.singleShot(0, canvas.scene.update)
  376. def joinGroup(group_id):
  377. if canvas.debug:
  378. print("PatchCanvas::joinGroup(%i)" % group_id)
  379. item = None
  380. s_item = None
  381. group_name = ""
  382. group_icon = ICON_APPLICATION
  383. plugin_id = -1
  384. plugin_ui = False
  385. ports_data = []
  386. conns_data = []
  387. # Step 1 - Store all Item data
  388. for group in canvas.group_list:
  389. if group.group_id == group_id:
  390. if not group.split:
  391. qCritical("PatchCanvas::joinGroup(%i) - group is not splitted" % group_id)
  392. return
  393. item = group.widgets[0]
  394. s_item = group.widgets[1]
  395. group_name = group.group_name
  396. group_icon = group.icon
  397. plugin_id = group.plugin_id
  398. plugin_ui = group.plugin_ui
  399. break
  400. # FIXME
  401. if not (item and s_item):
  402. qCritical("PatchCanvas::joinGroup(%i) - unable to find groups to join" % group_id)
  403. return
  404. port_list_ids = list(item.getPortList())
  405. port_list_idss = s_item.getPortList()
  406. for port_id in port_list_idss:
  407. if port_id not in port_list_ids:
  408. port_list_ids.append(port_id)
  409. for port in canvas.port_list:
  410. if port.port_id in port_list_ids:
  411. port_dict = port_dict_t()
  412. port_dict.group_id = port.group_id
  413. port_dict.port_id = port.port_id
  414. port_dict.port_name = port.port_name
  415. port_dict.port_mode = port.port_mode
  416. port_dict.port_type = port.port_type
  417. port_dict.is_alternate = port.is_alternate
  418. port_dict.widget = None
  419. ports_data.append(port_dict)
  420. for connection in canvas.connection_list:
  421. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  422. connection_dict = connection_dict_t()
  423. connection_dict.connection_id = connection.connection_id
  424. connection_dict.group_in_id = connection.group_in_id
  425. connection_dict.port_in_id = connection.port_in_id
  426. connection_dict.group_out_id = connection.group_out_id
  427. connection_dict.port_out_id = connection.port_out_id
  428. connection_dict.widget = None
  429. conns_data.append(connection_dict)
  430. # Step 2 - Remove Item and Children
  431. for conn in conns_data:
  432. disconnectPorts(conn.connection_id)
  433. for port_id in port_list_ids:
  434. removePort(group_id, port_id)
  435. removeGroup(group_id)
  436. # Step 3 - Re-create Item, now together
  437. addGroup(group_id, group_name, SPLIT_NO, group_icon)
  438. if plugin_id >= 0:
  439. setGroupAsPlugin(group_id, plugin_id, plugin_ui)
  440. for port in ports_data:
  441. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
  442. for conn in conns_data:
  443. connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id)
  444. QTimer.singleShot(0, canvas.scene.update)
  445. # ------------------------------------------------------------------------------------------------------------
  446. def getGroupPos(group_id, port_mode=PORT_MODE_OUTPUT):
  447. if canvas.debug:
  448. print("PatchCanvas::getGroupPos(%i, %s)" % (group_id, port_mode2str(port_mode)))
  449. for group in canvas.group_list:
  450. if group.group_id == group_id:
  451. return group.widgets[1 if (group.split and port_mode == PORT_MODE_INPUT) else 0].pos()
  452. qCritical("PatchCanvas::getGroupPos(%i, %s) - unable to find group" % (group_id, port_mode2str(port_mode)))
  453. return QPointF(0, 0)
  454. def saveGroupPositions():
  455. if canvas.debug:
  456. print("PatchCanvas::getGroupPositions()")
  457. ret = []
  458. for group in canvas.group_list:
  459. if group.split:
  460. pos1 = group.widgets[0].pos()
  461. pos2 = group.widgets[1].pos()
  462. else:
  463. pos1 = group.widgets[0].pos()
  464. pos2 = QPointF(0, 0)
  465. ret.append({
  466. "name" : group.group_name,
  467. "pos1x": pos1.x(),
  468. "pos1y": pos1.y(),
  469. "pos2x": pos2.x(),
  470. "pos2y": pos2.y(),
  471. "split": group.split,
  472. })
  473. return ret
  474. def restoreGroupPositions(dataList):
  475. if canvas.debug:
  476. print("PatchCanvas::restoreGroupPositions(...)")
  477. mapping = {}
  478. for group in canvas.group_list:
  479. mapping[group.group_name] = group
  480. for data in dataList:
  481. name = data['name']
  482. group = mapping.get(name, None)
  483. if group is None:
  484. continue
  485. group.widgets[0].setPos(data['pos1x'], data['pos1y'])
  486. if group.split and group.widgets[1]:
  487. group.widgets[1].setPos(data['pos2x'], data['pos2y'])
  488. def setGroupPos(group_id, group_pos_x, group_pos_y):
  489. setGroupPosFull(group_id, group_pos_x, group_pos_y, group_pos_x, group_pos_y)
  490. def setGroupPosFull(group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i):
  491. if canvas.debug:
  492. print("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i)" % (
  493. group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  494. for group in canvas.group_list:
  495. if group.group_id == group_id:
  496. group.widgets[0].setPos(group_pos_x_o, group_pos_y_o)
  497. if group.split and group.widgets[1]:
  498. group.widgets[1].setPos(group_pos_x_i, group_pos_y_i)
  499. QTimer.singleShot(0, canvas.scene.update)
  500. return
  501. qCritical("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i) - unable to find group to reposition" % (
  502. group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  503. # ------------------------------------------------------------------------------------------------------------
  504. def setGroupIcon(group_id, icon):
  505. if canvas.debug:
  506. print("PatchCanvas::setGroupIcon(%i, %s)" % (group_id, icon2str(icon)))
  507. for group in canvas.group_list:
  508. if group.group_id == group_id:
  509. group.icon = icon
  510. group.widgets[0].setIcon(icon)
  511. if group.split and group.widgets[1]:
  512. group.widgets[1].setIcon(icon)
  513. QTimer.singleShot(0, canvas.scene.update)
  514. return
  515. qCritical("PatchCanvas::setGroupIcon(%i, %s) - unable to find group to change icon" % (group_id, icon2str(icon)))
  516. def setGroupAsPlugin(group_id, plugin_id, hasUi):
  517. if canvas.debug:
  518. print("PatchCanvas::setGroupAsPlugin(%i, %i, %s)" % (group_id, plugin_id, bool2str(hasUi)))
  519. for group in canvas.group_list:
  520. if group.group_id == group_id:
  521. group.plugin_id = plugin_id
  522. group.plugin_ui = hasUi
  523. group.widgets[0].setAsPlugin(plugin_id, hasUi)
  524. if group.split and group.widgets[1]:
  525. group.widgets[1].setAsPlugin(plugin_id, hasUi)
  526. return
  527. qCritical("PatchCanvas::setGroupAsPlugin(%i, %i, %s) - unable to find group to set as plugin" % (
  528. group_id, plugin_id, bool2str(hasUi)))
  529. # ------------------------------------------------------------------------------------------------------------
  530. def addPort(group_id, port_id, port_name, port_mode, port_type, is_alternate=False):
  531. if canvas.debug:
  532. print("PatchCanvas::addPort(%i, %i, %s, %s, %s, %s)" % (
  533. group_id, port_id, port_name.encode(),
  534. port_mode2str(port_mode), port_type2str(port_type), bool2str(is_alternate)))
  535. for port in canvas.port_list:
  536. if port.group_id == group_id and port.port_id == port_id:
  537. qWarning("PatchCanvas::addPort(%i, %i, %s, %s, %s) - port already exists" % (
  538. group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  539. return
  540. box_widget = None
  541. port_widget = None
  542. for group in canvas.group_list:
  543. if group.group_id == group_id:
  544. if group.split and group.widgets[0].getSplittedMode() != port_mode and group.widgets[1]:
  545. n = 1
  546. else:
  547. n = 0
  548. box_widget = group.widgets[n]
  549. port_widget = box_widget.addPortFromGroup(port_id, port_mode, port_type, port_name, is_alternate)
  550. break
  551. if not (box_widget and port_widget):
  552. qCritical("PatchCanvas::addPort(%i, %i, %s, %s, %s) - Unable to find parent group" % (
  553. group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  554. return
  555. port_dict = port_dict_t()
  556. port_dict.group_id = group_id
  557. port_dict.port_id = port_id
  558. port_dict.port_name = port_name
  559. port_dict.port_mode = port_mode
  560. port_dict.port_type = port_type
  561. port_dict.is_alternate = is_alternate
  562. port_dict.widget = port_widget
  563. canvas.port_list.append(port_dict)
  564. box_widget.updatePositions()
  565. if options.eyecandy == EYECANDY_FULL:
  566. CanvasItemFX(port_widget, True, False)
  567. return
  568. QTimer.singleShot(0, canvas.scene.update)
  569. def removePort(group_id, port_id):
  570. if canvas.debug:
  571. print("PatchCanvas::removePort(%i, %i)" % (group_id, port_id))
  572. for port in canvas.port_list:
  573. if port.group_id == group_id and port.port_id == port_id:
  574. item = port.widget
  575. item.parentItem().removePortFromGroup(port_id)
  576. canvas.scene.removeItem(item)
  577. canvas.port_list.remove(port)
  578. del item
  579. QTimer.singleShot(0, canvas.scene.update)
  580. return
  581. qCritical("PatchCanvas::removePort(%i, %i) - Unable to find port to remove" % (group_id, port_id))
  582. def renamePort(group_id, port_id, new_port_name):
  583. if canvas.debug:
  584. print("PatchCanvas::renamePort(%i, %i, %s)" % (group_id, port_id, new_port_name.encode()))
  585. for port in canvas.port_list:
  586. if port.group_id == group_id and port.port_id == port_id:
  587. port.port_name = new_port_name
  588. port.widget.setPortName(new_port_name)
  589. port.widget.parentItem().updatePositions()
  590. QTimer.singleShot(0, canvas.scene.update)
  591. return
  592. qCritical("PatchCanvas::renamePort(%i, %i, %s) - Unable to find port to rename" % (
  593. group_id, port_id, new_port_name.encode()))
  594. def connectPorts(connection_id, group_out_id, port_out_id, group_in_id, port_in_id):
  595. if canvas.debug:
  596. print("PatchCanvas::connectPorts(%i, %i, %i, %i, %i)" % (
  597. connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
  598. port_out = None
  599. port_in = None
  600. port_out_parent = None
  601. port_in_parent = None
  602. for port in canvas.port_list:
  603. if port.group_id == group_out_id and port.port_id == port_out_id:
  604. port_out = port.widget
  605. port_out_parent = port_out.parentItem()
  606. elif port.group_id == group_in_id and port.port_id == port_in_id:
  607. port_in = port.widget
  608. port_in_parent = port_in.parentItem()
  609. # FIXME
  610. if not (port_out and port_in):
  611. qCritical("PatchCanvas::connectPorts(%i, %i, %i, %i, %i) - unable to find ports to connect" % (
  612. connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
  613. return
  614. connection_dict = connection_dict_t()
  615. connection_dict.connection_id = connection_id
  616. connection_dict.group_in_id = group_in_id
  617. connection_dict.port_in_id = port_in_id
  618. connection_dict.group_out_id = group_out_id
  619. connection_dict.port_out_id = port_out_id
  620. if options.use_bezier_lines:
  621. connection_dict.widget = CanvasBezierLine(port_out, port_in, None)
  622. else:
  623. connection_dict.widget = CanvasLine(port_out, port_in, None)
  624. canvas.scene.addItem(connection_dict.widget)
  625. port_out_parent.addLineFromGroup(connection_dict.widget, connection_id)
  626. port_in_parent.addLineFromGroup(connection_dict.widget, connection_id)
  627. canvas.last_z_value += 1
  628. port_out_parent.setZValue(canvas.last_z_value)
  629. port_in_parent.setZValue(canvas.last_z_value)
  630. canvas.last_z_value += 1
  631. connection_dict.widget.setZValue(canvas.last_z_value)
  632. canvas.connection_list.append(connection_dict)
  633. if options.eyecandy == EYECANDY_FULL:
  634. item = connection_dict.widget
  635. CanvasItemFX(item, True, False)
  636. return
  637. QTimer.singleShot(0, canvas.scene.update)
  638. def disconnectPorts(connection_id):
  639. if canvas.debug:
  640. print("PatchCanvas::disconnectPorts(%i)" % connection_id)
  641. line = None
  642. item1 = None
  643. item2 = None
  644. group1id = port1id = 0
  645. group2id = port2id = 0
  646. for connection in canvas.connection_list:
  647. if connection.connection_id == connection_id:
  648. group1id = connection.group_out_id
  649. group2id = connection.group_in_id
  650. port1id = connection.port_out_id
  651. port2id = connection.port_in_id
  652. line = connection.widget
  653. canvas.connection_list.remove(connection)
  654. break
  655. if not line:
  656. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find connection ports" % connection_id)
  657. return
  658. for port in canvas.port_list:
  659. if port.group_id == group1id and port.port_id == port1id:
  660. item1 = port.widget
  661. break
  662. if not item1:
  663. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find output port" % connection_id)
  664. return
  665. for port in canvas.port_list:
  666. if port.group_id == group2id and port.port_id == port2id:
  667. item2 = port.widget
  668. break
  669. if not item2:
  670. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find input port" % connection_id)
  671. return
  672. item1.parentItem().removeLineFromGroup(connection_id)
  673. item2.parentItem().removeLineFromGroup(connection_id)
  674. if options.eyecandy == EYECANDY_FULL:
  675. CanvasItemFX(line, False, True)
  676. return
  677. canvas.scene.removeItem(line)
  678. del line
  679. QTimer.singleShot(0, canvas.scene.update)
  680. # ------------------------------------------------------------------------------------------------------------
  681. def arrange():
  682. if canvas.debug:
  683. print("PatchCanvas::arrange()")
  684. # ------------------------------------------------------------------------------------------------------------
  685. def updateZValues():
  686. if canvas.debug:
  687. print("PatchCanvas::updateZValues()")
  688. for group in canvas.group_list:
  689. group.widgets[0].resetLinesZValue()
  690. if group.split and group.widgets[1]:
  691. group.widgets[1].resetLinesZValue()
  692. # ------------------------------------------------------------------------------------------------------------
  693. def handlePluginRemoved(plugin_id):
  694. if canvas.debug:
  695. print("PatchCanvas::handlePluginRemoved(%i)" % plugin_id)
  696. for group in canvas.group_list:
  697. if group.plugin_id < plugin_id or group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
  698. continue
  699. group.plugin_id -= 1
  700. group.widgets[0].m_plugin_id -= 1
  701. if group.split and group.widgets[1]:
  702. group.widgets[1].m_plugin_id -= 1
  703. def handleAllPluginsRemoved():
  704. if canvas.debug:
  705. print("PatchCanvas::handleAllPluginsRemoved()")
  706. for group in canvas.group_list:
  707. if group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
  708. continue
  709. group.plugin_id = -1
  710. group.plugin_ui = False
  711. group.widgets[0].m_plugin_id = -1
  712. group.widgets[0].m_plugin_ui = False
  713. if group.split and group.widgets[1]:
  714. group.widgets[1].m_plugin_id = -1
  715. group.widgets[1].m_plugin_ui = False
  716. # ------------------------------------------------------------------------------------------------------------