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.

1063 lines
35KB

  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, 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. from carla_shared import QSafeSettings
  58. # ------------------------------------------------------------------------------------------------------------
  59. class CanvasObject(QObject):
  60. def __init__(self, parent=None):
  61. QObject.__init__(self, parent)
  62. @pyqtSlot()
  63. def AnimationFinishedShow(self):
  64. animation = self.sender()
  65. if animation:
  66. animation.forceStop()
  67. canvas.animation_list.remove(animation)
  68. @pyqtSlot()
  69. def AnimationFinishedHide(self):
  70. animation = self.sender()
  71. if animation:
  72. animation.forceStop()
  73. canvas.animation_list.remove(animation)
  74. item = animation.item()
  75. if item:
  76. item.hide()
  77. @pyqtSlot()
  78. def AnimationFinishedDestroy(self):
  79. animation = self.sender()
  80. if animation:
  81. animation.forceStop()
  82. canvas.animation_list.remove(animation)
  83. item = animation.item()
  84. if item:
  85. CanvasRemoveItemFX(item)
  86. @pyqtSlot()
  87. def PortContextMenuConnect(self):
  88. try:
  89. sources, targets = self.sender().data()
  90. except:
  91. return
  92. for port_type in (PORT_TYPE_AUDIO_JACK, PORT_TYPE_MIDI_JACK, PORT_TYPE_MIDI_ALSA, PORT_TYPE_PARAMETER):
  93. source_ports = sources[port_type]
  94. target_ports = targets[port_type]
  95. source_ports_len = len(source_ports)
  96. target_ports_len = len(target_ports)
  97. if source_ports_len == 0 or target_ports_len == 0:
  98. continue
  99. for i in range(min(source_ports_len, target_ports_len)):
  100. data = "%i:%i:%i:%i" % (source_ports[i][0],
  101. source_ports[i][1],
  102. target_ports[i][0],
  103. target_ports[i][1])
  104. CanvasCallback(ACTION_PORTS_CONNECT, 0, 0, data)
  105. if source_ports_len == 1 and target_ports_len > 1:
  106. for i in range(1, target_ports_len):
  107. data = "%i:%i:%i:%i" % (source_ports[0][0],
  108. source_ports[0][1],
  109. target_ports[i][0],
  110. target_ports[i][1])
  111. CanvasCallback(ACTION_PORTS_CONNECT, 0, 0, data)
  112. @pyqtSlot()
  113. def PortContextMenuDisconnect(self):
  114. try:
  115. connectionId = int(self.sender().data())
  116. except:
  117. return
  118. CanvasCallback(ACTION_PORTS_DISCONNECT, connectionId, 0, "")
  119. @pyqtSlot(int, bool, int, int)
  120. def boxPositionChanged(self, groupId, split, x, y):
  121. x2 = y2 = 0
  122. if split:
  123. for group in canvas.group_list:
  124. if group.group_id == groupId:
  125. if group.split:
  126. pos = group.widgets[1].pos()
  127. x2 = pos.x()
  128. y2 = pos.y()
  129. break
  130. valueStr = "%i:%i:%i:%i" % (x, y, x2, y2)
  131. CanvasCallback(ACTION_GROUP_POSITION, groupId, 0, valueStr)
  132. @pyqtSlot(int, bool, int, int)
  133. def sboxPositionChanged(self, groupId, split, x2, y2):
  134. x = y = 0
  135. for group in canvas.group_list:
  136. if group.group_id == groupId:
  137. pos = group.widgets[0].pos()
  138. x = pos.x()
  139. y = pos.y()
  140. break
  141. valueStr = "%i:%i:%i:%i" % (x, y, x2, y2)
  142. CanvasCallback(ACTION_GROUP_POSITION, groupId, 0, valueStr)
  143. # ------------------------------------------------------------------------------------------------------------
  144. def getStoredCanvasPosition(key, fallback_pos):
  145. try:
  146. return canvas.settings.value("CanvasPositions/" + key, fallback_pos, type=QPointF)
  147. except:
  148. return fallback_pos
  149. def getStoredCanvasSplit(group_name, fallback_split_mode):
  150. try:
  151. return canvas.settings.value("CanvasPositions/%s_SPLIT" % group_name, fallback_split_mode, type=int)
  152. except:
  153. return fallback_split_mode
  154. # ------------------------------------------------------------------------------------------------------------
  155. def init(appName, scene, callback, debug=False):
  156. if debug:
  157. print("PatchCanvas::init(\"%s\", %s, %s, %s)" % (appName, scene, callback, bool2str(debug)))
  158. if canvas.initiated:
  159. qCritical("PatchCanvas::init() - already initiated")
  160. return
  161. if not callback:
  162. qFatal("PatchCanvas::init() - fatal error: callback not set")
  163. return
  164. canvas.callback = callback
  165. canvas.debug = debug
  166. canvas.scene = scene
  167. canvas.last_z_value = 0
  168. canvas.last_connection_id = 0
  169. canvas.initial_pos = QPointF(0, 0)
  170. canvas.size_rect = QRectF()
  171. if not canvas.qobject:
  172. canvas.qobject = CanvasObject()
  173. if not canvas.settings:
  174. canvas.settings = QSafeSettings("falkTX", appName)
  175. if canvas.theme:
  176. del canvas.theme
  177. canvas.theme = None
  178. for i in range(Theme.THEME_MAX):
  179. this_theme_name = getThemeName(i)
  180. if this_theme_name == options.theme_name:
  181. canvas.theme = Theme(i)
  182. break
  183. if not canvas.theme:
  184. canvas.theme = Theme(getDefaultTheme())
  185. canvas.scene.updateTheme()
  186. canvas.initiated = True
  187. def clear():
  188. if canvas.debug:
  189. print("PatchCanvas::clear()")
  190. group_pos = {}
  191. group_list_ids = []
  192. port_list_ids = []
  193. connection_list_ids = []
  194. for group in canvas.group_list:
  195. group_pos[group.group_name] = (
  196. group.split,
  197. group.widgets[0].pos(),
  198. group.widgets[1].pos() if group.split else None,
  199. )
  200. group_list_ids.append(group.group_id)
  201. for port in canvas.port_list:
  202. port_list_ids.append((port.group_id, port.port_id))
  203. for connection in canvas.connection_list:
  204. connection_list_ids.append(connection.connection_id)
  205. for idx in connection_list_ids:
  206. disconnectPorts(idx)
  207. for group_id, port_id in port_list_ids:
  208. removePort(group_id, port_id)
  209. for idx in group_list_ids:
  210. removeGroup(idx)
  211. canvas.last_z_value = 0
  212. canvas.last_connection_id = 0
  213. canvas.group_list = []
  214. canvas.port_list = []
  215. canvas.connection_list = []
  216. canvas.group_plugin_map = {}
  217. canvas.old_group_pos = group_pos
  218. canvas.scene.clearSelection()
  219. animatedItems = []
  220. for animation in canvas.animation_list:
  221. animatedItems.append(animation.item())
  222. for item in canvas.scene.items():
  223. if item.type() in (CanvasIconType, CanvasRubberbandType) or item in animatedItems:
  224. continue
  225. canvas.scene.removeItem(item)
  226. del item
  227. canvas.initiated = False
  228. QTimer.singleShot(0, canvas.scene.update)
  229. # ------------------------------------------------------------------------------------------------------------
  230. def setInitialPos(x, y):
  231. if canvas.debug:
  232. print("PatchCanvas::setInitialPos(%i, %i)" % (x, y))
  233. canvas.initial_pos.setX(x)
  234. canvas.initial_pos.setY(y)
  235. def setCanvasSize(x, y, width, height):
  236. if canvas.debug:
  237. print("PatchCanvas::setCanvasSize(%i, %i, %i, %i)" % (x, y, width, height))
  238. canvas.size_rect.setX(x)
  239. canvas.size_rect.setY(y)
  240. canvas.size_rect.setWidth(width)
  241. canvas.size_rect.setHeight(height)
  242. canvas.scene.updateLimits()
  243. canvas.scene.fixScaleFactor()
  244. def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):
  245. if canvas.debug:
  246. print("PatchCanvas::addGroup(%i, %s, %s, %s)" % (
  247. group_id, group_name.encode(), split2str(split), icon2str(icon)))
  248. for group in canvas.group_list:
  249. if group.group_id == group_id:
  250. qWarning("PatchCanvas::addGroup(%i, %s, %s, %s) - group already exists" % (
  251. group_id, group_name.encode(), split2str(split), icon2str(icon)))
  252. return
  253. old_matching_group = canvas.old_group_pos.pop(group_name, None)
  254. if split == SPLIT_UNDEF:
  255. isHardware = bool(icon == ICON_HARDWARE)
  256. if features.handle_group_pos:
  257. split = getStoredCanvasSplit(group_name, SPLIT_YES if isHardware else split)
  258. elif isHardware:
  259. split = SPLIT_YES
  260. elif old_matching_group is not None and old_matching_group[0]:
  261. split = SPLIT_YES
  262. group_box = CanvasBox(group_id, group_name, icon)
  263. group_box.positionChanged.connect(canvas.qobject.boxPositionChanged)
  264. group_dict = group_dict_t()
  265. group_dict.group_id = group_id
  266. group_dict.group_name = group_name
  267. group_dict.split = bool(split == SPLIT_YES)
  268. group_dict.icon = icon
  269. group_dict.plugin_id = -1
  270. group_dict.plugin_ui = False
  271. group_dict.plugin_inline = False
  272. group_dict.widgets = [group_box, None]
  273. if split == SPLIT_YES:
  274. group_box.setSplit(True, PORT_MODE_OUTPUT)
  275. group_box.blockSignals(True)
  276. if features.handle_group_pos:
  277. group_box.setPos(getStoredCanvasPosition(group_name + "_OUTPUT", CanvasGetNewGroupPos(False)))
  278. elif old_matching_group is not None:
  279. group_box.setPos(old_matching_group[1])
  280. else:
  281. group_box.setPos(CanvasGetNewGroupPos(False))
  282. group_box.blockSignals(False)
  283. group_sbox = CanvasBox(group_id, group_name, icon)
  284. group_sbox.setSplit(True, PORT_MODE_INPUT)
  285. group_sbox.positionChanged.connect(canvas.qobject.sboxPositionChanged)
  286. group_dict.widgets[1] = group_sbox
  287. group_sbox.blockSignals(True)
  288. if features.handle_group_pos:
  289. group_sbox.setPos(getStoredCanvasPosition(group_name + "_INPUT", CanvasGetNewGroupPos(True)))
  290. elif old_matching_group is not None and old_matching_group[0]:
  291. group_sbox.setPos(old_matching_group[2])
  292. else:
  293. group_sbox.setPos(CanvasGetNewGroupPos(True))
  294. group_sbox.blockSignals(False)
  295. canvas.last_z_value += 1
  296. group_sbox.setZValue(canvas.last_z_value)
  297. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  298. CanvasItemFX(group_sbox, True, False)
  299. group_sbox.checkItemPos(True)
  300. else:
  301. group_box.setSplit(False)
  302. if features.handle_group_pos:
  303. group_box.setPos(getStoredCanvasPosition(group_name, CanvasGetNewGroupPos(False)))
  304. elif old_matching_group is not None:
  305. group_box.setPos(old_matching_group[1])
  306. else:
  307. # Special ladish fake-split groups
  308. horizontal = bool(icon == ICON_HARDWARE or icon == ICON_LADISH_ROOM)
  309. group_box.setPos(CanvasGetNewGroupPos(horizontal))
  310. group_box.checkItemPos(True)
  311. canvas.last_z_value += 1
  312. group_box.setZValue(canvas.last_z_value)
  313. canvas.group_list.append(group_dict)
  314. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  315. CanvasItemFX(group_box, True, False)
  316. return
  317. QTimer.singleShot(0, canvas.scene.update)
  318. def removeGroup(group_id):
  319. if canvas.debug:
  320. print("PatchCanvas::removeGroup(%i)" % group_id)
  321. for group in canvas.group_list:
  322. if group.group_id == group_id:
  323. item = group.widgets[0]
  324. group_name = group.group_name
  325. if group.split:
  326. s_item = group.widgets[1]
  327. if features.handle_group_pos:
  328. canvas.settings.setValue("CanvasPositions/%s_OUTPUT" % group_name, item.pos())
  329. canvas.settings.setValue("CanvasPositions/%s_INPUT" % group_name, s_item.pos())
  330. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_YES)
  331. if options.eyecandy == EYECANDY_FULL:
  332. CanvasItemFX(s_item, False, True)
  333. else:
  334. s_item.removeIconFromScene()
  335. canvas.scene.removeItem(s_item)
  336. del s_item
  337. else:
  338. if features.handle_group_pos:
  339. canvas.settings.setValue("CanvasPositions/%s" % group_name, item.pos())
  340. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_NO)
  341. if options.eyecandy == EYECANDY_FULL:
  342. CanvasItemFX(item, False, True)
  343. else:
  344. item.removeIconFromScene()
  345. canvas.scene.removeItem(item)
  346. del item
  347. canvas.group_list.remove(group)
  348. canvas.group_plugin_map.pop(group.plugin_id, None)
  349. QTimer.singleShot(0, canvas.scene.update)
  350. return
  351. qCritical("PatchCanvas::removeGroup(%i) - unable to find group to remove" % group_id)
  352. def renameGroup(group_id, new_group_name):
  353. if canvas.debug:
  354. print("PatchCanvas::renameGroup(%i, %s)" % (group_id, new_group_name.encode()))
  355. for group in canvas.group_list:
  356. if group.group_id == group_id:
  357. group.group_name = new_group_name
  358. group.widgets[0].setGroupName(new_group_name)
  359. if group.split and group.widgets[1]:
  360. group.widgets[1].setGroupName(new_group_name)
  361. QTimer.singleShot(0, canvas.scene.update)
  362. return
  363. qCritical("PatchCanvas::renameGroup(%i, %s) - unable to find group to rename" % (group_id, new_group_name.encode()))
  364. def splitGroup(group_id):
  365. if canvas.debug:
  366. print("PatchCanvas::splitGroup(%i)" % group_id)
  367. item = None
  368. group_name = ""
  369. group_icon = ICON_APPLICATION
  370. plugin_id = -1
  371. plugin_ui = False
  372. plugin_inline = False
  373. ports_data = []
  374. conns_data = []
  375. # Step 1 - Store all Item data
  376. for group in canvas.group_list:
  377. if group.group_id == group_id:
  378. if group.split:
  379. qCritical("PatchCanvas::splitGroup(%i) - group is already split" % group_id)
  380. return
  381. item = group.widgets[0]
  382. group_name = group.group_name
  383. group_icon = group.icon
  384. plugin_id = group.plugin_id
  385. plugin_ui = group.plugin_ui
  386. plugin_inline = group.plugin_inline
  387. break
  388. if not item:
  389. qCritical("PatchCanvas::splitGroup(%i) - unable to find group to split" % group_id)
  390. return
  391. port_list_ids = list(item.getPortList())
  392. for port in canvas.port_list:
  393. if port.port_id in port_list_ids:
  394. port_dict = port_dict_t()
  395. port_dict.group_id = port.group_id
  396. port_dict.port_id = port.port_id
  397. port_dict.port_name = port.port_name
  398. port_dict.port_mode = port.port_mode
  399. port_dict.port_type = port.port_type
  400. port_dict.is_alternate = port.is_alternate
  401. port_dict.widget = None
  402. ports_data.append(port_dict)
  403. for connection in canvas.connection_list:
  404. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  405. connection_dict = connection_dict_t()
  406. connection_dict.connection_id = connection.connection_id
  407. connection_dict.group_in_id = connection.group_in_id
  408. connection_dict.port_in_id = connection.port_in_id
  409. connection_dict.group_out_id = connection.group_out_id
  410. connection_dict.port_out_id = connection.port_out_id
  411. connection_dict.widget = None
  412. conns_data.append(connection_dict)
  413. # Step 2 - Remove Item and Children
  414. for conn in conns_data:
  415. disconnectPorts(conn.connection_id)
  416. for port_id in port_list_ids:
  417. removePort(group_id, port_id)
  418. removeGroup(group_id)
  419. # Step 3 - Re-create Item, now split
  420. addGroup(group_id, group_name, SPLIT_YES, group_icon)
  421. if plugin_id >= 0:
  422. setGroupAsPlugin(group_id, plugin_id, plugin_ui, plugin_inline)
  423. for port in ports_data:
  424. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
  425. for conn in conns_data:
  426. connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id)
  427. QTimer.singleShot(0, canvas.scene.update)
  428. def joinGroup(group_id):
  429. if canvas.debug:
  430. print("PatchCanvas::joinGroup(%i)" % group_id)
  431. item = None
  432. s_item = None
  433. group_name = ""
  434. group_icon = ICON_APPLICATION
  435. plugin_id = -1
  436. plugin_ui = False
  437. plugin_inline = False
  438. ports_data = []
  439. conns_data = []
  440. # Step 1 - Store all Item data
  441. for group in canvas.group_list:
  442. if group.group_id == group_id:
  443. if not group.split:
  444. qCritical("PatchCanvas::joinGroup(%i) - group is not split" % group_id)
  445. return
  446. item = group.widgets[0]
  447. s_item = group.widgets[1]
  448. group_name = group.group_name
  449. group_icon = group.icon
  450. plugin_id = group.plugin_id
  451. plugin_ui = group.plugin_ui
  452. plugin_inline = group.plugin_inline
  453. break
  454. # FIXME
  455. if not (item and s_item):
  456. qCritical("PatchCanvas::joinGroup(%i) - unable to find groups to join" % group_id)
  457. return
  458. port_list_ids = list(item.getPortList())
  459. port_list_idss = s_item.getPortList()
  460. for port_id in port_list_idss:
  461. if port_id not in port_list_ids:
  462. port_list_ids.append(port_id)
  463. for port in canvas.port_list:
  464. if port.port_id in port_list_ids:
  465. port_dict = port_dict_t()
  466. port_dict.group_id = port.group_id
  467. port_dict.port_id = port.port_id
  468. port_dict.port_name = port.port_name
  469. port_dict.port_mode = port.port_mode
  470. port_dict.port_type = port.port_type
  471. port_dict.is_alternate = port.is_alternate
  472. port_dict.widget = None
  473. ports_data.append(port_dict)
  474. for connection in canvas.connection_list:
  475. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  476. connection_dict = connection_dict_t()
  477. connection_dict.connection_id = connection.connection_id
  478. connection_dict.group_in_id = connection.group_in_id
  479. connection_dict.port_in_id = connection.port_in_id
  480. connection_dict.group_out_id = connection.group_out_id
  481. connection_dict.port_out_id = connection.port_out_id
  482. connection_dict.widget = None
  483. conns_data.append(connection_dict)
  484. # Step 2 - Remove Item and Children
  485. for conn in conns_data:
  486. disconnectPorts(conn.connection_id)
  487. for port_id in port_list_ids:
  488. removePort(group_id, port_id)
  489. removeGroup(group_id)
  490. # Step 3 - Re-create Item, now together
  491. addGroup(group_id, group_name, SPLIT_NO, group_icon)
  492. if plugin_id >= 0:
  493. setGroupAsPlugin(group_id, plugin_id, plugin_ui, plugin_inline)
  494. for port in ports_data:
  495. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
  496. for conn in conns_data:
  497. connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id)
  498. QTimer.singleShot(0, canvas.scene.update)
  499. # ------------------------------------------------------------------------------------------------------------
  500. def getGroupPos(group_id, port_mode=PORT_MODE_OUTPUT):
  501. if canvas.debug:
  502. print("PatchCanvas::getGroupPos(%i, %s)" % (group_id, port_mode2str(port_mode)))
  503. for group in canvas.group_list:
  504. if group.group_id == group_id:
  505. return group.widgets[1 if (group.split and port_mode == PORT_MODE_INPUT) else 0].pos()
  506. qCritical("PatchCanvas::getGroupPos(%i, %s) - unable to find group" % (group_id, port_mode2str(port_mode)))
  507. return QPointF(0, 0)
  508. def saveGroupPositions():
  509. if canvas.debug:
  510. print("PatchCanvas::getGroupPositions()")
  511. ret = []
  512. for group in canvas.group_list:
  513. if group.split:
  514. pos1 = group.widgets[0].pos()
  515. pos2 = group.widgets[1].pos()
  516. else:
  517. pos1 = group.widgets[0].pos()
  518. pos2 = QPointF(0, 0)
  519. ret.append({
  520. "name" : group.group_name,
  521. "pos1x": pos1.x(),
  522. "pos1y": pos1.y(),
  523. "pos2x": pos2.x(),
  524. "pos2y": pos2.y(),
  525. "split": group.split,
  526. })
  527. return ret
  528. def restoreGroupPositions(dataList):
  529. if canvas.debug:
  530. print("PatchCanvas::restoreGroupPositions(...)")
  531. mapping = {}
  532. for group in canvas.group_list:
  533. mapping[group.group_name] = group
  534. for data in dataList:
  535. name = data['name']
  536. group = mapping.get(name, None)
  537. if group is None:
  538. continue
  539. group.widgets[0].blockSignals(True)
  540. group.widgets[0].setPos(data['pos1x'], data['pos1y'])
  541. group.widgets[0].blockSignals(False)
  542. if group.split and group.widgets[1]:
  543. group.widgets[1].blockSignals(True)
  544. group.widgets[1].setPos(data['pos2x'], data['pos2y'])
  545. group.widgets[1].blockSignals(False)
  546. def setGroupPos(group_id, group_pos_x, group_pos_y):
  547. setGroupPosFull(group_id, group_pos_x, group_pos_y, group_pos_x, group_pos_y)
  548. def setGroupPosFull(group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i):
  549. if canvas.debug:
  550. print("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i)" % (
  551. group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  552. for group in canvas.group_list:
  553. if group.group_id == group_id:
  554. group.widgets[0].blockSignals(True)
  555. group.widgets[0].setPos(group_pos_x_o, group_pos_y_o)
  556. group.widgets[0].blockSignals(False)
  557. if group.split and group.widgets[1]:
  558. group.widgets[1].blockSignals(True)
  559. group.widgets[1].setPos(group_pos_x_i, group_pos_y_i)
  560. group.widgets[1].blockSignals(False)
  561. QTimer.singleShot(0, canvas.scene.update)
  562. return
  563. qCritical("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i) - unable to find group to reposition" % (
  564. group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  565. # ------------------------------------------------------------------------------------------------------------
  566. def setGroupIcon(group_id, icon):
  567. if canvas.debug:
  568. print("PatchCanvas::setGroupIcon(%i, %s)" % (group_id, icon2str(icon)))
  569. for group in canvas.group_list:
  570. if group.group_id == group_id:
  571. group.icon = icon
  572. group.widgets[0].setIcon(icon)
  573. if group.split and group.widgets[1]:
  574. group.widgets[1].setIcon(icon)
  575. QTimer.singleShot(0, canvas.scene.update)
  576. return
  577. qCritical("PatchCanvas::setGroupIcon(%i, %s) - unable to find group to change icon" % (group_id, icon2str(icon)))
  578. def setGroupAsPlugin(group_id, plugin_id, hasUI, hasInlineDisplay):
  579. if canvas.debug:
  580. print("PatchCanvas::setGroupAsPlugin(%i, %i, %s, %s)" % (
  581. group_id, plugin_id, bool2str(hasUI), bool2str(hasInlineDisplay)))
  582. for group in canvas.group_list:
  583. if group.group_id == group_id:
  584. group.plugin_id = plugin_id
  585. group.plugin_ui = hasUI
  586. group.plugin_inline = hasInlineDisplay
  587. group.widgets[0].setAsPlugin(plugin_id, hasUI, hasInlineDisplay)
  588. if group.split and group.widgets[1]:
  589. group.widgets[1].setAsPlugin(plugin_id, hasUI, hasInlineDisplay)
  590. canvas.group_plugin_map[plugin_id] = group
  591. return
  592. qCritical("PatchCanvas::setGroupAsPlugin(%i, %i, %s, %s) - unable to find group to set as plugin" % (
  593. group_id, plugin_id, bool2str(hasUI), bool2str(hasInlineDisplay)))
  594. # ------------------------------------------------------------------------------------------------------------
  595. def focusGroupUsingPluginId(plugin_id):
  596. if canvas.debug:
  597. print("PatchCanvas::focusGroupUsingPluginId(%i)" % (plugin_id,))
  598. if plugin_id < 0 or plugin_id >= MAX_PLUGIN_ID_ALLOWED:
  599. return False
  600. for group in canvas.group_list:
  601. if group.plugin_id == plugin_id:
  602. item = group.widgets[0]
  603. canvas.scene.clearSelection()
  604. canvas.scene.getView().centerOn(item)
  605. item.setSelected(True)
  606. return True
  607. def focusGroupUsingGroupName(group_name):
  608. if canvas.debug:
  609. print("PatchCanvas::focusGroupUsingGroupName(%s)" % (group_name,))
  610. for group in canvas.group_list:
  611. if group.group_name == group_name:
  612. item = group.widgets[0]
  613. canvas.scene.clearSelection()
  614. canvas.scene.getView().centerOn(item)
  615. item.setSelected(True)
  616. return True
  617. # ------------------------------------------------------------------------------------------------------------
  618. def addPort(group_id, port_id, port_name, port_mode, port_type, is_alternate=False):
  619. if canvas.debug:
  620. print("PatchCanvas::addPort(%i, %i, %s, %s, %s, %s)" % (
  621. group_id, port_id, port_name.encode(),
  622. port_mode2str(port_mode), port_type2str(port_type), bool2str(is_alternate)))
  623. for port in canvas.port_list:
  624. if port.group_id == group_id and port.port_id == port_id:
  625. qWarning("PatchCanvas::addPort(%i, %i, %s, %s, %s) - port already exists" % (
  626. group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  627. return
  628. box_widget = None
  629. port_widget = None
  630. for group in canvas.group_list:
  631. if group.group_id == group_id:
  632. if group.split and group.widgets[0].getSplittedMode() != port_mode and group.widgets[1]:
  633. n = 1
  634. else:
  635. n = 0
  636. box_widget = group.widgets[n]
  637. port_widget = box_widget.addPortFromGroup(port_id, port_mode, port_type, port_name, is_alternate)
  638. break
  639. if not (box_widget and port_widget):
  640. qCritical("PatchCanvas::addPort(%i, %i, %s, %s, %s) - Unable to find parent group" % (
  641. group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  642. return
  643. port_dict = port_dict_t()
  644. port_dict.group_id = group_id
  645. port_dict.port_id = port_id
  646. port_dict.port_name = port_name
  647. port_dict.port_mode = port_mode
  648. port_dict.port_type = port_type
  649. port_dict.is_alternate = is_alternate
  650. port_dict.widget = port_widget
  651. canvas.port_list.append(port_dict)
  652. box_widget.updatePositions()
  653. if options.eyecandy == EYECANDY_FULL:
  654. CanvasItemFX(port_widget, True, False)
  655. return
  656. QTimer.singleShot(0, canvas.scene.update)
  657. def removePort(group_id, port_id):
  658. if canvas.debug:
  659. print("PatchCanvas::removePort(%i, %i)" % (group_id, port_id))
  660. for port in canvas.port_list:
  661. if port.group_id == group_id and port.port_id == port_id:
  662. item = port.widget
  663. item.parentItem().removePortFromGroup(port_id)
  664. canvas.scene.removeItem(item)
  665. canvas.port_list.remove(port)
  666. del item
  667. QTimer.singleShot(0, canvas.scene.update)
  668. return
  669. qCritical("PatchCanvas::removePort(%i, %i) - Unable to find port to remove" % (group_id, port_id))
  670. def renamePort(group_id, port_id, new_port_name):
  671. if canvas.debug:
  672. print("PatchCanvas::renamePort(%i, %i, %s)" % (group_id, port_id, new_port_name.encode()))
  673. for port in canvas.port_list:
  674. if port.group_id == group_id and port.port_id == port_id:
  675. port.port_name = new_port_name
  676. port.widget.setPortName(new_port_name)
  677. port.widget.parentItem().updatePositions()
  678. QTimer.singleShot(0, canvas.scene.update)
  679. return
  680. qCritical("PatchCanvas::renamePort(%i, %i, %s) - Unable to find port to rename" % (
  681. group_id, port_id, new_port_name.encode()))
  682. def connectPorts(connection_id, group_out_id, port_out_id, group_in_id, port_in_id):
  683. if canvas.debug:
  684. print("PatchCanvas::connectPorts(%i, %i, %i, %i, %i)" % (
  685. connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
  686. port_out = None
  687. port_in = None
  688. port_out_parent = None
  689. port_in_parent = None
  690. for port in canvas.port_list:
  691. if port.group_id == group_out_id and port.port_id == port_out_id:
  692. port_out = port.widget
  693. port_out_parent = port_out.parentItem()
  694. elif port.group_id == group_in_id and port.port_id == port_in_id:
  695. port_in = port.widget
  696. port_in_parent = port_in.parentItem()
  697. # FIXME
  698. if not (port_out and port_in):
  699. qCritical("PatchCanvas::connectPorts(%i, %i, %i, %i, %i) - unable to find ports to connect" % (
  700. connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
  701. return
  702. connection_dict = connection_dict_t()
  703. connection_dict.connection_id = connection_id
  704. connection_dict.group_in_id = group_in_id
  705. connection_dict.port_in_id = port_in_id
  706. connection_dict.group_out_id = group_out_id
  707. connection_dict.port_out_id = port_out_id
  708. if options.use_bezier_lines:
  709. connection_dict.widget = CanvasBezierLine(port_out, port_in, None)
  710. else:
  711. connection_dict.widget = CanvasLine(port_out, port_in, None)
  712. canvas.scene.addItem(connection_dict.widget)
  713. port_out_parent.addLineFromGroup(connection_dict.widget, connection_id)
  714. port_in_parent.addLineFromGroup(connection_dict.widget, connection_id)
  715. canvas.last_z_value += 1
  716. port_out_parent.setZValue(canvas.last_z_value)
  717. port_in_parent.setZValue(canvas.last_z_value)
  718. canvas.last_z_value += 1
  719. connection_dict.widget.setZValue(canvas.last_z_value)
  720. canvas.connection_list.append(connection_dict)
  721. if options.eyecandy == EYECANDY_FULL:
  722. item = connection_dict.widget
  723. CanvasItemFX(item, True, False)
  724. return
  725. QTimer.singleShot(0, canvas.scene.update)
  726. def disconnectPorts(connection_id):
  727. if canvas.debug:
  728. print("PatchCanvas::disconnectPorts(%i)" % connection_id)
  729. line = None
  730. item1 = None
  731. item2 = None
  732. group1id = port1id = 0
  733. group2id = port2id = 0
  734. for connection in canvas.connection_list:
  735. if connection.connection_id == connection_id:
  736. group1id = connection.group_out_id
  737. group2id = connection.group_in_id
  738. port1id = connection.port_out_id
  739. port2id = connection.port_in_id
  740. line = connection.widget
  741. canvas.connection_list.remove(connection)
  742. break
  743. if not line:
  744. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find connection ports" % connection_id)
  745. return
  746. for port in canvas.port_list:
  747. if port.group_id == group1id and port.port_id == port1id:
  748. item1 = port.widget
  749. break
  750. if not item1:
  751. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find output port" % connection_id)
  752. return
  753. for port in canvas.port_list:
  754. if port.group_id == group2id and port.port_id == port2id:
  755. item2 = port.widget
  756. break
  757. if not item2:
  758. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find input port" % connection_id)
  759. return
  760. item1.parentItem().removeLineFromGroup(connection_id)
  761. item2.parentItem().removeLineFromGroup(connection_id)
  762. if options.eyecandy == EYECANDY_FULL:
  763. CanvasItemFX(line, False, True)
  764. return
  765. canvas.scene.removeItem(line)
  766. del line
  767. QTimer.singleShot(0, canvas.scene.update)
  768. # ------------------------------------------------------------------------------------------------------------
  769. def arrange():
  770. if canvas.debug:
  771. print("PatchCanvas::arrange()")
  772. # ------------------------------------------------------------------------------------------------------------
  773. def updateZValues():
  774. if canvas.debug:
  775. print("PatchCanvas::updateZValues()")
  776. for group in canvas.group_list:
  777. group.widgets[0].resetLinesZValue()
  778. if group.split and group.widgets[1]:
  779. group.widgets[1].resetLinesZValue()
  780. # ------------------------------------------------------------------------------------------------------------
  781. def redrawPluginGroup(plugin_id):
  782. group = canvas.group_plugin_map.get(plugin_id, None)
  783. if group is None:
  784. #qCritical("PatchCanvas::redrawPluginGroup(%i) - unable to find group" % plugin_id)
  785. return
  786. group.widgets[0].redrawInlineDisplay()
  787. if group.split and group.widgets[1]:
  788. group.widgets[1].redrawInlineDisplay()
  789. def handlePluginRemoved(plugin_id):
  790. if canvas.debug:
  791. print("PatchCanvas::handlePluginRemoved(%i)" % plugin_id)
  792. group = canvas.group_plugin_map.pop(plugin_id, None)
  793. if group is not None:
  794. group.plugin_id = -1
  795. group.plugin_ui = False
  796. group.plugin_inline = False
  797. group.widgets[0].removeAsPlugin()
  798. if group.split and group.widgets[1]:
  799. group.widgets[1].removeAsPlugin()
  800. for group in canvas.group_list:
  801. if group.plugin_id < plugin_id or group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
  802. continue
  803. group.plugin_id -= 1
  804. group.widgets[0].m_plugin_id -= 1
  805. if group.split and group.widgets[1]:
  806. group.widgets[1].m_plugin_id -= 1
  807. canvas.group_plugin_map[plugin_id] = group
  808. def handleAllPluginsRemoved():
  809. if canvas.debug:
  810. print("PatchCanvas::handleAllPluginsRemoved()")
  811. canvas.group_plugin_map = {}
  812. for group in canvas.group_list:
  813. if group.plugin_id < 0:
  814. continue
  815. if group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
  816. continue
  817. group.plugin_id = -1
  818. group.plugin_ui = False
  819. group.plugin_inline = False
  820. group.widgets[0].removeAsPlugin()
  821. if group.split and group.widgets[1]:
  822. group.widgets[1].removeAsPlugin()
  823. # ------------------------------------------------------------------------------------------------------------