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.

patchcanvas.py 29KB

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