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.

2792 lines
97KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # PatchBay Canvas engine using QGraphicsView/Scene
  4. # Copyright (C) 2010-2014 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 (Config)
  19. from carla_config import *
  20. # ------------------------------------------------------------------------------------------------------------
  21. # Imports (Global)
  22. if config_UseQt5:
  23. from PyQt5.QtCore import pyqtSignal, pyqtSlot, qDebug, qCritical, qFatal, qWarning, Qt, QObject
  24. from PyQt5.QtCore import QAbstractAnimation, QLineF, QPointF, QRectF, QSizeF, QSettings, QTimer
  25. from PyQt5.QtGui import QColor, QLinearGradient, QPen, QPolygonF, QPainter, QPainterPath
  26. from PyQt5.QtGui import QCursor, QFont, QFontMetrics
  27. from PyQt5.QtSvg import QGraphicsSvgItem, QSvgRenderer
  28. from PyQt5.QtWidgets import QGraphicsScene, QGraphicsItem, QGraphicsLineItem, QGraphicsPathItem
  29. from PyQt5.QtWidgets import QGraphicsColorizeEffect, QGraphicsDropShadowEffect
  30. from PyQt5.QtWidgets import QInputDialog, QLineEdit, QMenu
  31. else:
  32. from PyQt4.QtCore import pyqtSignal, pyqtSlot, qDebug, qCritical, qFatal, qWarning, Qt, QObject
  33. from PyQt4.QtCore import QAbstractAnimation, QLineF, QPointF, QRectF, QSizeF, QSettings, QTimer
  34. from PyQt4.QtGui import QColor, QLinearGradient, QPen, QPolygonF, QPainter, QPainterPath
  35. from PyQt4.QtGui import QCursor, QFont, QFontMetrics
  36. from PyQt4.QtGui import QGraphicsScene, QGraphicsItem, QGraphicsLineItem, QGraphicsPathItem
  37. from PyQt4.QtGui import QGraphicsColorizeEffect, QGraphicsDropShadowEffect
  38. from PyQt4.QtGui import QInputDialog, QLineEdit, QMenu
  39. from PyQt4.QtSvg import QGraphicsSvgItem, QSvgRenderer
  40. # ------------------------------------------------------------------------------------------------------------
  41. # Imports (Theme)
  42. from patchcanvas_theme import *
  43. # ------------------------------------------------------------------------------
  44. # patchcanvas-api.h
  45. # Port Mode
  46. PORT_MODE_NULL = 0
  47. PORT_MODE_INPUT = 1
  48. PORT_MODE_OUTPUT = 2
  49. # Port Type
  50. PORT_TYPE_NULL = 0
  51. PORT_TYPE_AUDIO_JACK = 1
  52. PORT_TYPE_MIDI_JACK = 2
  53. PORT_TYPE_MIDI_A2J = 3
  54. PORT_TYPE_MIDI_ALSA = 4
  55. # Callback Action
  56. ACTION_GROUP_INFO = 0 # group_id, N, N
  57. ACTION_GROUP_RENAME = 1 # group_id, N, new_name
  58. ACTION_GROUP_SPLIT = 2 # group_id, N, N
  59. ACTION_GROUP_JOIN = 3 # group_id, N, N
  60. ACTION_PORT_INFO = 4 # port_id, N, N
  61. ACTION_PORT_RENAME = 5 # port_id, N, new_name
  62. ACTION_PORTS_CONNECT = 6 # out_id, in_id, N
  63. ACTION_PORTS_DISCONNECT = 7 # conn_id, N, N
  64. ACTION_PLUGIN_CLONE = 8 # plugin_id, N, N
  65. ACTION_PLUGIN_EDIT = 9 # plugin_id, N, N
  66. ACTION_PLUGIN_RENAME = 10 # plugin_id, N, N
  67. ACTION_PLUGIN_REMOVE = 11 # plugin_id, N, N
  68. ACTION_PLUGIN_SHOW_UI = 12 # plugin_id, N, new_name
  69. # Icon
  70. ICON_APPLICATION = 0
  71. ICON_HARDWARE = 1
  72. ICON_DISTRHO = 2
  73. ICON_FILE = 3
  74. ICON_PLUGIN = 4
  75. ICON_LADISH_ROOM = 5
  76. # Split Option
  77. SPLIT_UNDEF = 0
  78. SPLIT_NO = 1
  79. SPLIT_YES = 2
  80. # Antialiasing Option
  81. ANTIALIASING_NONE = 0
  82. ANTIALIASING_SMALL = 1
  83. ANTIALIASING_FULL = 2
  84. # Eye-Candy Option
  85. EYECANDY_NONE = 0
  86. EYECANDY_SMALL = 1
  87. EYECANDY_FULL = 2
  88. # Canvas options
  89. class options_t(object):
  90. __slots__ = [
  91. 'theme_name',
  92. 'auto_hide_groups',
  93. 'use_bezier_lines',
  94. 'antialiasing',
  95. 'eyecandy'
  96. ]
  97. # Canvas features
  98. class features_t(object):
  99. __slots__ = [
  100. 'group_info',
  101. 'group_rename',
  102. 'port_info',
  103. 'port_rename',
  104. 'handle_group_pos'
  105. ]
  106. # ------------------------------------------------------------------------------
  107. # patchcanvas.h
  108. # object types
  109. CanvasBoxType = QGraphicsItem.UserType + 1
  110. CanvasIconType = QGraphicsItem.UserType + 2
  111. CanvasPortType = QGraphicsItem.UserType + 3
  112. CanvasLineType = QGraphicsItem.UserType + 4
  113. CanvasBezierLineType = QGraphicsItem.UserType + 5
  114. CanvasLineMovType = QGraphicsItem.UserType + 6
  115. CanvasBezierLineMovType = QGraphicsItem.UserType + 7
  116. # object lists
  117. class group_dict_t(object):
  118. __slots__ = [
  119. 'group_id',
  120. 'group_name',
  121. 'split',
  122. 'icon',
  123. 'widgets'
  124. ]
  125. class port_dict_t(object):
  126. __slots__ = [
  127. 'group_id',
  128. 'port_id',
  129. 'port_name',
  130. 'port_mode',
  131. 'port_type',
  132. 'widget'
  133. ]
  134. class connection_dict_t(object):
  135. __slots__ = [
  136. 'connection_id',
  137. 'port_in_id',
  138. 'port_out_id',
  139. 'widget'
  140. ]
  141. class animation_dict_t(object):
  142. __slots__ = [
  143. 'animation',
  144. 'item'
  145. ]
  146. # Main Canvas object
  147. class Canvas(object):
  148. __slots__ = [
  149. 'scene',
  150. 'callback',
  151. 'debug',
  152. 'last_z_value',
  153. 'last_connection_id',
  154. 'initial_pos',
  155. 'size_rect',
  156. 'group_list',
  157. 'port_list',
  158. 'connection_list',
  159. 'animation_list',
  160. 'qobject',
  161. 'settings',
  162. 'theme',
  163. 'initiated'
  164. ]
  165. # ------------------------------------------------------------------------------
  166. # patchcanvas.cpp
  167. class CanvasObject(QObject):
  168. def __init__(self, parent=None):
  169. QObject.__init__(self, parent)
  170. @pyqtSlot()
  171. def AnimationIdle(self):
  172. animation = self.sender()
  173. if animation:
  174. CanvasRemoveAnimation(animation)
  175. @pyqtSlot()
  176. def AnimationHide(self):
  177. animation = self.sender()
  178. if animation:
  179. item = animation.item()
  180. if item:
  181. item.hide()
  182. CanvasRemoveAnimation(animation)
  183. @pyqtSlot()
  184. def AnimationDestroy(self):
  185. animation = self.sender()
  186. if animation:
  187. item = animation.item()
  188. if item:
  189. CanvasRemoveItemFX(item)
  190. CanvasRemoveAnimation(animation)
  191. @pyqtSlot()
  192. def PortContextMenuDisconnect(self):
  193. try:
  194. connectionId = int(self.sender().data())
  195. except:
  196. return
  197. CanvasCallback(ACTION_PORTS_DISCONNECT, connectionId, 0, "")
  198. # Global objects
  199. canvas = Canvas()
  200. canvas.qobject = None
  201. canvas.settings = None
  202. canvas.theme = None
  203. canvas.initiated = False
  204. canvas.group_list = []
  205. canvas.port_list = []
  206. canvas.connection_list = []
  207. canvas.animation_list = []
  208. options = options_t()
  209. options.theme_name = getDefaultThemeName()
  210. options.auto_hide_groups = False
  211. options.use_bezier_lines = True
  212. options.antialiasing = ANTIALIASING_SMALL
  213. options.eyecandy = EYECANDY_SMALL
  214. features = features_t()
  215. features.group_info = False
  216. features.group_rename = False
  217. features.port_info = False
  218. features.port_rename = False
  219. features.handle_group_pos = False
  220. # Internal functions
  221. def bool2str(check):
  222. return "True" if check else "False"
  223. def port_mode2str(port_mode):
  224. if port_mode == PORT_MODE_NULL:
  225. return "PORT_MODE_NULL"
  226. elif port_mode == PORT_MODE_INPUT:
  227. return "PORT_MODE_INPUT"
  228. elif port_mode == PORT_MODE_OUTPUT:
  229. return "PORT_MODE_OUTPUT"
  230. else:
  231. return "PORT_MODE_???"
  232. def port_type2str(port_type):
  233. if port_type == PORT_TYPE_NULL:
  234. return "PORT_TYPE_NULL"
  235. elif port_type == PORT_TYPE_AUDIO_JACK:
  236. return "PORT_TYPE_AUDIO_JACK"
  237. elif port_type == PORT_TYPE_MIDI_JACK:
  238. return "PORT_TYPE_MIDI_JACK"
  239. elif port_type == PORT_TYPE_MIDI_A2J:
  240. return "PORT_TYPE_MIDI_A2J"
  241. elif port_type == PORT_TYPE_MIDI_ALSA:
  242. return "PORT_TYPE_MIDI_ALSA"
  243. else:
  244. return "PORT_TYPE_???"
  245. def icon2str(icon):
  246. if icon == ICON_APPLICATION:
  247. return "ICON_APPLICATION"
  248. elif icon == ICON_HARDWARE:
  249. return "ICON_HARDWARE"
  250. elif icon == ICON_DISTRHO:
  251. return "ICON_DISTRHO"
  252. elif icon == ICON_FILE:
  253. return "ICON_FILE"
  254. elif icon == ICON_PLUGIN:
  255. return "ICON_PLUGIN"
  256. elif icon == ICON_LADISH_ROOM:
  257. return "ICON_LADISH_ROOM"
  258. else:
  259. return "ICON_???"
  260. def split2str(split):
  261. if split == SPLIT_UNDEF:
  262. return "SPLIT_UNDEF"
  263. elif split == SPLIT_NO:
  264. return "SPLIT_NO"
  265. elif split == SPLIT_YES:
  266. return "SPLIT_YES"
  267. else:
  268. return "SPLIT_???"
  269. # PatchCanvas API
  270. def setOptions(new_options):
  271. if canvas.initiated: return
  272. options.theme_name = new_options.theme_name
  273. options.auto_hide_groups = new_options.auto_hide_groups
  274. options.use_bezier_lines = new_options.use_bezier_lines
  275. options.antialiasing = new_options.antialiasing
  276. options.eyecandy = new_options.eyecandy
  277. def setFeatures(new_features):
  278. if canvas.initiated: return
  279. features.group_info = new_features.group_info
  280. features.group_rename = new_features.group_rename
  281. features.port_info = new_features.port_info
  282. features.port_rename = new_features.port_rename
  283. features.handle_group_pos = new_features.handle_group_pos
  284. def init(appName, scene, callback, debug=False):
  285. if debug:
  286. qDebug("PatchCanvas::init(\"%s\", %s, %s, %s)" % (appName, scene, callback, bool2str(debug)))
  287. if canvas.initiated:
  288. qCritical("PatchCanvas::init() - already initiated")
  289. return
  290. if not callback:
  291. qFatal("PatchCanvas::init() - fatal error: callback not set")
  292. return
  293. canvas.scene = scene
  294. canvas.callback = callback
  295. canvas.debug = debug
  296. canvas.last_z_value = 0
  297. canvas.last_connection_id = 0
  298. canvas.initial_pos = QPointF(0, 0)
  299. canvas.size_rect = QRectF()
  300. if not canvas.qobject: canvas.qobject = CanvasObject()
  301. if not canvas.settings: canvas.settings = QSettings("falkTX", appName)
  302. if canvas.theme:
  303. del canvas.theme
  304. canvas.theme = None
  305. for i in range(Theme.THEME_MAX):
  306. this_theme_name = getThemeName(i)
  307. if this_theme_name == options.theme_name:
  308. canvas.theme = Theme(i)
  309. break
  310. if not canvas.theme:
  311. canvas.theme = Theme(getDefaultTheme())
  312. canvas.scene.updateTheme()
  313. canvas.initiated = True
  314. def clear():
  315. if canvas.debug:
  316. qDebug("PatchCanvas::clear()")
  317. group_list_ids = []
  318. port_list_ids = []
  319. connection_list_ids = []
  320. for group in canvas.group_list:
  321. group_list_ids.append(group.group_id)
  322. for port in canvas.port_list:
  323. port_list_ids.append(port.port_id)
  324. for connection in canvas.connection_list:
  325. connection_list_ids.append(connection.connection_id)
  326. for idx in connection_list_ids:
  327. disconnectPorts(idx)
  328. for idx in port_list_ids:
  329. removePort(idx)
  330. for idx in group_list_ids:
  331. removeGroup(idx)
  332. canvas.last_z_value = 0
  333. canvas.last_connection_id = 0
  334. canvas.group_list = []
  335. canvas.port_list = []
  336. canvas.connection_list = []
  337. canvas.scene.clear()
  338. canvas.initiated = False
  339. def setInitialPos(x, y):
  340. if canvas.debug:
  341. qDebug("PatchCanvas::setInitialPos(%i, %i)" % (x, y))
  342. canvas.initial_pos.setX(x)
  343. canvas.initial_pos.setY(y)
  344. def setCanvasSize(x, y, width, height):
  345. if canvas.debug:
  346. qDebug("PatchCanvas::setCanvasSize(%i, %i, %i, %i)" % (x, y, width, height))
  347. canvas.size_rect.setX(x)
  348. canvas.size_rect.setY(y)
  349. canvas.size_rect.setWidth(width)
  350. canvas.size_rect.setHeight(height)
  351. def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):
  352. if canvas.debug:
  353. qDebug("PatchCanvas::addGroup(%i, %s, %s, %s)" % (group_id, group_name.encode(), split2str(split), icon2str(icon)))
  354. for group in canvas.group_list:
  355. if group.group_id == group_id:
  356. qWarning("PatchCanvas::addGroup(%i, %s, %s, %s) - group already exists" % (group_id, group_name.encode(), split2str(split), icon2str(icon)))
  357. return
  358. if split == SPLIT_UNDEF:
  359. isHardware = bool(icon == ICON_HARDWARE)
  360. if features.handle_group_pos:
  361. split = canvas.settings.value("CanvasPositions/%s_SPLIT" % group_name, SPLIT_YES if isHardware else split, type=int)
  362. elif isHardware:
  363. split = SPLIT_YES
  364. group_box = CanvasBox(group_id, group_name, icon)
  365. group_dict = group_dict_t()
  366. group_dict.group_id = group_id
  367. group_dict.group_name = group_name
  368. group_dict.split = bool(split == SPLIT_YES)
  369. group_dict.icon = icon
  370. group_dict.widgets = [group_box, None]
  371. if split == SPLIT_YES:
  372. group_box.setSplit(True, PORT_MODE_OUTPUT)
  373. if features.handle_group_pos:
  374. group_box.setPos(canvas.settings.value("CanvasPositions/%s_OUTPUT" % group_name, CanvasGetNewGroupPos(), type=QPointF))
  375. else:
  376. group_box.setPos(CanvasGetNewGroupPos())
  377. group_sbox = CanvasBox(group_id, group_name, icon)
  378. group_sbox.setSplit(True, PORT_MODE_INPUT)
  379. group_dict.widgets[1] = group_sbox
  380. if features.handle_group_pos:
  381. group_sbox.setPos(canvas.settings.value("CanvasPositions/%s_INPUT" % group_name, CanvasGetNewGroupPos(True), type=QPointF))
  382. else:
  383. group_sbox.setPos(CanvasGetNewGroupPos(True))
  384. canvas.last_z_value += 1
  385. group_sbox.setZValue(canvas.last_z_value)
  386. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  387. CanvasItemFX(group_sbox, True)
  388. group_sbox.checkItemPos()
  389. else:
  390. group_box.setSplit(False)
  391. if features.handle_group_pos:
  392. group_box.setPos(canvas.settings.value("CanvasPositions/%s" % group_name, CanvasGetNewGroupPos(), type=QPointF))
  393. else:
  394. # Special ladish fake-split groups
  395. horizontal = bool(icon == ICON_HARDWARE or icon == ICON_LADISH_ROOM)
  396. group_box.setPos(CanvasGetNewGroupPos(horizontal))
  397. group_box.checkItemPos()
  398. canvas.last_z_value += 1
  399. group_box.setZValue(canvas.last_z_value)
  400. canvas.group_list.append(group_dict)
  401. if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:
  402. CanvasItemFX(group_box, True)
  403. QTimer.singleShot(0, canvas.scene.update)
  404. def removeGroup(group_id):
  405. if canvas.debug:
  406. qDebug("PatchCanvas::removeGroup(%i)" % group_id)
  407. for group in canvas.group_list:
  408. if group.group_id == group_id:
  409. item = group.widgets[0]
  410. group_name = group.group_name
  411. if group.split:
  412. s_item = group.widgets[1]
  413. if features.handle_group_pos:
  414. canvas.settings.setValue("CanvasPositions/%s_OUTPUT" % group_name, item.pos())
  415. canvas.settings.setValue("CanvasPositions/%s_INPUT" % group_name, s_item.pos())
  416. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_YES)
  417. if options.eyecandy == EYECANDY_FULL:
  418. CanvasItemFX(s_item, False, True)
  419. else:
  420. s_item.removeIconFromScene()
  421. canvas.scene.removeItem(s_item)
  422. del s_item
  423. else:
  424. if features.handle_group_pos:
  425. canvas.settings.setValue("CanvasPositions/%s" % group_name, item.pos())
  426. canvas.settings.setValue("CanvasPositions/%s_SPLIT" % group_name, SPLIT_NO)
  427. if options.eyecandy == EYECANDY_FULL:
  428. CanvasItemFX(item, False, True)
  429. else:
  430. item.removeIconFromScene()
  431. canvas.scene.removeItem(item)
  432. del item
  433. canvas.group_list.remove(group)
  434. QTimer.singleShot(0, canvas.scene.update)
  435. return
  436. qCritical("PatchCanvas::removeGroup(%i) - unable to find group to remove" % group_id)
  437. def renameGroup(group_id, new_group_name):
  438. if canvas.debug:
  439. qDebug("PatchCanvas::renameGroup(%i, %s)" % (group_id, new_group_name.encode()))
  440. for group in canvas.group_list:
  441. if group.group_id == group_id:
  442. group.group_name = new_group_name
  443. group.widgets[0].setGroupName(new_group_name)
  444. if group.split and group.widgets[1]:
  445. group.widgets[1].setGroupName(new_group_name)
  446. QTimer.singleShot(0, canvas.scene.update)
  447. return
  448. qCritical("PatchCanvas::renameGroup(%i, %s) - unable to find group to rename" % (group_id, new_group_name.encode()))
  449. def splitGroup(group_id):
  450. if canvas.debug:
  451. qDebug("PatchCanvas::splitGroup(%i)" % group_id)
  452. item = None
  453. group_name = ""
  454. group_icon = ICON_APPLICATION
  455. ports_data = []
  456. conns_data = []
  457. # Step 1 - Store all Item data
  458. for group in canvas.group_list:
  459. if group.group_id == group_id:
  460. if group.split:
  461. qCritical("PatchCanvas::splitGroup(%i) - group is already splitted" % group_id)
  462. return
  463. item = group.widgets[0]
  464. group_name = group.group_name
  465. group_icon = group.icon
  466. break
  467. if not item:
  468. qCritical("PatchCanvas::splitGroup(%i) - unable to find group to split" % group_id)
  469. return
  470. port_list_ids = list(item.getPortList())
  471. for port in canvas.port_list:
  472. if port.port_id in port_list_ids:
  473. port_dict = port_dict_t()
  474. port_dict.group_id = port.group_id
  475. port_dict.port_id = port.port_id
  476. port_dict.port_name = port.port_name
  477. port_dict.port_mode = port.port_mode
  478. port_dict.port_type = port.port_type
  479. port_dict.widget = None
  480. ports_data.append(port_dict)
  481. for connection in canvas.connection_list:
  482. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  483. connection_dict = connection_dict_t()
  484. connection_dict.connection_id = connection.connection_id
  485. connection_dict.port_in_id = connection.port_in_id
  486. connection_dict.port_out_id = connection.port_out_id
  487. connection_dict.widget = None
  488. conns_data.append(connection_dict)
  489. # Step 2 - Remove Item and Children
  490. for conn in conns_data:
  491. disconnectPorts(conn.connection_id)
  492. for port_id in port_list_ids:
  493. removePort(port_id)
  494. removeGroup(group_id)
  495. # Step 3 - Re-create Item, now splitted
  496. addGroup(group_id, group_name, SPLIT_YES, group_icon)
  497. for port in ports_data:
  498. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type)
  499. for conn in conns_data:
  500. connectPorts(conn.connection_id, conn.port_out_id, conn.port_in_id)
  501. QTimer.singleShot(0, canvas.scene.update)
  502. def joinGroup(group_id):
  503. if canvas.debug:
  504. qDebug("PatchCanvas::joinGroup(%i)" % group_id)
  505. item = None
  506. s_item = None
  507. group_name = ""
  508. group_icon = ICON_APPLICATION
  509. ports_data = []
  510. conns_data = []
  511. # Step 1 - Store all Item data
  512. for group in canvas.group_list:
  513. if group.group_id == group_id:
  514. if not group.split:
  515. qCritical("PatchCanvas::joinGroup(%i) - group is not splitted" % group_id)
  516. return
  517. item = group.widgets[0]
  518. s_item = group.widgets[1]
  519. group_name = group.group_name
  520. group_icon = group.icon
  521. break
  522. # FIXME
  523. if not (item and s_item):
  524. qCritical("PatchCanvas::joinGroup(%i) - unable to find groups to join" % group_id)
  525. return
  526. port_list_ids = list(item.getPortList())
  527. port_list_idss = s_item.getPortList()
  528. for port_id in port_list_idss:
  529. if port_id not in port_list_ids:
  530. port_list_ids.append(port_id)
  531. for port in canvas.port_list:
  532. if port.port_id in port_list_ids:
  533. port_dict = port_dict_t()
  534. port_dict.group_id = port.group_id
  535. port_dict.port_id = port.port_id
  536. port_dict.port_name = port.port_name
  537. port_dict.port_mode = port.port_mode
  538. port_dict.port_type = port.port_type
  539. port_dict.widget = None
  540. ports_data.append(port_dict)
  541. for connection in canvas.connection_list:
  542. if connection.port_out_id in port_list_ids or connection.port_in_id in port_list_ids:
  543. connection_dict = connection_dict_t()
  544. connection_dict.connection_id = connection.connection_id
  545. connection_dict.port_in_id = connection.port_in_id
  546. connection_dict.port_out_id = connection.port_out_id
  547. connection_dict.widget = None
  548. conns_data.append(connection_dict)
  549. # Step 2 - Remove Item and Children
  550. for conn in conns_data:
  551. disconnectPorts(conn.connection_id)
  552. for port_id in port_list_ids:
  553. removePort(port_id)
  554. removeGroup(group_id)
  555. # Step 3 - Re-create Item, now together
  556. addGroup(group_id, group_name, SPLIT_NO, group_icon)
  557. for port in ports_data:
  558. addPort(group_id, port.port_id, port.port_name, port.port_mode, port.port_type)
  559. for conn in conns_data:
  560. connectPorts(conn.connection_id, conn.port_out_id, conn.port_in_id)
  561. QTimer.singleShot(0, canvas.scene.update)
  562. def getGroupPos(group_id, port_mode=PORT_MODE_OUTPUT):
  563. if canvas.debug:
  564. qDebug("PatchCanvas::getGroupPos(%i, %s)" % (group_id, port_mode2str(port_mode)))
  565. for group in canvas.group_list:
  566. if group.group_id == group_id:
  567. if group.split:
  568. if port_mode == PORT_MODE_OUTPUT:
  569. return group.widgets[0].pos()
  570. elif port_mode == PORT_MODE_INPUT:
  571. return group.widgets[1].pos()
  572. else:
  573. return QPointF(0, 0)
  574. else:
  575. return group.widgets[0].pos()
  576. qCritical("PatchCanvas::getGroupPos(%i, %s) - unable to find group" % (group_id, port_mode2str(port_mode)))
  577. return QPointF(0, 0)
  578. def setGroupPos(group_id, group_pos_x, group_pos_y):
  579. setGroupPosFull(group_id, group_pos_x, group_pos_y, group_pos_x, group_pos_y)
  580. def setGroupPosFull(group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i):
  581. if canvas.debug:
  582. qDebug("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i)" % (group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  583. for group in canvas.group_list:
  584. if group.group_id == group_id:
  585. group.widgets[0].setPos(group_pos_x_o, group_pos_y_o)
  586. if group.split and group.widgets[1]:
  587. group.widgets[1].setPos(group_pos_x_i, group_pos_y_i)
  588. QTimer.singleShot(0, canvas.scene.update)
  589. return
  590. qCritical("PatchCanvas::setGroupPos(%i, %i, %i, %i, %i) - unable to find group to reposition" % (group_id, group_pos_x_o, group_pos_y_o, group_pos_x_i, group_pos_y_i))
  591. def setGroupIcon(group_id, icon):
  592. if canvas.debug:
  593. qDebug("PatchCanvas::setGroupIcon(%i, %s)" % (group_id, icon2str(icon)))
  594. for group in canvas.group_list:
  595. if group.group_id == group_id:
  596. group.icon = icon
  597. group.widgets[0].setIcon(icon)
  598. if group.split and group.widgets[1]:
  599. group.widgets[1].setIcon(icon)
  600. QTimer.singleShot(0, canvas.scene.update)
  601. return
  602. qCritical("PatchCanvas::setGroupIcon(%i, %s) - unable to find group to change icon" % (group_id, icon2str(icon)))
  603. def setGroupAsPlugin(group_id, plugin_id, hasUi):
  604. if canvas.debug:
  605. qDebug("PatchCanvas::setGroupAsPlugin(%i, %i, %s)" % (group_id, plugin_id, bool2str(hasUi)))
  606. for group in canvas.group_list:
  607. if group.group_id == group_id:
  608. group.widgets[0].setAsPlugin(plugin_id, hasUi)
  609. if group.split and group.widgets[1]:
  610. group.widgets[1].setAsPlugin(plugin_id, hasUi)
  611. return
  612. qCritical("PatchCanvas::setGroupAsPlugin(%i, %i, %s) - unable to find group to set as plugin" % (group_id, plugin_id, bool2str(hasUi)))
  613. def addPort(group_id, port_id, port_name, port_mode, port_type):
  614. if canvas.debug:
  615. qDebug("PatchCanvas::addPort(%i, %i, %s, %s, %s)" % (group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  616. for port in canvas.port_list:
  617. if port.group_id == group_id and port.port_id == port_id:
  618. qWarning("PatchCanvas::addPort(%i, %i, %s, %s, %s) - port already exists" % (group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  619. return
  620. box_widget = None
  621. port_widget = None
  622. for group in canvas.group_list:
  623. if group.group_id == group_id:
  624. if group.split and group.widgets[0].getSplittedMode() != port_mode and group.widgets[1]:
  625. n = 1
  626. else:
  627. n = 0
  628. box_widget = group.widgets[n]
  629. port_widget = box_widget.addPortFromGroup(port_id, port_mode, port_type, port_name)
  630. break
  631. if not (box_widget and port_widget):
  632. qCritical("PatchCanvas::addPort(%i, %i, %s, %s, %s) - Unable to find parent group" % (group_id, port_id, port_name.encode(), port_mode2str(port_mode), port_type2str(port_type)))
  633. return
  634. if options.eyecandy == EYECANDY_FULL:
  635. CanvasItemFX(port_widget, True)
  636. port_dict = port_dict_t()
  637. port_dict.group_id = group_id
  638. port_dict.port_id = port_id
  639. port_dict.port_name = port_name
  640. port_dict.port_mode = port_mode
  641. port_dict.port_type = port_type
  642. port_dict.widget = port_widget
  643. canvas.port_list.append(port_dict)
  644. box_widget.updatePositions()
  645. QTimer.singleShot(0, canvas.scene.update)
  646. def removePort(port_id):
  647. if canvas.debug:
  648. qDebug("PatchCanvas::removePort(%i)" % port_id)
  649. for port in canvas.port_list:
  650. if port.port_id == port_id:
  651. item = port.widget
  652. item.parentItem().removePortFromGroup(port_id)
  653. canvas.scene.removeItem(item)
  654. del item
  655. canvas.port_list.remove(port)
  656. QTimer.singleShot(0, canvas.scene.update)
  657. return
  658. qCritical("PatchCanvas::removePort(%i) - Unable to find port to remove" % port_id)
  659. def renamePort(port_id, new_port_name):
  660. if canvas.debug:
  661. qDebug("PatchCanvas::renamePort(%i, %s)" % (port_id, new_port_name.encode()))
  662. for port in canvas.port_list:
  663. if port.port_id == port_id:
  664. port.port_name = new_port_name
  665. port.widget.setPortName(new_port_name)
  666. port.widget.parentItem().updatePositions()
  667. QTimer.singleShot(0, canvas.scene.update)
  668. return
  669. qCritical("PatchCanvas::renamePort(%i, %s) - Unable to find port to rename" % (port_id, new_port_name.encode()))
  670. def connectPorts(connection_id, port_out_id, port_in_id):
  671. if canvas.debug:
  672. qDebug("PatchCanvas::connectPorts(%i, %i, %i)" % (connection_id, port_out_id, port_in_id))
  673. port_out = None
  674. port_in = None
  675. port_out_parent = None
  676. port_in_parent = None
  677. for port in canvas.port_list:
  678. if port.port_id == port_out_id:
  679. port_out = port.widget
  680. port_out_parent = port_out.parentItem()
  681. elif port.port_id == port_in_id:
  682. port_in = port.widget
  683. port_in_parent = port_in.parentItem()
  684. # FIXME
  685. if not (port_out and port_in):
  686. qCritical("PatchCanvas::connectPorts(%i, %i, %i) - unable to find ports to connect" % (connection_id, port_out_id, port_in_id))
  687. return
  688. connection_dict = connection_dict_t()
  689. connection_dict.connection_id = connection_id
  690. connection_dict.port_out_id = port_out_id
  691. connection_dict.port_in_id = port_in_id
  692. if options.use_bezier_lines:
  693. connection_dict.widget = CanvasBezierLine(port_out, port_in, None)
  694. else:
  695. connection_dict.widget = CanvasLine(port_out, port_in, None)
  696. canvas.scene.addItem(connection_dict.widget)
  697. port_out_parent.addLineFromGroup(connection_dict.widget, connection_id)
  698. port_in_parent.addLineFromGroup(connection_dict.widget, connection_id)
  699. canvas.last_z_value += 1
  700. port_out_parent.setZValue(canvas.last_z_value)
  701. port_in_parent.setZValue(canvas.last_z_value)
  702. canvas.last_z_value += 1
  703. connection_dict.widget.setZValue(canvas.last_z_value)
  704. canvas.connection_list.append(connection_dict)
  705. if options.eyecandy == EYECANDY_FULL:
  706. item = connection_dict.widget
  707. CanvasItemFX(item, True)
  708. QTimer.singleShot(0, canvas.scene.update)
  709. def disconnectPorts(connection_id):
  710. if canvas.debug:
  711. qDebug("PatchCanvas::disconnectPorts(%i)" % connection_id)
  712. port_1_id = port_2_id = 0
  713. line = None
  714. item1 = None
  715. item2 = None
  716. for connection in canvas.connection_list:
  717. if connection.connection_id == connection_id:
  718. port_1_id = connection.port_out_id
  719. port_2_id = connection.port_in_id
  720. line = connection.widget
  721. canvas.connection_list.remove(connection)
  722. break
  723. if not line:
  724. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find connection ports" % connection_id)
  725. return
  726. for port in canvas.port_list:
  727. if port.port_id == port_1_id:
  728. item1 = port.widget
  729. break
  730. if not item1:
  731. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find output port" % connection_id)
  732. return
  733. for port in canvas.port_list:
  734. if port.port_id == port_2_id:
  735. item2 = port.widget
  736. break
  737. if not item2:
  738. qCritical("PatchCanvas::disconnectPorts(%i) - unable to find input port" % connection_id)
  739. return
  740. item1.parentItem().removeLineFromGroup(connection_id)
  741. item2.parentItem().removeLineFromGroup(connection_id)
  742. if options.eyecandy == EYECANDY_FULL:
  743. CanvasItemFX(line, False, True)
  744. else:
  745. line.deleteFromScene()
  746. QTimer.singleShot(0, canvas.scene.update)
  747. def arrange():
  748. if canvas.debug:
  749. qDebug("PatchCanvas::arrange()")
  750. def updateZValues():
  751. if canvas.debug:
  752. qDebug("PatchCanvas::updateZValues()")
  753. for group in canvas.group_list:
  754. group.widgets[0].resetLinesZValue()
  755. if group.split and group.widgets[1]:
  756. group.widgets[1].resetLinesZValue()
  757. def handlePluginRemoved(plugin_id):
  758. if canvas.debug:
  759. qDebug("PatchCanvas::handlePluginRemoved(%i)" % plugin_id)
  760. for group in canvas.group_list:
  761. if group.widgets[0].m_plugin_id < plugin_id:
  762. continue
  763. group.widgets[0].m_plugin_id -= 1
  764. if group.split and group.widgets[1]:
  765. group.widgets[1].m_plugin_id -= 1
  766. # Extra Internal functions
  767. def CanvasGetGroupName(group_id):
  768. if canvas.debug:
  769. qDebug("PatchCanvas::CanvasGetGroupName(%i)" % group_id)
  770. for group in canvas.group_list:
  771. if group.group_id == group_id:
  772. return group.group_name
  773. qCritical("PatchCanvas::CanvasGetGroupName(%i) - unable to find group" % group_id)
  774. return ""
  775. def CanvasGetGroupPortCount(group_id):
  776. if canvas.debug:
  777. qDebug("PatchCanvas::CanvasGetGroupPortCount(%i)" % group_id)
  778. port_count = 0
  779. for port in canvas.port_list:
  780. if port.group_id == group_id:
  781. port_count += 1
  782. return port_count
  783. def CanvasGetNewGroupPos(horizontal=False):
  784. if canvas.debug:
  785. qDebug("PatchCanvas::CanvasGetNewGroupPos(%s)" % bool2str(horizontal))
  786. new_pos = QPointF(canvas.initial_pos.x(), canvas.initial_pos.y())
  787. items = canvas.scene.items()
  788. break_loop = False
  789. while not break_loop:
  790. break_for = False
  791. for i in range(len(items)):
  792. item = items[i]
  793. if item and item.type() == CanvasBoxType:
  794. if item.sceneBoundingRect().contains(new_pos):
  795. if horizontal:
  796. new_pos += QPointF(item.boundingRect().width() + 15, 0)
  797. else:
  798. new_pos += QPointF(0, item.boundingRect().height() + 15)
  799. break_for = True
  800. break
  801. if i >= len(items) - 1 and not break_for:
  802. break_loop = True
  803. return new_pos
  804. def CanvasGetFullPortName(port_id):
  805. if canvas.debug:
  806. qDebug("PatchCanvas::CanvasGetFullPortName(%i)" % port_id)
  807. for port in canvas.port_list:
  808. if port.port_id == port_id:
  809. group_id = port.group_id
  810. for group in canvas.group_list:
  811. if group.group_id == group_id:
  812. return group.group_name + ":" + port.port_name
  813. break
  814. qCritical("PatchCanvas::CanvasGetFullPortName(%i) - unable to find port" % port_id)
  815. return ""
  816. def CanvasGetPortConnectionList(port_id):
  817. if canvas.debug:
  818. qDebug("PatchCanvas::CanvasGetPortConnectionList(%i)" % port_id)
  819. port_con_list = []
  820. for connection in canvas.connection_list:
  821. if connection.port_out_id == port_id or connection.port_in_id == port_id:
  822. port_con_list.append(connection.connection_id)
  823. return port_con_list
  824. def CanvasGetConnectedPort(connection_id, port_id):
  825. if canvas.debug:
  826. qDebug("PatchCanvas::CanvasGetConnectedPort(%i, %i)" % (connection_id, port_id))
  827. for connection in canvas.connection_list:
  828. if connection.connection_id == connection_id:
  829. if connection.port_out_id == port_id:
  830. return connection.port_in_id
  831. else:
  832. return connection.port_out_id
  833. qCritical("PatchCanvas::CanvasGetConnectedPort(%i, %i) - unable to find connection" % (connection_id, port_id))
  834. return 0
  835. def CanvasRemoveAnimation(f_animation):
  836. if canvas.debug:
  837. qDebug("PatchCanvas::CanvasRemoveAnimation(%s)" % f_animation)
  838. for animation in canvas.animation_list:
  839. if animation.animation == f_animation:
  840. canvas.animation_list.remove(animation)
  841. del animation.animation
  842. break
  843. def CanvasCallback(action, value1, value2, value_str):
  844. if canvas.debug:
  845. qDebug("PatchCanvas::CanvasCallback(%i, %i, %i, %s)" % (action, value1, value2, value_str.encode()))
  846. canvas.callback(action, value1, value2, value_str)
  847. def CanvasItemFX(item, show, destroy=False):
  848. if canvas.debug:
  849. qDebug("PatchCanvas::CanvasItemFX(%s, %s, %s)" % (item, bool2str(show), bool2str(destroy)))
  850. # Check if item already has an animationItemFX
  851. for animation in canvas.animation_list:
  852. if animation.item == item:
  853. animation.animation.stop()
  854. canvas.animation_list.remove(animation)
  855. del animation.animation
  856. break
  857. animation = CanvasFadeAnimation(item, show)
  858. animation.setDuration(750 if show else 500)
  859. animation_dict = animation_dict_t()
  860. animation_dict.animation = animation
  861. animation_dict.item = item
  862. canvas.animation_list.append(animation_dict)
  863. if show:
  864. animation.finished.connect(canvas.qobject.AnimationIdle)
  865. else:
  866. if destroy:
  867. animation.finished.connect(canvas.qobject.AnimationDestroy)
  868. else:
  869. animation.finished.connect(canvas.qobject.AnimationHide)
  870. animation.start()
  871. def CanvasRemoveItemFX(item):
  872. if canvas.debug:
  873. qDebug("PatchCanvas::CanvasRemoveItemFX(%s)" % item)
  874. if item.type() == CanvasBoxType:
  875. item.removeIconFromScene()
  876. canvas.scene.removeItem(item)
  877. elif item.type() == CanvasPortType:
  878. canvas.scene.removeItem(item)
  879. elif item.type() in (CanvasLineType, CanvasBezierLineType):
  880. pass #item.deleteFromScene()
  881. # Force deletion of item if needed
  882. if item.type() in (CanvasBoxType, CanvasPortType):
  883. del item
  884. # ------------------------------------------------------------------------------
  885. # patchscene.cpp
  886. class PatchScene(QGraphicsScene):
  887. scaleChanged = pyqtSignal(float)
  888. sceneGroupMoved = pyqtSignal(int, int, QPointF)
  889. pluginSelected = pyqtSignal(list)
  890. def __init__(self, parent, view):
  891. QGraphicsScene.__init__(self, parent)
  892. self.m_ctrl_down = False
  893. self.m_mouse_down_init = False
  894. self.m_mouse_rubberband = False
  895. self.addRubberBand()
  896. self.m_view = view
  897. if not self.m_view:
  898. qFatal("PatchCanvas::PatchScene() - invalid view")
  899. self.selectionChanged.connect(self.slot_selectionChanged)
  900. def addRubberBand(self):
  901. self.m_rubberband = self.addRect(QRectF(0, 0, 0, 0))
  902. self.m_rubberband.setZValue(-1)
  903. self.m_rubberband.hide()
  904. self.m_rubberband_selection = False
  905. self.m_rubberband_orig_point = QPointF(0, 0)
  906. def clear(self):
  907. QGraphicsScene.clear(self)
  908. # Re-add rubberband, that just got deleted
  909. self.addRubberBand()
  910. def fixScaleFactor(self):
  911. scale = self.m_view.transform().m11()
  912. if scale > 3.0:
  913. self.m_view.resetTransform()
  914. self.m_view.scale(3.0, 3.0)
  915. elif scale < 0.2:
  916. self.m_view.resetTransform()
  917. self.m_view.scale(0.2, 0.2)
  918. self.scaleChanged.emit(self.m_view.transform().m11())
  919. def updateTheme(self):
  920. self.setBackgroundBrush(canvas.theme.canvas_bg)
  921. self.m_rubberband.setPen(canvas.theme.rubberband_pen)
  922. self.m_rubberband.setBrush(canvas.theme.rubberband_brush)
  923. def zoom_fit(self):
  924. min_x = min_y = max_x = max_y = None
  925. first_value = True
  926. items_list = self.items()
  927. if len(items_list) > 0:
  928. for item in items_list:
  929. if item and item.isVisible() and item.type() == CanvasBoxType:
  930. pos = item.scenePos()
  931. rect = item.boundingRect()
  932. if first_value:
  933. min_x = pos.x()
  934. elif pos.x() < min_x:
  935. min_x = pos.x()
  936. if first_value:
  937. min_y = pos.y()
  938. elif pos.y() < min_y:
  939. min_y = pos.y()
  940. if first_value:
  941. max_x = pos.x() + rect.width()
  942. elif pos.x() + rect.width() > max_x:
  943. max_x = pos.x() + rect.width()
  944. if first_value:
  945. max_y = pos.y() + rect.height()
  946. elif pos.y() + rect.height() > max_y:
  947. max_y = pos.y() + rect.height()
  948. first_value = False
  949. if not first_value:
  950. self.m_view.fitInView(min_x, min_y, abs(max_x - min_x), abs(max_y - min_y), Qt.KeepAspectRatio)
  951. self.fixScaleFactor()
  952. def zoom_in(self):
  953. if self.m_view.transform().m11() < 3.0:
  954. self.m_view.scale(1.2, 1.2)
  955. self.scaleChanged.emit(self.m_view.transform().m11())
  956. def zoom_out(self):
  957. if self.m_view.transform().m11() > 0.2:
  958. self.m_view.scale(0.8, 0.8)
  959. self.scaleChanged.emit(self.m_view.transform().m11())
  960. def zoom_reset(self):
  961. self.m_view.resetTransform()
  962. self.scaleChanged.emit(1.0)
  963. @pyqtSlot()
  964. def slot_selectionChanged(self):
  965. items_list = self.selectedItems()
  966. if len(items_list) == 0:
  967. self.pluginSelected.emit([])
  968. return
  969. plugin_list = []
  970. for item in items_list:
  971. if item and item.isVisible():
  972. group_item = None
  973. if item.type() == CanvasBoxType:
  974. group_item = item
  975. elif item.type() == CanvasPortType:
  976. group_item = item.parentItem()
  977. #elif item.type() in (CanvasLineType, CanvasBezierLineType, CanvasLineMovType, CanvasBezierLineMovType):
  978. #plugin_list = []
  979. #break
  980. if group_item is not None and group_item.m_plugin_id >= 0:
  981. plugin_list.append(group_item.m_plugin_id)
  982. self.pluginSelected.emit(plugin_list)
  983. def keyPressEvent(self, event):
  984. if not self.m_view:
  985. return event.ignore()
  986. if event.key() == Qt.Key_Control:
  987. self.m_ctrl_down = True
  988. elif event.key() == Qt.Key_Home:
  989. self.zoom_fit()
  990. return event.accept()
  991. elif self.m_ctrl_down:
  992. if event.key() == Qt.Key_Plus:
  993. self.zoom_in()
  994. return event.accept()
  995. elif event.key() == Qt.Key_Minus:
  996. self.zoom_out()
  997. return event.accept()
  998. elif event.key() == Qt.Key_1:
  999. self.zoom_reset()
  1000. return event.accept()
  1001. QGraphicsScene.keyPressEvent(self, event)
  1002. def keyReleaseEvent(self, event):
  1003. if event.key() == Qt.Key_Control:
  1004. self.m_ctrl_down = False
  1005. QGraphicsScene.keyReleaseEvent(self, event)
  1006. def mousePressEvent(self, event):
  1007. self.m_mouse_down_init = bool(event.button() == Qt.LeftButton)
  1008. self.m_mouse_rubberband = False
  1009. QGraphicsScene.mousePressEvent(self, event)
  1010. def mouseMoveEvent(self, event):
  1011. if self.m_mouse_down_init:
  1012. self.m_mouse_down_init = False
  1013. self.m_mouse_rubberband = bool(len(self.selectedItems()) == 0)
  1014. if self.m_mouse_rubberband:
  1015. if not self.m_rubberband_selection:
  1016. self.m_rubberband.show()
  1017. self.m_rubberband_selection = True
  1018. self.m_rubberband_orig_point = event.scenePos()
  1019. pos = event.scenePos()
  1020. if pos.x() > self.m_rubberband_orig_point.x():
  1021. x = self.m_rubberband_orig_point.x()
  1022. else:
  1023. x = pos.x()
  1024. if pos.y() > self.m_rubberband_orig_point.y():
  1025. y = self.m_rubberband_orig_point.y()
  1026. else:
  1027. y = pos.y()
  1028. self.m_rubberband.setRect(x, y, abs(pos.x() - self.m_rubberband_orig_point.x()), abs(pos.y() - self.m_rubberband_orig_point.y()))
  1029. return event.accept()
  1030. QGraphicsScene.mouseMoveEvent(self, event)
  1031. def mouseReleaseEvent(self, event):
  1032. if self.m_rubberband_selection:
  1033. items_list = self.items()
  1034. if len(items_list) > 0:
  1035. for item in items_list:
  1036. if item and item.isVisible() and item.type() == CanvasBoxType:
  1037. item_rect = item.sceneBoundingRect()
  1038. item_top_left = QPointF(item_rect.x(), item_rect.y())
  1039. item_bottom_right = QPointF(item_rect.x() + item_rect.width(), item_rect.y() + item_rect.height())
  1040. if self.m_rubberband.contains(item_top_left) and self.m_rubberband.contains(item_bottom_right):
  1041. item.setSelected(True)
  1042. self.m_rubberband.hide()
  1043. self.m_rubberband.setRect(0, 0, 0, 0)
  1044. self.m_rubberband_selection = False
  1045. else:
  1046. items_list = self.selectedItems()
  1047. for item in items_list:
  1048. if item and item.isVisible() and item.type() == CanvasBoxType:
  1049. item.checkItemPos()
  1050. self.sceneGroupMoved.emit(item.getGroupId(), item.getSplittedMode(), item.scenePos())
  1051. if len(items_list) > 1:
  1052. canvas.scene.update()
  1053. self.m_mouse_down_init = False
  1054. self.m_mouse_rubberband = False
  1055. QGraphicsScene.mouseReleaseEvent(self, event)
  1056. def wheelEvent(self, event):
  1057. if not self.m_view:
  1058. return event.ignore()
  1059. if self.m_ctrl_down:
  1060. factor = 1.41 ** (event.delta() / 240.0)
  1061. self.m_view.scale(factor, factor)
  1062. self.fixScaleFactor()
  1063. return event.accept()
  1064. QGraphicsScene.wheelEvent(self, event)
  1065. # ------------------------------------------------------------------------------
  1066. # canvasfadeanimation.cpp
  1067. class CanvasFadeAnimation(QAbstractAnimation):
  1068. def __init__(self, item, show, parent=None):
  1069. QAbstractAnimation.__init__(self, parent)
  1070. self.m_show = show
  1071. self.m_duration = 0
  1072. self.m_item = item
  1073. def item(self):
  1074. return self.m_item
  1075. def setDuration(self, time):
  1076. if self.m_item.opacity() == 0 and not self.m_show:
  1077. self._duration = 0
  1078. else:
  1079. self.m_item.show()
  1080. self.m_duration = time
  1081. def duration(self):
  1082. return self.m_duration
  1083. def updateCurrentTime(self, time):
  1084. if self.m_duration == 0:
  1085. return
  1086. if self.m_show:
  1087. value = float(time) / self.m_duration
  1088. else:
  1089. value = 1.0 - (float(time) / self.m_duration)
  1090. self.m_item.setOpacity(value)
  1091. if self.m_item.type() == CanvasBoxType:
  1092. self.m_item.setShadowOpacity(value)
  1093. def updateDirection(self, direction):
  1094. pass
  1095. def updateState(self, oldState, newState):
  1096. pass
  1097. # ------------------------------------------------------------------------------
  1098. # canvasline.cpp
  1099. class CanvasLine(QGraphicsLineItem):
  1100. def __init__(self, item1, item2, parent):
  1101. QGraphicsLineItem.__init__(self, parent)
  1102. self.item1 = item1
  1103. self.item2 = item2
  1104. self.m_locked = False
  1105. self.m_lineSelected = False
  1106. self.setGraphicsEffect(None)
  1107. self.updateLinePos()
  1108. def deleteFromScene(self):
  1109. canvas.scene.removeItem(self)
  1110. del self
  1111. def isLocked(self):
  1112. return self.m_locked
  1113. def setLocked(self, yesno):
  1114. self.m_locked = yesno
  1115. def isLineSelected(self):
  1116. return self.m_lineSelected
  1117. def setLineSelected(self, yesno):
  1118. if self.m_locked:
  1119. return
  1120. if options.eyecandy == EYECANDY_FULL:
  1121. if yesno:
  1122. self.setGraphicsEffect(CanvasPortGlow(self.item1.getPortType(), self.toGraphicsObject()))
  1123. else:
  1124. self.setGraphicsEffect(None)
  1125. self.m_lineSelected = yesno
  1126. self.updateLineGradient()
  1127. def updateLinePos(self):
  1128. if self.item1.getPortMode() == PORT_MODE_OUTPUT:
  1129. line = QLineF(self.item1.scenePos().x() + self.item1.getPortWidth() + 12,
  1130. self.item1.scenePos().y() + float(canvas.theme.port_height)/2,
  1131. self.item2.scenePos().x(),
  1132. self.item2.scenePos().y() + float(canvas.theme.port_height)/2)
  1133. self.setLine(line)
  1134. self.m_lineSelected = False
  1135. self.updateLineGradient()
  1136. def type(self):
  1137. return CanvasLineType
  1138. def updateLineGradient(self):
  1139. pos_top = self.boundingRect().top()
  1140. pos_bot = self.boundingRect().bottom()
  1141. if self.item2.scenePos().y() >= self.item1.scenePos().y():
  1142. pos1 = 0
  1143. pos2 = 1
  1144. else:
  1145. pos1 = 1
  1146. pos2 = 0
  1147. port_type1 = self.item1.getPortType()
  1148. port_type2 = self.item2.getPortType()
  1149. port_gradient = QLinearGradient(0, pos_top, 0, pos_bot)
  1150. if port_type1 == PORT_TYPE_AUDIO_JACK:
  1151. port_gradient.setColorAt(pos1, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack)
  1152. elif port_type1 == PORT_TYPE_MIDI_JACK:
  1153. port_gradient.setColorAt(pos1, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack)
  1154. elif port_type1 == PORT_TYPE_MIDI_A2J:
  1155. port_gradient.setColorAt(pos1, canvas.theme.line_midi_a2j_sel if self.m_lineSelected else canvas.theme.line_midi_a2j)
  1156. elif port_type1 == PORT_TYPE_MIDI_ALSA:
  1157. port_gradient.setColorAt(pos1, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa)
  1158. if port_type2 == PORT_TYPE_AUDIO_JACK:
  1159. port_gradient.setColorAt(pos2, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack)
  1160. elif port_type2 == PORT_TYPE_MIDI_JACK:
  1161. port_gradient.setColorAt(pos2, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack)
  1162. elif port_type2 == PORT_TYPE_MIDI_A2J:
  1163. port_gradient.setColorAt(pos2, canvas.theme.line_midi_a2j_sel if self.m_lineSelected else canvas.theme.line_midi_a2j)
  1164. elif port_type2 == PORT_TYPE_MIDI_ALSA:
  1165. port_gradient.setColorAt(pos2, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa)
  1166. self.setPen(QPen(port_gradient, 2))
  1167. def paint(self, painter, option, widget):
  1168. painter.save()
  1169. painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing))
  1170. QGraphicsLineItem.paint(self, painter, option, widget)
  1171. painter.restore()
  1172. # ------------------------------------------------------------------------------
  1173. # canvasbezierline.cpp
  1174. class CanvasBezierLine(QGraphicsPathItem):
  1175. def __init__(self, item1, item2, parent):
  1176. QGraphicsPathItem.__init__(self, parent)
  1177. self.item1 = item1
  1178. self.item2 = item2
  1179. self.m_locked = False
  1180. self.m_lineSelected = False
  1181. self.setBrush(QColor(0, 0, 0, 0))
  1182. self.setGraphicsEffect(None)
  1183. self.updateLinePos()
  1184. def deleteFromScene(self):
  1185. canvas.scene.removeItem(self)
  1186. del self
  1187. def isLocked(self):
  1188. return self.m_locked
  1189. def setLocked(self, yesno):
  1190. self.m_locked = yesno
  1191. def isLineSelected(self):
  1192. return self.m_lineSelected
  1193. def setLineSelected(self, yesno):
  1194. if self.m_locked:
  1195. return
  1196. if options.eyecandy == EYECANDY_FULL:
  1197. if yesno:
  1198. self.setGraphicsEffect(CanvasPortGlow(self.item1.getPortType(), self.toGraphicsObject()))
  1199. else:
  1200. self.setGraphicsEffect(None)
  1201. self.m_lineSelected = yesno
  1202. self.updateLineGradient()
  1203. def updateLinePos(self):
  1204. if self.item1.getPortMode() == PORT_MODE_OUTPUT:
  1205. item1_x = self.item1.scenePos().x() + self.item1.getPortWidth() + 12
  1206. item1_y = self.item1.scenePos().y() + float(canvas.theme.port_height)/2
  1207. item2_x = self.item2.scenePos().x()
  1208. item2_y = self.item2.scenePos().y() + float(canvas.theme.port_height)/2
  1209. item1_mid_x = abs(item1_x - item2_x) / 2
  1210. item1_new_x = item1_x + item1_mid_x
  1211. item2_mid_x = abs(item1_x - item2_x) / 2
  1212. item2_new_x = item2_x - item2_mid_x
  1213. path = QPainterPath(QPointF(item1_x, item1_y))
  1214. path.cubicTo(item1_new_x, item1_y, item2_new_x, item2_y, item2_x, item2_y)
  1215. self.setPath(path)
  1216. self.m_lineSelected = False
  1217. self.updateLineGradient()
  1218. def type(self):
  1219. return CanvasBezierLineType
  1220. def updateLineGradient(self):
  1221. pos_top = self.boundingRect().top()
  1222. pos_bot = self.boundingRect().bottom()
  1223. if self.item2.scenePos().y() >= self.item1.scenePos().y():
  1224. pos1 = 0
  1225. pos2 = 1
  1226. else:
  1227. pos1 = 1
  1228. pos2 = 0
  1229. port_type1 = self.item1.getPortType()
  1230. port_type2 = self.item2.getPortType()
  1231. port_gradient = QLinearGradient(0, pos_top, 0, pos_bot)
  1232. if port_type1 == PORT_TYPE_AUDIO_JACK:
  1233. port_gradient.setColorAt(pos1, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack)
  1234. elif port_type1 == PORT_TYPE_MIDI_JACK:
  1235. port_gradient.setColorAt(pos1, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack)
  1236. elif port_type1 == PORT_TYPE_MIDI_A2J:
  1237. port_gradient.setColorAt(pos1, canvas.theme.line_midi_a2j_sel if self.m_lineSelected else canvas.theme.line_midi_a2j)
  1238. elif port_type1 == PORT_TYPE_MIDI_ALSA:
  1239. port_gradient.setColorAt(pos1, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa)
  1240. if port_type2 == PORT_TYPE_AUDIO_JACK:
  1241. port_gradient.setColorAt(pos2, canvas.theme.line_audio_jack_sel if self.m_lineSelected else canvas.theme.line_audio_jack)
  1242. elif port_type2 == PORT_TYPE_MIDI_JACK:
  1243. port_gradient.setColorAt(pos2, canvas.theme.line_midi_jack_sel if self.m_lineSelected else canvas.theme.line_midi_jack)
  1244. elif port_type2 == PORT_TYPE_MIDI_A2J:
  1245. port_gradient.setColorAt(pos2, canvas.theme.line_midi_a2j_sel if self.m_lineSelected else canvas.theme.line_midi_a2j)
  1246. elif port_type2 == PORT_TYPE_MIDI_ALSA:
  1247. port_gradient.setColorAt(pos2, canvas.theme.line_midi_alsa_sel if self.m_lineSelected else canvas.theme.line_midi_alsa)
  1248. self.setPen(QPen(port_gradient, 2))
  1249. def paint(self, painter, option, widget):
  1250. painter.save()
  1251. painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing))
  1252. QGraphicsPathItem.paint(self, painter, option, widget)
  1253. painter.restore()
  1254. # ------------------------------------------------------------------------------
  1255. # canvaslivemov.cpp
  1256. class CanvasLineMov(QGraphicsLineItem):
  1257. def __init__(self, port_mode, port_type, parent):
  1258. QGraphicsLineItem.__init__(self, parent)
  1259. self.m_port_mode = port_mode
  1260. self.m_port_type = port_type
  1261. # Port position doesn't change while moving around line
  1262. self.p_lineX = self.scenePos().x()
  1263. self.p_lineY = self.scenePos().y()
  1264. self.p_width = self.parentItem().getPortWidth()
  1265. if port_type == PORT_TYPE_AUDIO_JACK:
  1266. pen = QPen(canvas.theme.line_audio_jack, 2)
  1267. elif port_type == PORT_TYPE_MIDI_JACK:
  1268. pen = QPen(canvas.theme.line_midi_jack, 2)
  1269. elif port_type == PORT_TYPE_MIDI_A2J:
  1270. pen = QPen(canvas.theme.line_midi_a2j, 2)
  1271. elif port_type == PORT_TYPE_MIDI_ALSA:
  1272. pen = QPen(canvas.theme.line_midi_alsa, 2)
  1273. else:
  1274. qWarning("PatchCanvas::CanvasLineMov(%s, %s, %s) - invalid port type" % (port_mode2str(port_mode), port_type2str(port_type), parent))
  1275. pen = QPen(Qt.black)
  1276. self.setPen(pen)
  1277. def deleteFromScene(self):
  1278. canvas.scene.removeItem(self)
  1279. del self
  1280. def updateLinePos(self, scenePos):
  1281. item_pos = [0, 0]
  1282. if self.m_port_mode == PORT_MODE_INPUT:
  1283. item_pos[0] = 0
  1284. item_pos[1] = float(canvas.theme.port_height)/2
  1285. elif self.m_port_mode == PORT_MODE_OUTPUT:
  1286. item_pos[0] = self.p_width + 12
  1287. item_pos[1] = float(canvas.theme.port_height)/2
  1288. else:
  1289. return
  1290. line = QLineF(item_pos[0], item_pos[1], scenePos.x() - self.p_lineX, scenePos.y() - self.p_lineY)
  1291. self.setLine(line)
  1292. def type(self):
  1293. return CanvasLineMovType
  1294. def paint(self, painter, option, widget):
  1295. painter.save()
  1296. painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing))
  1297. QGraphicsLineItem.paint(self, painter, option, widget)
  1298. painter.restore()
  1299. # ------------------------------------------------------------------------------
  1300. # canvasbezierlinemov.cpp
  1301. class CanvasBezierLineMov(QGraphicsPathItem):
  1302. def __init__(self, port_mode, port_type, parent):
  1303. QGraphicsPathItem.__init__(self, parent)
  1304. self.m_port_mode = port_mode
  1305. self.m_port_type = port_type
  1306. # Port position doesn't change while moving around line
  1307. self.p_itemX = self.scenePos().x()
  1308. self.p_itemY = self.scenePos().y()
  1309. self.p_width = self.parentItem().getPortWidth()
  1310. if port_type == PORT_TYPE_AUDIO_JACK:
  1311. pen = QPen(canvas.theme.line_audio_jack, 2)
  1312. elif port_type == PORT_TYPE_MIDI_JACK:
  1313. pen = QPen(canvas.theme.line_midi_jack, 2)
  1314. elif port_type == PORT_TYPE_MIDI_A2J:
  1315. pen = QPen(canvas.theme.line_midi_a2j, 2)
  1316. elif port_type == PORT_TYPE_MIDI_ALSA:
  1317. pen = QPen(canvas.theme.line_midi_alsa, 2)
  1318. else:
  1319. qWarning("PatchCanvas::CanvasBezierLineMov(%s, %s, %s) - invalid port type" % (port_mode2str(port_mode), port_type2str(port_type), parent))
  1320. pen = QPen(Qt.black)
  1321. self.setBrush(QColor(0, 0, 0, 0))
  1322. self.setPen(pen)
  1323. def deleteFromScene(self):
  1324. canvas.scene.removeItem(self)
  1325. del self
  1326. def updateLinePos(self, scenePos):
  1327. if self.m_port_mode == PORT_MODE_INPUT:
  1328. old_x = 0
  1329. old_y = float(canvas.theme.port_height)/2
  1330. mid_x = abs(scenePos.x() - self.p_itemX) / 2
  1331. new_x = old_x - mid_x
  1332. elif self.m_port_mode == PORT_MODE_OUTPUT:
  1333. old_x = self.p_width + 12
  1334. old_y = float(canvas.theme.port_height)/2
  1335. mid_x = abs(scenePos.x() - (self.p_itemX + old_x)) / 2
  1336. new_x = old_x + mid_x
  1337. else:
  1338. return
  1339. final_x = scenePos.x() - self.p_itemX
  1340. final_y = scenePos.y() - self.p_itemY
  1341. path = QPainterPath(QPointF(old_x, old_y))
  1342. path.cubicTo(new_x, old_y, new_x, final_y, final_x, final_y)
  1343. self.setPath(path)
  1344. def type(self):
  1345. return CanvasBezierLineMovType
  1346. def paint(self, painter, option, widget):
  1347. painter.save()
  1348. painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing))
  1349. QGraphicsPathItem.paint(self, painter, option, widget)
  1350. painter.restore()
  1351. # ------------------------------------------------------------------------------
  1352. # canvasport.cpp
  1353. class CanvasPort(QGraphicsItem):
  1354. def __init__(self, port_id, port_name, port_mode, port_type, parent):
  1355. QGraphicsItem.__init__(self, parent)
  1356. # Save Variables, useful for later
  1357. self.m_port_id = port_id
  1358. self.m_port_mode = port_mode
  1359. self.m_port_type = port_type
  1360. self.m_port_name = port_name
  1361. # Base Variables
  1362. self.m_port_width = 15
  1363. self.m_port_height = canvas.theme.port_height
  1364. self.m_port_font = QFont(canvas.theme.port_font_name, canvas.theme.port_font_size, canvas.theme.port_font_state)
  1365. self.m_line_mov = None
  1366. self.m_hover_item = None
  1367. self.m_last_selected_state = False
  1368. self.m_mouse_down = False
  1369. self.m_cursor_moving = False
  1370. self.setFlags(QGraphicsItem.ItemIsSelectable)
  1371. def getPortId(self):
  1372. return self.m_port_id
  1373. def getPortMode(self):
  1374. return self.m_port_mode
  1375. def getPortType(self):
  1376. return self.m_port_type
  1377. def getPortName(self):
  1378. return self.m_port_name
  1379. def getFullPortName(self):
  1380. return self.parentItem().getGroupName() + ":" + self.m_port_name
  1381. def getPortWidth(self):
  1382. return self.m_port_width
  1383. def getPortHeight(self):
  1384. return self.m_port_height
  1385. def setPortMode(self, port_mode):
  1386. self.m_port_mode = port_mode
  1387. self.update()
  1388. def setPortType(self, port_type):
  1389. self.m_port_type = port_type
  1390. self.update()
  1391. def setPortName(self, port_name):
  1392. if QFontMetrics(self.m_port_font).width(port_name) < QFontMetrics(self.m_port_font).width(self.m_port_name):
  1393. QTimer.singleShot(0, canvas.scene.update)
  1394. self.m_port_name = port_name
  1395. self.update()
  1396. def setPortWidth(self, port_width):
  1397. if port_width < self.m_port_width:
  1398. QTimer.singleShot(0, canvas.scene.update)
  1399. self.m_port_width = port_width
  1400. self.update()
  1401. def type(self):
  1402. return CanvasPortType
  1403. def mousePressEvent(self, event):
  1404. self.m_hover_item = None
  1405. self.m_mouse_down = bool(event.button() == Qt.LeftButton)
  1406. self.m_cursor_moving = False
  1407. QGraphicsItem.mousePressEvent(self, event)
  1408. def mouseMoveEvent(self, event):
  1409. if self.m_mouse_down:
  1410. if not self.m_cursor_moving:
  1411. self.setCursor(QCursor(Qt.CrossCursor))
  1412. self.m_cursor_moving = True
  1413. for connection in canvas.connection_list:
  1414. if connection.port_out_id == self.m_port_id or connection.port_in_id == self.m_port_id:
  1415. connection.widget.setLocked(True)
  1416. if not self.m_line_mov:
  1417. if options.use_bezier_lines:
  1418. self.m_line_mov = CanvasBezierLineMov(self.m_port_mode, self.m_port_type, self)
  1419. else:
  1420. self.m_line_mov = CanvasLineMov(self.m_port_mode, self.m_port_type, self)
  1421. canvas.last_z_value += 1
  1422. self.m_line_mov.setZValue(canvas.last_z_value)
  1423. canvas.last_z_value += 1
  1424. self.parentItem().setZValue(canvas.last_z_value)
  1425. item = None
  1426. items = canvas.scene.items(event.scenePos(), Qt.ContainsItemShape, Qt.AscendingOrder)
  1427. for i in range(len(items)):
  1428. if items[i].type() == CanvasPortType:
  1429. if items[i] != self:
  1430. if not item:
  1431. item = items[i]
  1432. elif items[i].parentItem().zValue() > item.parentItem().zValue():
  1433. item = items[i]
  1434. if self.m_hover_item and self.m_hover_item != item:
  1435. self.m_hover_item.setSelected(False)
  1436. if item:
  1437. a2j_connection = bool(item.getPortType() == PORT_TYPE_MIDI_JACK and self.m_port_type == PORT_TYPE_MIDI_A2J) or (item.getPortType() == PORT_TYPE_MIDI_A2J and self.m_port_type == PORT_TYPE_MIDI_JACK)
  1438. if item.getPortMode() != self.m_port_mode and (item.getPortType() == self.m_port_type or a2j_connection):
  1439. item.setSelected(True)
  1440. self.m_hover_item = item
  1441. else:
  1442. self.m_hover_item = None
  1443. else:
  1444. self.m_hover_item = None
  1445. self.m_line_mov.updateLinePos(event.scenePos())
  1446. return event.accept()
  1447. QGraphicsItem.mouseMoveEvent(self, event)
  1448. def mouseReleaseEvent(self, event):
  1449. if self.m_mouse_down:
  1450. if self.m_line_mov:
  1451. self.m_line_mov.deleteFromScene()
  1452. self.m_line_mov = None
  1453. for connection in canvas.connection_list:
  1454. if connection.port_out_id == self.m_port_id or connection.port_in_id == self.m_port_id:
  1455. connection.widget.setLocked(False)
  1456. if self.m_hover_item:
  1457. check = False
  1458. for connection in canvas.connection_list:
  1459. if ( (connection.port_out_id == self.m_port_id and connection.port_in_id == self.m_hover_item.getPortId()) or
  1460. (connection.port_out_id == self.m_hover_item.getPortId() and connection.port_in_id == self.m_port_id) ):
  1461. canvas.callback(ACTION_PORTS_DISCONNECT, connection.connection_id, 0, "")
  1462. check = True
  1463. break
  1464. if not check:
  1465. if self.m_port_mode == PORT_MODE_OUTPUT:
  1466. canvas.callback(ACTION_PORTS_CONNECT, self.m_port_id, self.m_hover_item.getPortId(), "")
  1467. else:
  1468. canvas.callback(ACTION_PORTS_CONNECT, self.m_hover_item.getPortId(), self.m_port_id, "")
  1469. canvas.scene.clearSelection()
  1470. if self.m_cursor_moving:
  1471. self.setCursor(QCursor(Qt.ArrowCursor))
  1472. self.m_hover_item = None
  1473. self.m_mouse_down = False
  1474. self.m_cursor_moving = False
  1475. QGraphicsItem.mouseReleaseEvent(self, event)
  1476. def contextMenuEvent(self, event):
  1477. canvas.scene.clearSelection()
  1478. self.setSelected(True)
  1479. menu = QMenu()
  1480. discMenu = QMenu("Disconnect", menu)
  1481. port_con_list = CanvasGetPortConnectionList(self.m_port_id)
  1482. if len(port_con_list) > 0:
  1483. for port_id in port_con_list:
  1484. port_con_id = CanvasGetConnectedPort(port_id, self.m_port_id)
  1485. act_x_disc = discMenu.addAction(CanvasGetFullPortName(port_con_id))
  1486. act_x_disc.setData(port_id)
  1487. act_x_disc.triggered.connect(canvas.qobject.PortContextMenuDisconnect)
  1488. else:
  1489. act_x_disc = discMenu.addAction("No connections")
  1490. act_x_disc.setEnabled(False)
  1491. menu.addMenu(discMenu)
  1492. act_x_disc_all = menu.addAction("Disconnect &All")
  1493. act_x_sep_1 = menu.addSeparator()
  1494. act_x_info = menu.addAction("Get &Info")
  1495. act_x_rename = menu.addAction("&Rename")
  1496. if not features.port_info:
  1497. act_x_info.setVisible(False)
  1498. if not features.port_rename:
  1499. act_x_rename.setVisible(False)
  1500. if not (features.port_info and features.port_rename):
  1501. act_x_sep_1.setVisible(False)
  1502. act_selected = menu.exec_(event.screenPos())
  1503. if act_selected == act_x_disc_all:
  1504. for port_id in port_con_list:
  1505. canvas.callback(ACTION_PORTS_DISCONNECT, port_id, 0, "")
  1506. elif act_selected == act_x_info:
  1507. canvas.callback(ACTION_PORT_INFO, self.m_port_id, 0, "")
  1508. elif act_selected == act_x_rename:
  1509. new_name_try = QInputDialog.getText(None, "Rename Port", "New name:", QLineEdit.Normal, self.m_port_name)
  1510. if new_name_try[1] and new_name_try[0]: # 1 - bool ok, 0 - return text
  1511. canvas.callback(ACTION_PORT_RENAME, self.m_port_id, 0, new_name_try[0])
  1512. event.accept()
  1513. def boundingRect(self):
  1514. return QRectF(0, 0, self.m_port_width + 12, self.m_port_height)
  1515. def paint(self, painter, option, widget):
  1516. painter.save()
  1517. painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing == ANTIALIASING_FULL))
  1518. poly_locx = [0, 0, 0, 0, 0]
  1519. if self.m_port_mode == PORT_MODE_INPUT:
  1520. text_pos = QPointF(3, canvas.theme.port_text_ypos)
  1521. if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON:
  1522. poly_locx[0] = 0
  1523. poly_locx[1] = self.m_port_width + 5
  1524. poly_locx[2] = self.m_port_width + 12
  1525. poly_locx[3] = self.m_port_width + 5
  1526. poly_locx[4] = 0
  1527. elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE:
  1528. poly_locx[0] = 0
  1529. poly_locx[1] = self.m_port_width + 5
  1530. poly_locx[2] = self.m_port_width + 5
  1531. poly_locx[3] = self.m_port_width + 5
  1532. poly_locx[4] = 0
  1533. else:
  1534. qCritical("PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'" % canvas.theme.port_mode)
  1535. return
  1536. elif self.m_port_mode == PORT_MODE_OUTPUT:
  1537. text_pos = QPointF(9, canvas.theme.port_text_ypos)
  1538. if canvas.theme.port_mode == Theme.THEME_PORT_POLYGON:
  1539. poly_locx[0] = self.m_port_width + 12
  1540. poly_locx[1] = 7
  1541. poly_locx[2] = 0
  1542. poly_locx[3] = 7
  1543. poly_locx[4] = self.m_port_width + 12
  1544. elif canvas.theme.port_mode == Theme.THEME_PORT_SQUARE:
  1545. poly_locx[0] = self.m_port_width + 12
  1546. poly_locx[1] = 5
  1547. poly_locx[2] = 5
  1548. poly_locx[3] = 5
  1549. poly_locx[4] = self.m_port_width + 12
  1550. else:
  1551. qCritical("PatchCanvas::CanvasPort.paint() - invalid theme port mode '%s'" % canvas.theme.port_mode)
  1552. return
  1553. else:
  1554. qCritical("PatchCanvas::CanvasPort.paint() - invalid port mode '%s'" % port_mode2str(self.m_port_mode))
  1555. return
  1556. if self.m_port_type == PORT_TYPE_AUDIO_JACK:
  1557. poly_color = canvas.theme.port_audio_jack_bg_sel if self.isSelected() else canvas.theme.port_audio_jack_bg
  1558. poly_pen = canvas.theme.port_audio_jack_pen_sel if self.isSelected() else canvas.theme.port_audio_jack_pen
  1559. text_pen = canvas.theme.port_audio_jack_text_sel if self.isSelected() else canvas.theme.port_audio_jack_text
  1560. conn_pen = canvas.theme.port_audio_jack_pen_sel
  1561. elif self.m_port_type == PORT_TYPE_MIDI_JACK:
  1562. poly_color = canvas.theme.port_midi_jack_bg_sel if self.isSelected() else canvas.theme.port_midi_jack_bg
  1563. poly_pen = canvas.theme.port_midi_jack_pen_sel if self.isSelected() else canvas.theme.port_midi_jack_pen
  1564. text_pen = canvas.theme.port_midi_jack_text_sel if self.isSelected() else canvas.theme.port_midi_jack_text
  1565. conn_pen = canvas.theme.port_midi_jack_pen_sel
  1566. elif self.m_port_type == PORT_TYPE_MIDI_A2J:
  1567. poly_color = canvas.theme.port_midi_a2j_bg_sel if self.isSelected() else canvas.theme.port_midi_a2j_bg
  1568. poly_pen = canvas.theme.port_midi_a2j_pen_sel if self.isSelected() else canvas.theme.port_midi_a2j_pen
  1569. text_pen = canvas.theme.port_midi_a2j_text_sel if self.isSelected() else canvas.theme.port_midi_a2j_text
  1570. conn_pen = canvas.theme.port_midi_a2j_pen_sel
  1571. elif self.m_port_type == PORT_TYPE_MIDI_ALSA:
  1572. poly_color = canvas.theme.port_midi_alsa_bg_sel if self.isSelected() else canvas.theme.port_midi_alsa_bg
  1573. poly_pen = canvas.theme.port_midi_alsa_pen_sel if self.isSelected() else canvas.theme.port_midi_alsa_pen
  1574. text_pen = canvas.theme.port_midi_alsa_text_sel if self.isSelected() else canvas.theme.port_midi_alsa_text
  1575. conn_pen = canvas.theme.port_midi_alsa_pen_sel
  1576. else:
  1577. qCritical("PatchCanvas::CanvasPort.paint() - invalid port type '%s'" % port_type2str(self.m_port_type))
  1578. return
  1579. polygon = QPolygonF()
  1580. polygon += QPointF(poly_locx[0], 0)
  1581. polygon += QPointF(poly_locx[1], 0)
  1582. polygon += QPointF(poly_locx[2], float(canvas.theme.port_height)/2)
  1583. polygon += QPointF(poly_locx[3], canvas.theme.port_height)
  1584. polygon += QPointF(poly_locx[4], canvas.theme.port_height)
  1585. if canvas.theme.port_bg_pixmap:
  1586. portRect = polygon.boundingRect()
  1587. portPos = portRect.topLeft()
  1588. painter.drawTiledPixmap(portRect, canvas.theme.port_bg_pixmap, portPos)
  1589. else:
  1590. painter.setBrush(poly_color)
  1591. painter.setPen(poly_pen)
  1592. painter.drawPolygon(polygon)
  1593. painter.setPen(text_pen)
  1594. painter.setFont(self.m_port_font)
  1595. painter.drawText(text_pos, self.m_port_name)
  1596. if self.isSelected() != self.m_last_selected_state:
  1597. for connection in canvas.connection_list:
  1598. if connection.port_out_id == self.m_port_id or connection.port_in_id == self.m_port_id:
  1599. connection.widget.setLineSelected(self.isSelected())
  1600. if canvas.theme.idx == Theme.THEME_OOSTUDIO and canvas.theme.port_bg_pixmap:
  1601. painter.setPen(Qt.NoPen)
  1602. painter.setBrush(conn_pen.brush())
  1603. if self.m_port_mode == PORT_MODE_INPUT:
  1604. connRect = QRectF(portRect.topLeft(), QSizeF(2, portRect.height()))
  1605. else:
  1606. connRect = QRectF(QPointF(portRect.right()-2, portRect.top()), QSizeF(2, portRect.height()))
  1607. painter.drawRect(connRect)
  1608. self.m_last_selected_state = self.isSelected()
  1609. painter.restore()
  1610. # ------------------------------------------------------------------------------
  1611. # canvasbox.cpp
  1612. class cb_line_t(object):
  1613. __slots__ = [
  1614. 'line',
  1615. 'connection_id'
  1616. ]
  1617. class CanvasBox(QGraphicsItem):
  1618. def __init__(self, group_id, group_name, icon, parent=None):
  1619. QGraphicsItem.__init__(self, parent)
  1620. # Save Variables, useful for later
  1621. self.m_group_id = group_id
  1622. self.m_group_name = group_name
  1623. # plugin Id, < 0 if invalid
  1624. self.m_plugin_id = -1
  1625. self.m_plugin_ui = False
  1626. # Base Variables
  1627. self.p_width = 50
  1628. self.p_height = canvas.theme.box_header_height + canvas.theme.box_header_spacing + 1
  1629. self.m_last_pos = QPointF()
  1630. self.m_splitted = False
  1631. self.m_splitted_mode = PORT_MODE_NULL
  1632. self.m_cursor_moving = False
  1633. self.m_forced_split = False
  1634. self.m_mouse_down = False
  1635. self.m_port_list_ids = []
  1636. self.m_connection_lines = []
  1637. # Set Font
  1638. self.m_font_name = QFont(canvas.theme.box_font_name, canvas.theme.box_font_size, canvas.theme.box_font_state)
  1639. self.m_font_port = QFont(canvas.theme.port_font_name, canvas.theme.port_font_size, canvas.theme.port_font_state)
  1640. # Icon
  1641. if canvas.theme.box_use_icon:
  1642. self.icon_svg = CanvasIcon(icon, self.m_group_name, self)
  1643. else:
  1644. self.icon_svg = None
  1645. # Shadow
  1646. if options.eyecandy:
  1647. self.shadow = CanvasBoxShadow(self.toGraphicsObject())
  1648. self.shadow.setFakeParent(self)
  1649. self.setGraphicsEffect(self.shadow)
  1650. else:
  1651. self.shadow = None
  1652. # Final touches
  1653. self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
  1654. # Wait for at least 1 port
  1655. if options.auto_hide_groups:
  1656. self.setVisible(False)
  1657. self.setFlag(QGraphicsItem.ItemIsFocusable, True)
  1658. self.updatePositions()
  1659. canvas.scene.addItem(self)
  1660. def getGroupId(self):
  1661. return self.m_group_id
  1662. def getGroupName(self):
  1663. return self.m_group_name
  1664. def isSplitted(self):
  1665. return self.m_splitted
  1666. def getSplittedMode(self):
  1667. return self.m_splitted_mode
  1668. def getPortCount(self):
  1669. return len(self.m_port_list_ids)
  1670. def getPortList(self):
  1671. return self.m_port_list_ids
  1672. def setAsPlugin(self, plugin_id, hasUi):
  1673. self.m_plugin_id = plugin_id
  1674. self.m_plugin_ui = hasUi
  1675. def setIcon(self, icon):
  1676. if self.icon_svg:
  1677. self.icon_svg.setIcon(icon, self.m_group_name)
  1678. def setSplit(self, split, mode=PORT_MODE_NULL):
  1679. self.m_splitted = split
  1680. self.m_splitted_mode = mode
  1681. def setGroupName(self, group_name):
  1682. self.m_group_name = group_name
  1683. self.updatePositions()
  1684. def setShadowOpacity(self, opacity):
  1685. if self.shadow:
  1686. self.shadow.setOpacity(opacity)
  1687. def addPortFromGroup(self, port_id, port_mode, port_type, port_name):
  1688. if len(self.m_port_list_ids) == 0:
  1689. if options.auto_hide_groups:
  1690. if options.eyecandy == EYECANDY_FULL:
  1691. CanvasItemFX(self, True)
  1692. self.setVisible(True)
  1693. new_widget = CanvasPort(port_id, port_name, port_mode, port_type, self)
  1694. port_dict = port_dict_t()
  1695. port_dict.group_id = self.m_group_id
  1696. port_dict.port_id = port_id
  1697. port_dict.port_name = port_name
  1698. port_dict.port_mode = port_mode
  1699. port_dict.port_type = port_type
  1700. port_dict.widget = new_widget
  1701. self.m_port_list_ids.append(port_id)
  1702. return new_widget
  1703. def removePortFromGroup(self, port_id):
  1704. if port_id in self.m_port_list_ids:
  1705. self.m_port_list_ids.remove(port_id)
  1706. else:
  1707. qCritical("PatchCanvas::CanvasBox.removePort(%i) - unable to find port to remove" % port_id)
  1708. return
  1709. if len(self.m_port_list_ids) > 0:
  1710. self.updatePositions()
  1711. elif self.isVisible():
  1712. if options.auto_hide_groups:
  1713. if options.eyecandy == EYECANDY_FULL:
  1714. CanvasItemFX(self, False)
  1715. else:
  1716. self.setVisible(False)
  1717. def addLineFromGroup(self, line, connection_id):
  1718. new_cbline = cb_line_t()
  1719. new_cbline.line = line
  1720. new_cbline.connection_id = connection_id
  1721. self.m_connection_lines.append(new_cbline)
  1722. def removeLineFromGroup(self, connection_id):
  1723. for connection in self.m_connection_lines:
  1724. if connection.connection_id == connection_id:
  1725. self.m_connection_lines.remove(connection)
  1726. return
  1727. qCritical("PatchCanvas::CanvasBox.removeLineFromGroup(%i) - unable to find line to remove" % connection_id)
  1728. def checkItemPos(self):
  1729. if not canvas.size_rect.isNull():
  1730. pos = self.scenePos()
  1731. if not (canvas.size_rect.contains(pos) and canvas.size_rect.contains(pos + QPointF(self.p_width, self.p_height))):
  1732. if pos.x() < canvas.size_rect.x():
  1733. self.setPos(canvas.size_rect.x(), pos.y())
  1734. elif pos.x() + self.p_width > canvas.size_rect.width():
  1735. self.setPos(canvas.size_rect.width() - self.p_width, pos.y())
  1736. pos = self.scenePos()
  1737. if pos.y() < canvas.size_rect.y():
  1738. self.setPos(pos.x(), canvas.size_rect.y())
  1739. elif pos.y() + self.p_height > canvas.size_rect.height():
  1740. self.setPos(pos.x(), canvas.size_rect.height() - self.p_height)
  1741. def removeIconFromScene(self):
  1742. if self.icon_svg:
  1743. canvas.scene.removeItem(self.icon_svg)
  1744. def updatePositions(self):
  1745. self.prepareGeometryChange()
  1746. max_in_width = 0
  1747. max_in_height = canvas.theme.box_header_height + canvas.theme.box_header_spacing
  1748. max_out_width = 0
  1749. max_out_height = canvas.theme.box_header_height + canvas.theme.box_header_spacing
  1750. port_spacing = canvas.theme.port_height + canvas.theme.port_spacing
  1751. have_audio_jack_in = have_midi_jack_in = have_midi_a2j_in = have_midi_alsa_in = False
  1752. have_audio_jack_out = have_midi_jack_out = have_midi_a2j_out = have_midi_alsa_out = False
  1753. # reset box size
  1754. self.p_width = 50
  1755. self.p_height = canvas.theme.box_header_height + canvas.theme.box_header_spacing + 1
  1756. # Check Text Name size
  1757. app_name_size = QFontMetrics(self.m_font_name).width(self.m_group_name) + 30
  1758. if app_name_size > self.p_width:
  1759. self.p_width = app_name_size
  1760. # Get Port List
  1761. port_list = []
  1762. for port in canvas.port_list:
  1763. if port.port_id in self.m_port_list_ids:
  1764. port_list.append(port)
  1765. # Get Max Box Width/Height
  1766. for port in port_list:
  1767. if port.port_mode == PORT_MODE_INPUT:
  1768. max_in_height += port_spacing
  1769. size = QFontMetrics(self.m_font_port).width(port.port_name)
  1770. if size > max_in_width:
  1771. max_in_width = size
  1772. if port.port_type == PORT_TYPE_AUDIO_JACK and not have_audio_jack_in:
  1773. have_audio_jack_in = True
  1774. max_in_height += canvas.theme.port_spacingT
  1775. elif port.port_type == PORT_TYPE_MIDI_JACK and not have_midi_jack_in:
  1776. have_midi_jack_in = True
  1777. max_in_height += canvas.theme.port_spacingT
  1778. elif port.port_type == PORT_TYPE_MIDI_A2J and not have_midi_a2j_in:
  1779. have_midi_a2j_in = True
  1780. max_in_height += canvas.theme.port_spacingT
  1781. elif port.port_type == PORT_TYPE_MIDI_ALSA and not have_midi_alsa_in:
  1782. have_midi_alsa_in = True
  1783. max_in_height += canvas.theme.port_spacingT
  1784. elif port.port_mode == PORT_MODE_OUTPUT:
  1785. max_out_height += port_spacing
  1786. size = QFontMetrics(self.m_font_port).width(port.port_name)
  1787. if size > max_out_width:
  1788. max_out_width = size
  1789. if port.port_type == PORT_TYPE_AUDIO_JACK and not have_audio_jack_out:
  1790. have_audio_jack_out = True
  1791. max_out_height += canvas.theme.port_spacingT
  1792. elif port.port_type == PORT_TYPE_MIDI_JACK and not have_midi_jack_out:
  1793. have_midi_jack_out = True
  1794. max_out_height += canvas.theme.port_spacingT
  1795. elif port.port_type == PORT_TYPE_MIDI_A2J and not have_midi_a2j_out:
  1796. have_midi_a2j_out = True
  1797. max_out_height += canvas.theme.port_spacingT
  1798. elif port.port_type == PORT_TYPE_MIDI_ALSA and not have_midi_alsa_out:
  1799. have_midi_alsa_out = True
  1800. max_out_height += canvas.theme.port_spacingT
  1801. if canvas.theme.port_spacingT == 0:
  1802. max_in_height += 2
  1803. max_out_height += 2
  1804. final_width = 30 + max_in_width + max_out_width
  1805. if final_width > self.p_width:
  1806. self.p_width = final_width
  1807. if max_in_height > self.p_height:
  1808. self.p_height = max_in_height
  1809. if max_out_height > self.p_height:
  1810. self.p_height = max_out_height
  1811. # Remove bottom space
  1812. self.p_height -= canvas.theme.port_spacingT
  1813. if canvas.theme.box_header_spacing > 0:
  1814. if len(port_list) == 0:
  1815. self.p_height -= canvas.theme.box_header_spacing
  1816. else:
  1817. self.p_height -= canvas.theme.box_header_spacing/2
  1818. last_in_pos = canvas.theme.box_header_height + canvas.theme.box_header_spacing
  1819. last_out_pos = canvas.theme.box_header_height + canvas.theme.box_header_spacing
  1820. last_in_type = PORT_TYPE_NULL
  1821. last_out_type = PORT_TYPE_NULL
  1822. # Re-position ports, AUDIO_JACK
  1823. for port in port_list:
  1824. if port.port_type == PORT_TYPE_AUDIO_JACK:
  1825. if port.port_mode == PORT_MODE_INPUT:
  1826. port.widget.setPos(QPointF(1 + canvas.theme.port_offset, last_in_pos))
  1827. port.widget.setPortWidth(max_in_width)
  1828. last_in_pos += port_spacing
  1829. last_in_type = port.port_type
  1830. elif port.port_mode == PORT_MODE_OUTPUT:
  1831. port.widget.setPos(QPointF(self.p_width - max_out_width - canvas.theme.port_offset - 13, last_out_pos))
  1832. port.widget.setPortWidth(max_out_width)
  1833. last_out_pos += port_spacing
  1834. last_out_type = port.port_type
  1835. # Re-position ports, MIDI_JACK
  1836. for port in port_list:
  1837. if port.port_type == PORT_TYPE_MIDI_JACK:
  1838. if port.port_mode == PORT_MODE_INPUT:
  1839. if last_in_type != PORT_TYPE_NULL and port.port_type != last_in_type:
  1840. last_in_pos += canvas.theme.port_spacingT
  1841. port.widget.setPos(QPointF(1 + canvas.theme.port_offset, last_in_pos))
  1842. port.widget.setPortWidth(max_in_width)
  1843. last_in_pos += port_spacing
  1844. last_in_type = port.port_type
  1845. elif port.port_mode == PORT_MODE_OUTPUT:
  1846. if last_out_type != PORT_TYPE_NULL and port.port_type != last_out_type:
  1847. last_out_pos += canvas.theme.port_spacingT
  1848. port.widget.setPos(QPointF(self.p_width - max_out_width - canvas.theme.port_offset - 13, last_out_pos))
  1849. port.widget.setPortWidth(max_out_width)
  1850. last_out_pos += port_spacing
  1851. last_out_type = port.port_type
  1852. # Re-position ports, MIDI_A2J
  1853. for port in port_list:
  1854. if port.port_type == PORT_TYPE_MIDI_A2J:
  1855. if port.port_mode == PORT_MODE_INPUT:
  1856. if last_in_type != PORT_TYPE_NULL and port.port_type != last_in_type:
  1857. last_in_pos += canvas.theme.port_spacingT
  1858. port.widget.setPos(QPointF(1 + canvas.theme.port_offset, last_in_pos))
  1859. port.widget.setPortWidth(max_in_width)
  1860. last_in_pos += port_spacing
  1861. last_in_type = port.port_type
  1862. elif port.port_mode == PORT_MODE_OUTPUT:
  1863. if last_out_type != PORT_TYPE_NULL and port.port_type != last_out_type:
  1864. last_out_pos += canvas.theme.port_spacingT
  1865. port.widget.setPos(QPointF(self.p_width - max_out_width - canvas.theme.port_offset - 13, last_out_pos))
  1866. port.widget.setPortWidth(max_out_width)
  1867. last_out_pos += port_spacing
  1868. last_out_type = port.port_type
  1869. # Re-position ports, MIDI_ALSA
  1870. for port in port_list:
  1871. if port.port_type == PORT_TYPE_MIDI_ALSA:
  1872. if port.port_mode == PORT_MODE_INPUT:
  1873. if last_in_type != PORT_TYPE_NULL and port.port_type != last_in_type:
  1874. last_in_pos += canvas.theme.port_spacingT
  1875. port.widget.setPos(QPointF(1 + canvas.theme.port_offset, last_in_pos))
  1876. port.widget.setPortWidth(max_in_width)
  1877. last_in_pos += port_spacing
  1878. last_in_type = port.port_type
  1879. elif port.port_mode == PORT_MODE_OUTPUT:
  1880. if last_out_type != PORT_TYPE_NULL and port.port_type != last_out_type:
  1881. last_out_pos += canvas.theme.port_spacingT
  1882. port.widget.setPos(QPointF(self.p_width - max_out_width - canvas.theme.port_offset - 13, last_out_pos))
  1883. port.widget.setPortWidth(max_out_width)
  1884. last_out_pos += port_spacing
  1885. last_out_type = port.port_type
  1886. self.repaintLines(True)
  1887. self.update()
  1888. def repaintLines(self, forced=False):
  1889. if self.pos() != self.m_last_pos or forced:
  1890. for connection in self.m_connection_lines:
  1891. connection.line.updateLinePos()
  1892. self.m_last_pos = self.pos()
  1893. def resetLinesZValue(self):
  1894. for connection in canvas.connection_list:
  1895. if connection.port_out_id in self.m_port_list_ids and connection.port_in_id in self.m_port_list_ids:
  1896. z_value = canvas.last_z_value
  1897. else:
  1898. z_value = canvas.last_z_value - 1
  1899. connection.widget.setZValue(z_value)
  1900. def type(self):
  1901. return CanvasBoxType
  1902. def contextMenuEvent(self, event):
  1903. menu = QMenu()
  1904. discMenu = QMenu("Disconnect", menu)
  1905. port_con_list = []
  1906. port_con_list_ids = []
  1907. for port_id in self.m_port_list_ids:
  1908. tmp_port_con_list = CanvasGetPortConnectionList(port_id)
  1909. for port_con_id in tmp_port_con_list:
  1910. if port_con_id not in port_con_list:
  1911. port_con_list.append(port_con_id)
  1912. port_con_list_ids.append(port_id)
  1913. if len(port_con_list) > 0:
  1914. for i in range(len(port_con_list)):
  1915. port_con_id = CanvasGetConnectedPort(port_con_list[i], port_con_list_ids[i])
  1916. act_x_disc = discMenu.addAction(CanvasGetFullPortName(port_con_id))
  1917. act_x_disc.setData(port_con_list[i])
  1918. act_x_disc.triggered.connect(canvas.qobject.PortContextMenuDisconnect)
  1919. else:
  1920. act_x_disc = discMenu.addAction("No connections")
  1921. act_x_disc.setEnabled(False)
  1922. menu.addMenu(discMenu)
  1923. act_x_disc_all = menu.addAction("Disconnect &All")
  1924. act_x_sep1 = menu.addSeparator()
  1925. act_x_info = menu.addAction("&Info")
  1926. act_x_rename = menu.addAction("&Rename")
  1927. act_x_sep2 = menu.addSeparator()
  1928. act_x_split_join = menu.addAction("Join" if self.m_splitted else "Split")
  1929. if not features.group_info:
  1930. act_x_info.setVisible(False)
  1931. if not features.group_rename:
  1932. act_x_rename.setVisible(False)
  1933. if not (features.group_info and features.group_rename):
  1934. act_x_sep1.setVisible(False)
  1935. if self.m_plugin_id >= 0:
  1936. menu.addSeparator()
  1937. act_p_edit = menu.addAction("&Edit")
  1938. act_p_ui = menu.addAction("&Show Custom UI")
  1939. menu.addSeparator()
  1940. act_p_clone = menu.addAction("&Clone")
  1941. act_p_rename = menu.addAction("&Rename...")
  1942. act_p_remove = menu.addAction("Re&move")
  1943. if not self.m_plugin_ui:
  1944. act_p_ui.setVisible(False)
  1945. else:
  1946. act_p_edit = act_p_ui = None
  1947. act_p_clone = act_p_rename = act_p_remove = None
  1948. haveIns = haveOuts = False
  1949. for port in canvas.port_list:
  1950. if port.port_id in self.m_port_list_ids:
  1951. if port.port_mode == PORT_MODE_INPUT:
  1952. haveIns = True
  1953. elif port.port_mode == PORT_MODE_OUTPUT:
  1954. haveOuts = True
  1955. if not (self.m_splitted or bool(haveIns and haveOuts)):
  1956. act_x_sep2.setVisible(False)
  1957. act_x_split_join.setVisible(False)
  1958. act_selected = menu.exec_(event.screenPos())
  1959. if act_selected is None:
  1960. pass
  1961. elif act_selected == act_x_disc_all:
  1962. for port_id in port_con_list:
  1963. canvas.callback(ACTION_PORTS_DISCONNECT, port_id, 0, "")
  1964. elif act_selected == act_x_info:
  1965. canvas.callback(ACTION_GROUP_INFO, self.m_group_id, 0, "")
  1966. elif act_selected == act_x_rename:
  1967. new_name_try = QInputDialog.getText(None, "Rename Group", "New name:", QLineEdit.Normal, self.m_group_name)
  1968. if new_name_try[1] and new_name_try[0]: # 1 - bool ok, 0 - return text
  1969. canvas.callback(ACTION_GROUP_RENAME, self.m_group_id, 0, new_name_try[0])
  1970. elif act_selected == act_x_split_join:
  1971. if self.m_splitted:
  1972. canvas.callback(ACTION_GROUP_JOIN, self.m_group_id, 0, "")
  1973. else:
  1974. canvas.callback(ACTION_GROUP_SPLIT, self.m_group_id, 0, "")
  1975. elif act_selected == act_p_edit:
  1976. canvas.callback(ACTION_PLUGIN_EDIT, self.m_plugin_id, 0, "")
  1977. elif act_selected == act_p_ui:
  1978. canvas.callback(ACTION_PLUGIN_SHOW_UI, self.m_plugin_id, 0, "")
  1979. elif act_selected == act_p_clone:
  1980. canvas.callback(ACTION_PLUGIN_CLONE, self.m_plugin_id, 0, "")
  1981. elif act_selected == act_p_rename:
  1982. new_name_try = QInputDialog.getText(None, "Rename Plugin", "New name:", QLineEdit.Normal, self.m_group_name)
  1983. if new_name_try[1] and new_name_try[0]: # 1 - bool ok, 0 - return text
  1984. canvas.callback(ACTION_PLUGIN_RENAME, self.m_plugin_id, 0, new_name_try[0])
  1985. elif act_selected == act_p_remove:
  1986. canvas.callback(ACTION_PLUGIN_REMOVE, self.m_plugin_id, 0, "")
  1987. event.accept()
  1988. def keyPressEvent(self, event):
  1989. if self.m_plugin_id >= 0 and event.key() == Qt.Key_Delete:
  1990. canvas.callback(ACTION_PLUGIN_REMOVE, self.m_plugin_id, 0, "")
  1991. return event.accept()
  1992. QGraphicsItem.keyPressEvent(self, event)
  1993. def mouseDoubleClickEvent(self, event):
  1994. if self.m_plugin_id >= 0:
  1995. canvas.callback(ACTION_PLUGIN_SHOW_UI if self.m_plugin_ui else ACTION_PLUGIN_EDIT, self.m_plugin_id, 0, "")
  1996. return event.accept()
  1997. QGraphicsItem.mouseDoubleClickEvent(self, event)
  1998. def mousePressEvent(self, event):
  1999. canvas.last_z_value += 1
  2000. self.setZValue(canvas.last_z_value)
  2001. self.resetLinesZValue()
  2002. self.m_cursor_moving = False
  2003. if event.button() == Qt.RightButton:
  2004. canvas.scene.clearSelection()
  2005. self.setSelected(True)
  2006. self.m_mouse_down = False
  2007. return event.accept()
  2008. elif event.button() == Qt.LeftButton:
  2009. if self.sceneBoundingRect().contains(event.scenePos()):
  2010. self.m_mouse_down = True
  2011. else:
  2012. # Fix a weird Qt behaviour with right-click mouseMove
  2013. self.m_mouse_down = False
  2014. return event.ignore()
  2015. else:
  2016. self.m_mouse_down = False
  2017. QGraphicsItem.mousePressEvent(self, event)
  2018. def mouseMoveEvent(self, event):
  2019. if self.m_mouse_down:
  2020. if not self.m_cursor_moving:
  2021. self.setCursor(QCursor(Qt.SizeAllCursor))
  2022. self.m_cursor_moving = True
  2023. self.repaintLines()
  2024. QGraphicsItem.mouseMoveEvent(self, event)
  2025. def mouseReleaseEvent(self, event):
  2026. if self.m_cursor_moving:
  2027. self.setCursor(QCursor(Qt.ArrowCursor))
  2028. self.m_mouse_down = False
  2029. self.m_cursor_moving = False
  2030. QGraphicsItem.mouseReleaseEvent(self, event)
  2031. def boundingRect(self):
  2032. return QRectF(0, 0, self.p_width, self.p_height)
  2033. def paint(self, painter, option, widget):
  2034. painter.save()
  2035. painter.setRenderHint(QPainter.Antialiasing, False)
  2036. # Draw rectangle
  2037. if self.isSelected():
  2038. painter.setPen(canvas.theme.box_pen_sel)
  2039. else:
  2040. painter.setPen(canvas.theme.box_pen)
  2041. if canvas.theme.box_bg_type == Theme.THEME_BG_GRADIENT:
  2042. box_gradient = QLinearGradient(0, 0, 0, self.p_height)
  2043. box_gradient.setColorAt(0, canvas.theme.box_bg_1)
  2044. box_gradient.setColorAt(1, canvas.theme.box_bg_2)
  2045. painter.setBrush(box_gradient)
  2046. else:
  2047. painter.setBrush(canvas.theme.box_bg_1)
  2048. painter.drawRect(0, 0, self.p_width, self.p_height)
  2049. # Draw pixmap header
  2050. if canvas.theme.box_header_pixmap:
  2051. painter.setPen(Qt.NoPen)
  2052. painter.setBrush(canvas.theme.box_bg_2)
  2053. painter.drawRect(1, 1, self.p_width-2, canvas.theme.box_header_height)
  2054. headerPos = QPointF(1, 1)
  2055. headerRect = QRectF(2, 2, self.p_width-4, canvas.theme.box_header_height-3)
  2056. painter.drawTiledPixmap(headerRect, canvas.theme.box_header_pixmap, headerPos)
  2057. # Draw text
  2058. painter.setFont(self.m_font_name)
  2059. if self.isSelected():
  2060. painter.setPen(canvas.theme.box_text_sel)
  2061. else:
  2062. painter.setPen(canvas.theme.box_text)
  2063. if canvas.theme.box_use_icon:
  2064. textPos = QPointF(25, canvas.theme.box_text_ypos)
  2065. else:
  2066. appNameSize = QFontMetrics(self.m_font_name).width(self.m_group_name)
  2067. rem = self.p_width - appNameSize
  2068. textPos = QPointF(rem/2, canvas.theme.box_text_ypos)
  2069. painter.drawText(textPos, self.m_group_name)
  2070. self.repaintLines()
  2071. painter.restore()
  2072. # ------------------------------------------------------------------------------
  2073. # canvasicon.cpp
  2074. class CanvasIcon(QGraphicsSvgItem):
  2075. def __init__(self, icon, name, parent):
  2076. QGraphicsSvgItem.__init__(self, parent)
  2077. self.m_renderer = None
  2078. self.p_size = QRectF(0, 0, 0, 0)
  2079. self.m_colorFX = QGraphicsColorizeEffect(self)
  2080. self.m_colorFX.setColor(canvas.theme.box_text.color())
  2081. self.setGraphicsEffect(self.m_colorFX)
  2082. self.setIcon(icon, name)
  2083. def setIcon(self, icon, name):
  2084. name = name.lower()
  2085. icon_path = ""
  2086. if icon == ICON_APPLICATION:
  2087. self.p_size = QRectF(3, 2, 19, 18)
  2088. if "audacious" in name:
  2089. icon_path = ":/scalable/pb_audacious.svg"
  2090. self.p_size = QRectF(5, 4, 16, 16)
  2091. elif "clementine" in name:
  2092. icon_path = ":/scalable/pb_clementine.svg"
  2093. self.p_size = QRectF(5, 4, 16, 16)
  2094. elif "distrho" in name:
  2095. icon_path = ":/scalable/pb_distrho.svg"
  2096. self.p_size = QRectF(5, 4, 14, 14)
  2097. elif "jamin" in name:
  2098. icon_path = ":/scalable/pb_jamin.svg"
  2099. self.p_size = QRectF(5, 3, 16, 16)
  2100. elif "mplayer" in name:
  2101. icon_path = ":/scalable/pb_mplayer.svg"
  2102. self.p_size = QRectF(5, 4, 16, 16)
  2103. elif "vlc" in name:
  2104. icon_path = ":/scalable/pb_vlc.svg"
  2105. self.p_size = QRectF(5, 3, 16, 16)
  2106. else:
  2107. icon_path = ":/scalable/pb_generic.svg"
  2108. self.p_size = QRectF(4, 3, 16, 16)
  2109. elif icon == ICON_HARDWARE:
  2110. icon_path = ":/scalable/pb_hardware.svg"
  2111. self.p_size = QRectF(5, 2, 16, 16)
  2112. elif icon == ICON_DISTRHO:
  2113. icon_path = ":/scalable/pb_distrho.svg"
  2114. self.p_size = QRectF(5, 4, 14, 14)
  2115. elif icon == ICON_FILE:
  2116. icon_path = ":/scalable/pb_file.svg"
  2117. self.p_size = QRectF(5, 4, 12, 14)
  2118. elif icon == ICON_PLUGIN:
  2119. icon_path = ":/scalable/pb_plugin.svg"
  2120. self.p_size = QRectF(5, 4, 14, 14)
  2121. elif icon == ICON_LADISH_ROOM:
  2122. # TODO - make a unique ladish-room icon
  2123. icon_path = ":/scalable/pb_hardware.svg"
  2124. self.p_size = QRectF(5, 2, 16, 16)
  2125. else:
  2126. self.p_size = QRectF(0, 0, 0, 0)
  2127. qCritical("PatchCanvas::CanvasIcon.setIcon(%s, %s) - unsupported icon requested" % (icon2str(icon), name.encode()))
  2128. return
  2129. self.m_renderer = QSvgRenderer(icon_path, canvas.scene)
  2130. self.setSharedRenderer(self.m_renderer)
  2131. self.update()
  2132. def type(self):
  2133. return CanvasIconType
  2134. def boundingRect(self):
  2135. return self.p_size
  2136. def paint(self, painter, option, widget):
  2137. if self.m_renderer:
  2138. painter.save()
  2139. painter.setRenderHint(QPainter.Antialiasing, False)
  2140. painter.setRenderHint(QPainter.TextAntialiasing, False)
  2141. self.m_renderer.render(painter, self.p_size)
  2142. painter.restore()
  2143. else:
  2144. QGraphicsSvgItem.paint(self, painter, option, widget)
  2145. # ------------------------------------------------------------------------------
  2146. # canvasportglow.cpp
  2147. class CanvasPortGlow(QGraphicsDropShadowEffect):
  2148. def __init__(self, port_type, parent):
  2149. QGraphicsDropShadowEffect.__init__(self, parent)
  2150. self.setBlurRadius(12)
  2151. self.setOffset(0, 0)
  2152. if port_type == PORT_TYPE_AUDIO_JACK:
  2153. self.setColor(canvas.theme.line_audio_jack_glow)
  2154. elif port_type == PORT_TYPE_MIDI_JACK:
  2155. self.setColor(canvas.theme.line_midi_jack_glow)
  2156. elif port_type == PORT_TYPE_MIDI_A2J:
  2157. self.setColor(canvas.theme.line_midi_a2j_glow)
  2158. elif port_type == PORT_TYPE_MIDI_ALSA:
  2159. self.setColor(canvas.theme.line_midi_alsa_glow)
  2160. # ------------------------------------------------------------------------------
  2161. # canvasboxshadow.cpp
  2162. class CanvasBoxShadow(QGraphicsDropShadowEffect):
  2163. def __init__(self, parent):
  2164. QGraphicsDropShadowEffect.__init__(self, parent)
  2165. self.m_fakeParent = None
  2166. self.setBlurRadius(20)
  2167. self.setColor(canvas.theme.box_shadow)
  2168. self.setOffset(0, 0)
  2169. def setFakeParent(self, fakeParent):
  2170. self.m_fakeParent = fakeParent
  2171. def setOpacity(self, opacity):
  2172. color = QColor(canvas.theme.box_shadow)
  2173. color.setAlphaF(opacity)
  2174. self.setColor(color)
  2175. def draw(self, painter):
  2176. if self.m_fakeParent:
  2177. self.m_fakeParent.repaintLines()
  2178. QGraphicsDropShadowEffect.draw(self, painter)