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.

2773 lines
96KB

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