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.

2642 lines
92KB

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