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