Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

patchcanvas.py 91KB

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