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.

954 lines
32KB

  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.plugin_inline = False
  235. group_dict.widgets = [group_box, None]
  236. if split == SPLIT_YES:
  237. group_box.setSplit(True, PORT_MODE_OUTPUT)
  238. if features.handle_group_pos:
  239. group_box.setPos(getStoredCanvasPosition(group_name + "_OUTPUT", CanvasGetNewGroupPos(False)))
  240. else:
  241. group_box.setPos(CanvasGetNewGroupPos(False))
  242. group_sbox = CanvasBox(group_id, group_name, icon)
  243. group_sbox.setSplit(True, PORT_MODE_INPUT)
  244. group_dict.widgets[1] = group_sbox
  245. if features.handle_group_pos:
  246. group_sbox.setPos(getStoredCanvasPosition(group_name + "_INPUT", CanvasGetNewGroupPos(True)))
  247. else:
  248. group_sbox.setPos(CanvasGetNewGroupPos(True))
  249. canvas.last_z_value += 1
  250. group_sbox.setZValue(canvas.last_z_value)
  251. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  252. CanvasItemFX(group_sbox, True, False)
  253. group_sbox.checkItemPos()
  254. else:
  255. group_box.setSplit(False)
  256. if features.handle_group_pos:
  257. group_box.setPos(getStoredCanvasPosition(group_name, CanvasGetNewGroupPos(False)))
  258. else:
  259. # Special ladish fake-split groups
  260. horizontal = bool(icon == ICON_HARDWARE or icon == ICON_LADISH_ROOM)
  261. group_box.setPos(CanvasGetNewGroupPos(horizontal))
  262. group_box.checkItemPos()
  263. canvas.last_z_value += 1
  264. group_box.setZValue(canvas.last_z_value)
  265. canvas.group_list.append(group_dict)
  266. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  267. CanvasItemFX(group_box, True, False)
  268. return
  269. QTimer.singleShot(0, canvas.scene.update)
  270. def removeGroup(group_id):
  271. if canvas.debug:
  272. print("PatchCanvas::removeGroup(%i)" % group_id)
  273. for group in canvas.group_list:
  274. if group.group_id == group_id:
  275. item = group.widgets[0]
  276. group_name = group.group_name
  277. if group.split:
  278. s_item = group.widgets[1]
  279. if features.handle_group_pos:
  280. canvas.settings.setValue("CanvasPositions/%s_OUTPUT" % group_name, item.pos())
  281. canvas.settings.setValue("CanvasPositions/%s_INPUT" % group_name, s_item.pos())
  282. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_YES)
  283. if options.eyecandy == EYECANDY_FULL:
  284. CanvasItemFX(s_item, False, True)
  285. else:
  286. s_item.removeIconFromScene()
  287. canvas.scene.removeItem(s_item)
  288. del s_item
  289. else:
  290. if features.handle_group_pos:
  291. canvas.settings.setValue("CanvasPositions/%s" % group_name, item.pos())
  292. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_NO)
  293. if options.eyecandy == EYECANDY_FULL:
  294. CanvasItemFX(item, False, True)
  295. else:
  296. item.removeIconFromScene()
  297. canvas.scene.removeItem(item)
  298. del item
  299. canvas.group_list.remove(group)
  300. QTimer.singleShot(0, canvas.scene.update)
  301. return
  302. qCritical("PatchCanvas::removeGroup(%i) - unable to find group to remove" % group_id)
  303. def renameGroup(group_id, new_group_name):
  304. if canvas.debug:
  305. print("PatchCanvas::renameGroup(%i, %s)" % (group_id, new_group_name.encode()))
  306. for group in canvas.group_list:
  307. if group.group_id == group_id:
  308. group.group_name = new_group_name
  309. group.widgets[0].setGroupName(new_group_name)
  310. if group.split and group.widgets[1]:
  311. group.widgets[1].setGroupName(new_group_name)
  312. QTimer.singleShot(0, canvas.scene.update)
  313. return
  314. qCritical("PatchCanvas::renameGroup(%i, %s) - unable to find group to rename" % (group_id, new_group_name.encode()))
  315. def splitGroup(group_id):
  316. if canvas.debug:
  317. print("PatchCanvas::splitGroup(%i)" % group_id)
  318. item = None
  319. group_name = ""
  320. group_icon = ICON_APPLICATION
  321. plugin_id = -1
  322. plugin_ui = False
  323. plugin_inline = False
  324. ports_data = []
  325. conns_data = []
  326. # Step 1 - Store all Item data
  327. for group in canvas.group_list:
  328. if group.group_id == group_id:
  329. if group.split:
  330. qCritical("PatchCanvas::splitGroup(%i) - group is already splitted" % group_id)
  331. return
  332. item = group.widgets[0]
  333. group_name = group.group_name
  334. group_icon = group.icon
  335. plugin_id = group.plugin_id
  336. plugin_ui = group.plugin_ui
  337. plugin_inline = group.plugin_inline
  338. break
  339. if not item:
  340. qCritical("PatchCanvas::splitGroup(%i) - unable to find group to split" % group_id)
  341. return
  342. port_list_ids = list(item.getPortList())
  343. for port in canvas.port_list:
  344. if port.port_id in port_list_ids:
  345. port_dict = port_dict_t()
  346. port_dict.group_id = port.group_id
  347. port_dict.port_id = port.port_id
  348. port_dict.port_name = port.port_name
  349. port_dict.port_mode = port.port_mode
  350. port_dict.port_type = port.port_type
  351. port_dict.is_alternate = port.is_alternate
  352. port_dict.widget = None
  353. ports_data.append(port_dict)
  354. for connection in canvas.connection_list:
  355. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  356. connection_dict = connection_dict_t()
  357. connection_dict.connection_id = connection.connection_id
  358. connection_dict.group_in_id = connection.group_in_id
  359. connection_dict.port_in_id = connection.port_in_id
  360. connection_dict.group_out_id = connection.group_out_id
  361. connection_dict.port_out_id = connection.port_out_id
  362. connection_dict.widget = None
  363. conns_data.append(connection_dict)
  364. # Step 2 - Remove Item and Children
  365. for conn in conns_data:
  366. disconnectPorts(conn.connection_id)
  367. for port_id in port_list_ids:
  368. removePort(group_id, port_id)
  369. removeGroup(group_id)
  370. # Step 3 - Re-create Item, now splitted
  371. addGroup(group_id, group_name, SPLIT_YES, group_icon)
  372. if plugin_id >= 0:
  373. setGroupAsPlugin(group_id, plugin_id, plugin_ui, plugin_inline)
  374. for port in ports_data:
  375. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
  376. for conn in conns_data:
  377. connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id)
  378. QTimer.singleShot(0, canvas.scene.update)
  379. def joinGroup(group_id):
  380. if canvas.debug:
  381. print("PatchCanvas::joinGroup(%i)" % group_id)
  382. item = None
  383. s_item = None
  384. group_name = ""
  385. group_icon = ICON_APPLICATION
  386. plugin_id = -1
  387. plugin_ui = False
  388. plugin_inline = False
  389. ports_data = []
  390. conns_data = []
  391. # Step 1 - Store all Item data
  392. for group in canvas.group_list:
  393. if group.group_id == group_id:
  394. if not group.split:
  395. qCritical("PatchCanvas::joinGroup(%i) - group is not splitted" % group_id)
  396. return
  397. item = group.widgets[0]
  398. s_item = group.widgets[1]
  399. group_name = group.group_name
  400. group_icon = group.icon
  401. plugin_id = group.plugin_id
  402. plugin_ui = group.plugin_ui
  403. plugin_inline = group.plugin_inline
  404. break
  405. # FIXME
  406. if not (item and s_item):
  407. qCritical("PatchCanvas::joinGroup(%i) - unable to find groups to join" % group_id)
  408. return
  409. port_list_ids = list(item.getPortList())
  410. port_list_idss = s_item.getPortList()
  411. for port_id in port_list_idss:
  412. if port_id not in port_list_ids:
  413. port_list_ids.append(port_id)
  414. for port in canvas.port_list:
  415. if port.port_id in port_list_ids:
  416. port_dict = port_dict_t()
  417. port_dict.group_id = port.group_id
  418. port_dict.port_id = port.port_id
  419. port_dict.port_name = port.port_name
  420. port_dict.port_mode = port.port_mode
  421. port_dict.port_type = port.port_type
  422. port_dict.is_alternate = port.is_alternate
  423. port_dict.widget = None
  424. ports_data.append(port_dict)
  425. for connection in canvas.connection_list:
  426. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  427. connection_dict = connection_dict_t()
  428. connection_dict.connection_id = connection.connection_id
  429. connection_dict.group_in_id = connection.group_in_id
  430. connection_dict.port_in_id = connection.port_in_id
  431. connection_dict.group_out_id = connection.group_out_id
  432. connection_dict.port_out_id = connection.port_out_id
  433. connection_dict.widget = None
  434. conns_data.append(connection_dict)
  435. # Step 2 - Remove Item and Children
  436. for conn in conns_data:
  437. disconnectPorts(conn.connection_id)
  438. for port_id in port_list_ids:
  439. removePort(group_id, port_id)
  440. removeGroup(group_id)
  441. # Step 3 - Re-create Item, now together
  442. addGroup(group_id, group_name, SPLIT_NO, group_icon)
  443. if plugin_id >= 0:
  444. setGroupAsPlugin(group_id, plugin_id, plugin_ui, plugin_inline)
  445. for port in ports_data:
  446. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type, port.is_alternate)
  447. for conn in conns_data:
  448. connectPorts(conn.connection_id, conn.group_out_id, conn.port_out_id, conn.group_in_id, conn.port_in_id)
  449. QTimer.singleShot(0, canvas.scene.update)
  450. # ------------------------------------------------------------------------------------------------------------
  451. def getGroupPos(group_id, port_mode=PORT_MODE_OUTPUT):
  452. if canvas.debug:
  453. print("PatchCanvas::getGroupPos(%i, %s)" % (group_id, port_mode2str(port_mode)))
  454. for group in canvas.group_list:
  455. if group.group_id == group_id:
  456. return group.widgets[1 if (group.split and port_mode == PORT_MODE_INPUT) else 0].pos()
  457. qCritical("PatchCanvas::getGroupPos(%i, %s) - unable to find group" % (group_id, port_mode2str(port_mode)))
  458. return QPointF(0, 0)
  459. def saveGroupPositions():
  460. if canvas.debug:
  461. print("PatchCanvas::getGroupPositions()")
  462. ret = []
  463. for group in canvas.group_list:
  464. if group.split:
  465. pos1 = group.widgets[0].pos()
  466. pos2 = group.widgets[1].pos()
  467. else:
  468. pos1 = group.widgets[0].pos()
  469. pos2 = QPointF(0, 0)
  470. ret.append({
  471. "name" : group.group_name,
  472. "pos1x": pos1.x(),
  473. "pos1y": pos1.y(),
  474. "pos2x": pos2.x(),
  475. "pos2y": pos2.y(),
  476. "split": group.split,
  477. })
  478. return ret
  479. def restoreGroupPositions(dataList):
  480. if canvas.debug:
  481. print("PatchCanvas::restoreGroupPositions(...)")
  482. mapping = {}
  483. for group in canvas.group_list:
  484. mapping[group.group_name] = group
  485. for data in dataList:
  486. name = data['name']
  487. group = mapping.get(name, None)
  488. if group is None:
  489. continue
  490. group.widgets[0].setPos(data['pos1x'], data['pos1y'])
  491. if group.split and group.widgets[1]:
  492. group.widgets[1].setPos(data['pos2x'], data['pos2y'])
  493. def setGroupPos(group_id, group_pos_x, group_pos_y):
  494. setGroupPosFull(group_id, group_pos_x, group_pos_y, group_pos_x, group_pos_y)
  495. def setGroupPosFull(group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i):
  496. if canvas.debug:
  497. print("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i)" % (
  498. group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  499. for group in canvas.group_list:
  500. if group.group_id == group_id:
  501. group.widgets[0].setPos(group_pos_x_o, group_pos_y_o)
  502. if group.split and group.widgets[1]:
  503. group.widgets[1].setPos(group_pos_x_i, group_pos_y_i)
  504. QTimer.singleShot(0, canvas.scene.update)
  505. return
  506. qCritical("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i) - unable to find group to reposition" % (
  507. group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  508. # ------------------------------------------------------------------------------------------------------------
  509. def setGroupIcon(group_id, icon):
  510. if canvas.debug:
  511. print("PatchCanvas::setGroupIcon(%i, %s)" % (group_id, icon2str(icon)))
  512. for group in canvas.group_list:
  513. if group.group_id == group_id:
  514. group.icon = icon
  515. group.widgets[0].setIcon(icon)
  516. if group.split and group.widgets[1]:
  517. group.widgets[1].setIcon(icon)
  518. QTimer.singleShot(0, canvas.scene.update)
  519. return
  520. qCritical("PatchCanvas::setGroupIcon(%i, %s) - unable to find group to change icon" % (group_id, icon2str(icon)))
  521. def setGroupAsPlugin(group_id, plugin_id, hasUI, hasInlineDisplay):
  522. if canvas.debug:
  523. print("PatchCanvas::setGroupAsPlugin(%i, %i, %s, %s)" % (
  524. group_id, plugin_id, bool2str(hasUI), bool2str(hasInlineDisplay)))
  525. for group in canvas.group_list:
  526. if group.group_id == group_id:
  527. group.plugin_id = plugin_id
  528. group.plugin_ui = hasUI
  529. group.plugin_inline = hasInlineDisplay
  530. group.widgets[0].setAsPlugin(plugin_id, hasUI, hasInlineDisplay)
  531. if group.split and group.widgets[1]:
  532. group.widgets[1].setAsPlugin(plugin_id, hasUI, hasInlineDisplay)
  533. return
  534. qCritical("PatchCanvas::setGroupAsPlugin(%i, %i, %s, %s) - unable to find group to set as plugin" % (
  535. group_id, plugin_id, bool2str(hasUI), bool2str(hasInlineDisplay)))
  536. def redrawPluginGroup(plugin_id):
  537. for group in canvas.group_list:
  538. if group.plugin_id == plugin_id:
  539. group.widgets[0].update()
  540. if group.split and group.widgets[1]:
  541. group.widgets[1].update()
  542. return
  543. qCritical("PatchCanvas::redrawPluginGroup(%i) - unable to find group" % plugin_id)
  544. # ------------------------------------------------------------------------------------------------------------
  545. def addPort(group_id, port_id, port_name, port_mode, port_type, is_alternate=False):
  546. if canvas.debug:
  547. print("PatchCanvas::addPort(%i, %i, %s, %s, %s, %s)" % (
  548. group_id, port_id, port_name.encode(),
  549. port_mode2str(port_mode), port_type2str(port_type), bool2str(is_alternate)))
  550. for port in canvas.port_list:
  551. if port.group_id == group_id and port.port_id == port_id:
  552. qWarning("PatchCanvas::addPort(%i, %i, %s, %s, %s) - port already exists" % (
  553. group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  554. return
  555. box_widget = None
  556. port_widget = None
  557. for group in canvas.group_list:
  558. if group.group_id == group_id:
  559. if group.split and group.widgets[0].getSplittedMode() != port_mode and group.widgets[1]:
  560. n = 1
  561. else:
  562. n = 0
  563. box_widget = group.widgets[n]
  564. port_widget = box_widget.addPortFromGroup(port_id, port_mode, port_type, port_name, is_alternate)
  565. break
  566. if not (box_widget and port_widget):
  567. qCritical("PatchCanvas::addPort(%i, %i, %s, %s, %s) - Unable to find parent group" % (
  568. group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  569. return
  570. port_dict = port_dict_t()
  571. port_dict.group_id = group_id
  572. port_dict.port_id = port_id
  573. port_dict.port_name = port_name
  574. port_dict.port_mode = port_mode
  575. port_dict.port_type = port_type
  576. port_dict.is_alternate = is_alternate
  577. port_dict.widget = port_widget
  578. canvas.port_list.append(port_dict)
  579. box_widget.updatePositions()
  580. if options.eyecandy == EYECANDY_FULL:
  581. CanvasItemFX(port_widget, True, False)
  582. return
  583. QTimer.singleShot(0, canvas.scene.update)
  584. def removePort(group_id, port_id):
  585. if canvas.debug:
  586. print("PatchCanvas::removePort(%i, %i)" % (group_id, port_id))
  587. for port in canvas.port_list:
  588. if port.group_id == group_id and port.port_id == port_id:
  589. item = port.widget
  590. item.parentItem().removePortFromGroup(port_id)
  591. canvas.scene.removeItem(item)
  592. canvas.port_list.remove(port)
  593. del item
  594. QTimer.singleShot(0, canvas.scene.update)
  595. return
  596. qCritical("PatchCanvas::removePort(%i, %i) - Unable to find port to remove" % (group_id, port_id))
  597. def renamePort(group_id, port_id, new_port_name):
  598. if canvas.debug:
  599. print("PatchCanvas::renamePort(%i, %i, %s)" % (group_id, port_id, new_port_name.encode()))
  600. for port in canvas.port_list:
  601. if port.group_id == group_id and port.port_id == port_id:
  602. port.port_name = new_port_name
  603. port.widget.setPortName(new_port_name)
  604. port.widget.parentItem().updatePositions()
  605. QTimer.singleShot(0, canvas.scene.update)
  606. return
  607. qCritical("PatchCanvas::renamePort(%i, %i, %s) - Unable to find port to rename" % (
  608. group_id, port_id, new_port_name.encode()))
  609. def connectPorts(connection_id, group_out_id, port_out_id, group_in_id, port_in_id):
  610. if canvas.debug:
  611. print("PatchCanvas::connectPorts(%i, %i, %i, %i, %i)" % (
  612. connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
  613. port_out = None
  614. port_in = None
  615. port_out_parent = None
  616. port_in_parent = None
  617. for port in canvas.port_list:
  618. if port.group_id == group_out_id and port.port_id == port_out_id:
  619. port_out = port.widget
  620. port_out_parent = port_out.parentItem()
  621. elif port.group_id == group_in_id and port.port_id == port_in_id:
  622. port_in = port.widget
  623. port_in_parent = port_in.parentItem()
  624. # FIXME
  625. if not (port_out and port_in):
  626. qCritical("PatchCanvas::connectPorts(%i, %i, %i, %i, %i) - unable to find ports to connect" % (
  627. connection_id, group_out_id, port_out_id, group_in_id, port_in_id))
  628. return
  629. connection_dict = connection_dict_t()
  630. connection_dict.connection_id = connection_id
  631. connection_dict.group_in_id = group_in_id
  632. connection_dict.port_in_id = port_in_id
  633. connection_dict.group_out_id = group_out_id
  634. connection_dict.port_out_id = port_out_id
  635. if options.use_bezier_lines:
  636. connection_dict.widget = CanvasBezierLine(port_out, port_in, None)
  637. else:
  638. connection_dict.widget = CanvasLine(port_out, port_in, None)
  639. canvas.scene.addItem(connection_dict.widget)
  640. port_out_parent.addLineFromGroup(connection_dict.widget, connection_id)
  641. port_in_parent.addLineFromGroup(connection_dict.widget, connection_id)
  642. canvas.last_z_value += 1
  643. port_out_parent.setZValue(canvas.last_z_value)
  644. port_in_parent.setZValue(canvas.last_z_value)
  645. canvas.last_z_value += 1
  646. connection_dict.widget.setZValue(canvas.last_z_value)
  647. canvas.connection_list.append(connection_dict)
  648. if options.eyecandy == EYECANDY_FULL:
  649. item = connection_dict.widget
  650. CanvasItemFX(item, True, False)
  651. return
  652. QTimer.singleShot(0, canvas.scene.update)
  653. def disconnectPorts(connection_id):
  654. if canvas.debug:
  655. print("PatchCanvas::disconnectPorts(%i)" % connection_id)
  656. line = None
  657. item1 = None
  658. item2 = None
  659. group1id = port1id = 0
  660. group2id = port2id = 0
  661. for connection in canvas.connection_list:
  662. if connection.connection_id == connection_id:
  663. group1id = connection.group_out_id
  664. group2id = connection.group_in_id
  665. port1id = connection.port_out_id
  666. port2id = connection.port_in_id
  667. line = connection.widget
  668. canvas.connection_list.remove(connection)
  669. break
  670. if not line:
  671. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find connection ports" % connection_id)
  672. return
  673. for port in canvas.port_list:
  674. if port.group_id == group1id and port.port_id == port1id:
  675. item1 = port.widget
  676. break
  677. if not item1:
  678. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find output port" % connection_id)
  679. return
  680. for port in canvas.port_list:
  681. if port.group_id == group2id and port.port_id == port2id:
  682. item2 = port.widget
  683. break
  684. if not item2:
  685. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find input port" % connection_id)
  686. return
  687. item1.parentItem().removeLineFromGroup(connection_id)
  688. item2.parentItem().removeLineFromGroup(connection_id)
  689. if options.eyecandy == EYECANDY_FULL:
  690. CanvasItemFX(line, False, True)
  691. return
  692. canvas.scene.removeItem(line)
  693. del line
  694. QTimer.singleShot(0, canvas.scene.update)
  695. # ------------------------------------------------------------------------------------------------------------
  696. def arrange():
  697. if canvas.debug:
  698. print("PatchCanvas::arrange()")
  699. # ------------------------------------------------------------------------------------------------------------
  700. def updateZValues():
  701. if canvas.debug:
  702. print("PatchCanvas::updateZValues()")
  703. for group in canvas.group_list:
  704. group.widgets[0].resetLinesZValue()
  705. if group.split and group.widgets[1]:
  706. group.widgets[1].resetLinesZValue()
  707. # ------------------------------------------------------------------------------------------------------------
  708. def handlePluginRemoved(plugin_id):
  709. if canvas.debug:
  710. print("PatchCanvas::handlePluginRemoved(%i)" % plugin_id)
  711. for group in canvas.group_list:
  712. if group.plugin_id < plugin_id or group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
  713. continue
  714. group.plugin_id -= 1
  715. group.widgets[0].m_plugin_id -= 1
  716. if group.split and group.widgets[1]:
  717. group.widgets[1].m_plugin_id -= 1
  718. def handleAllPluginsRemoved():
  719. if canvas.debug:
  720. print("PatchCanvas::handleAllPluginsRemoved()")
  721. for group in canvas.group_list:
  722. if group.plugin_id > MAX_PLUGIN_ID_ALLOWED:
  723. continue
  724. group.plugin_id = -1
  725. group.plugin_ui = False
  726. group.plugin_inline = False
  727. group.widgets[0].m_plugin_id = -1
  728. group.widgets[0].m_plugin_ui = False
  729. group.widgets[0].m_plugin_inline = False
  730. if group.split and group.widgets[1]:
  731. group.widgets[1].m_plugin_id = -1
  732. group.widgets[1].m_plugin_ui = False
  733. group.widgets[1].m_plugin_inline = False
  734. # ------------------------------------------------------------------------------------------------------------