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.

2647 lines
92KB

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