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

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