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 92KB

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