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.

carla_rack.py 22KB

11 years ago
11 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla rack widget code
  4. # Copyright (C) 2011-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. if config_UseQt5:
  23. from PyQt5.QtCore import Qt, QSize, QTimer
  24. from PyQt5.QtGui import QPixmap
  25. from PyQt5.QtWidgets import QAbstractItemView, QApplication, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QScrollBar
  26. else:
  27. from PyQt4.QtCore import Qt, QSize, QTimer
  28. from PyQt4.QtGui import QAbstractItemView, QApplication, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPixmap, QScrollBar
  29. # ------------------------------------------------------------------------------------------------------------
  30. # Imports (Custom Stuff)
  31. from carla_skin import *
  32. # ------------------------------------------------------------------------------------------------------------
  33. # Rack widget item
  34. class CarlaRackItem(QListWidgetItem):
  35. kRackItemType = QListWidgetItem.UserType + 1
  36. def __init__(self, parent, pluginId):
  37. QListWidgetItem.__init__(self, parent, self.kRackItemType)
  38. self.fParent = parent
  39. self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
  40. #self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsDragEnabled|Qt.ItemIsDropEnabled)
  41. self.createWidget(pluginId)
  42. # -----------------------------------------------------------------
  43. def createWidget(self, pluginId):
  44. self.widget = createPluginSlot(self.fParent, pluginId)
  45. self.widget.setFixedHeight(self.widget.getFixedHeight())
  46. self.setSizeHint(QSize(640, self.widget.getFixedHeight()))
  47. self.fParent.setItemWidget(self, self.widget)
  48. # -----------------------------------------------------------------
  49. def close(self):
  50. self.widget.fEditDialog.close()
  51. def reloadAll(self, pluginId):
  52. self.widget.fEditDialog.close()
  53. del self.widget
  54. self.createWidget(pluginId)
  55. # ------------------------------------------------------------------------------------------------------------
  56. # Rack widget list
  57. class CarlaRackList(QListWidget):
  58. def __init__(self, parent):
  59. QListWidget.__init__(self, parent)
  60. exts = gCarla.host.get_supported_file_extensions().split(";") if gCarla.host is not None else ["wav",]
  61. # plugin files
  62. exts.append("dll")
  63. if MACOS:
  64. exts.append("dylib")
  65. if not WINDOWS:
  66. exts.append("so")
  67. self.fSupportedExtensions = tuple(i.replace("*.","") for i in exts)
  68. self.fWasLastDragValid = False
  69. self.setMinimumWidth(640+20) # required by zita, 591 was old value
  70. self.setSelectionMode(QAbstractItemView.SingleSelection)
  71. self.setSortingEnabled(False)
  72. #self.setSortingEnabled(True)
  73. self.setDragEnabled(True)
  74. self.setDragDropMode(QAbstractItemView.DropOnly)
  75. self.setDropIndicatorShown(True)
  76. self.viewport().setAcceptDrops(True)
  77. self.setFrameShape(QFrame.NoFrame)
  78. self.setFrameShadow(QFrame.Plain)
  79. self.fPixmapL = QPixmap(":/bitmaps/rack_interior_left.png")
  80. self.fPixmapR = QPixmap(":/bitmaps/rack_interior_right.png")
  81. self.fPixmapWidth = self.fPixmapL.width()
  82. def isDragEventValid(self, urls):
  83. for url in urls:
  84. filename = url.toLocalFile()
  85. if os.path.isdir(filename):
  86. if os.path.exists(os.path.join(filename, "manifest.ttl")):
  87. return True
  88. elif os.path.isfile(filename):
  89. if filename.lower().endswith(self.fSupportedExtensions):
  90. return True
  91. return False
  92. def dragEnterEvent(self, event):
  93. if self.isDragEventValid(event.mimeData().urls()):
  94. self.fWasLastDragValid = True
  95. event.acceptProposedAction()
  96. return
  97. self.fWasLastDragValid = False
  98. QListWidget.dragEnterEvent(self, event)
  99. def dragMoveEvent(self, event):
  100. if self.fWasLastDragValid:
  101. event.acceptProposedAction()
  102. tryItem = self.itemAt(event.pos())
  103. if tryItem is not None:
  104. self.setCurrentRow(tryItem.widget.getPluginId())
  105. else:
  106. self.setCurrentRow(-1)
  107. return
  108. QListWidget.dragMoveEvent(self, event)
  109. #def dragLeaveEvent(self, event):
  110. #self.fWasLastDragValid = False
  111. #QListWidget.dragLeaveEvent(self, event)
  112. def dropEvent(self, event):
  113. event.acceptProposedAction()
  114. urls = event.mimeData().urls()
  115. if len(urls) == 0:
  116. return
  117. tryItem = self.itemAt(event.pos())
  118. if tryItem is not None:
  119. pluginId = tryItem.widget.getPluginId()
  120. gCarla.host.replace_plugin(pluginId)
  121. for url in urls:
  122. filename = url.toLocalFile()
  123. if not gCarla.host.load_file(filename):
  124. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"),
  125. self.tr("Failed to load file"),
  126. gCarla.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  127. if tryItem is not None:
  128. gCarla.host.replace_plugin(self.parent().fPluginCount)
  129. #tryItem.widget.setActive(True, True, True)
  130. def mousePressEvent(self, event):
  131. if self.itemAt(event.pos()) is None:
  132. event.accept()
  133. self.setCurrentRow(-1)
  134. return
  135. QListWidget.mousePressEvent(self, event)
  136. def paintEvent(self, event):
  137. painter = QPainter(self.viewport())
  138. painter.drawTiledPixmap(0, 0, self.fPixmapWidth, self.height(), self.fPixmapL)
  139. painter.drawTiledPixmap(self.width()-self.fPixmapWidth-2, 0, self.fPixmapWidth, self.height(), self.fPixmapR)
  140. QListWidget.paintEvent(self, event)
  141. # ------------------------------------------------------------------------------------------------------------
  142. # Rack widget
  143. class CarlaRackW(QFrame):
  144. def __init__(self, parent, doSetup = True):
  145. QFrame.__init__(self, parent)
  146. self.fLayout = QHBoxLayout(self)
  147. self.fLayout.setContentsMargins(0, 0, 0, 0)
  148. self.fLayout.setSpacing(0)
  149. self.setLayout(self.fLayout)
  150. self.fPadLeft = QLabel(self)
  151. self.fPadLeft.setFixedWidth(25)
  152. self.fPadLeft.setObjectName("PadLeft")
  153. self.fPadLeft.setText("")
  154. self.fPadRight = QLabel(self)
  155. self.fPadRight.setFixedWidth(25)
  156. self.fPadRight.setObjectName("PadRight")
  157. self.fPadRight.setText("")
  158. self.fRack = CarlaRackList(self)
  159. self.fRack.setObjectName("CarlaRackList")
  160. self.fRack.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
  161. self.fRack.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
  162. self.fRack.currentRowChanged.connect(self.slot_currentRowChanged)
  163. sb = self.fRack.verticalScrollBar()
  164. self.fScrollBar = QScrollBar(Qt.Vertical, self)
  165. self.fScrollBar.setMinimum(sb.minimum())
  166. self.fScrollBar.setMaximum(sb.maximum())
  167. self.fScrollBar.setValue(sb.value())
  168. #sb.actionTriggered.connect(self.fScrollBar.triggerAction)
  169. #sb.sliderMoved.connect(self.fScrollBar.)
  170. #sb.sliderPressed.connect(self.fScrollBar.)
  171. #sb.sliderReleased.connect(self.fScrollBar.)
  172. sb.rangeChanged.connect(self.fScrollBar.setRange)
  173. sb.valueChanged.connect(self.fScrollBar.setValue)
  174. self.fScrollBar.rangeChanged.connect(sb.setRange)
  175. self.fScrollBar.valueChanged.connect(sb.setValue)
  176. self.fLayout.addWidget(self.fPadLeft)
  177. self.fLayout.addWidget(self.fRack)
  178. self.fLayout.addWidget(self.fPadRight)
  179. self.fLayout.addWidget(self.fScrollBar)
  180. # -------------------------------------------------------------
  181. # Internal stuff
  182. self.fParent = parent
  183. self.fPluginCount = 0
  184. self.fPluginList = []
  185. self.fCurrentRow = -1
  186. self.fLastSelectedItem = None
  187. # -------------------------------------------------------------
  188. # Set-up GUI stuff
  189. #app = QApplication.instance()
  190. #pal1 = app.palette().base().color()
  191. #pal2 = app.palette().button().color()
  192. #col1 = "stop:0 rgb(%i, %i, %i)" % (pal1.red(), pal1.green(), pal1.blue())
  193. #col2 = "stop:1 rgb(%i, %i, %i)" % (pal2.red(), pal2.green(), pal2.blue())
  194. self.setStyleSheet("""
  195. QLabel#PadLeft {
  196. background-image: url(:/bitmaps/rack_padding_left.png);
  197. background-repeat: repeat-y;
  198. }
  199. QLabel#PadRight {
  200. background-image: url(:/bitmaps/rack_padding_right.png);
  201. background-repeat: repeat-y;
  202. }
  203. CarlaRackList#CarlaRackList {
  204. background-color: black;
  205. }
  206. """)
  207. # -------------------------------------------------------------
  208. # Connect actions to functions
  209. if not doSetup: return
  210. parent.ui.menu_Canvas.hide()
  211. parent.ui.act_plugins_enable.triggered.connect(self.slot_pluginsEnable)
  212. parent.ui.act_plugins_disable.triggered.connect(self.slot_pluginsDisable)
  213. parent.ui.act_plugins_volume100.triggered.connect(self.slot_pluginsVolume100)
  214. parent.ui.act_plugins_mute.triggered.connect(self.slot_pluginsMute)
  215. parent.ui.act_plugins_wet100.triggered.connect(self.slot_pluginsWet100)
  216. parent.ui.act_plugins_bypass.triggered.connect(self.slot_pluginsBypass)
  217. parent.ui.act_plugins_center.triggered.connect(self.slot_pluginsCenter)
  218. parent.ui.act_plugins_panic.triggered.connect(self.slot_pluginsDisable)
  219. parent.ui.act_settings_configure.triggered.connect(self.slot_configureCarla)
  220. parent.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback)
  221. parent.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback)
  222. parent.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback)
  223. parent.ParameterMidiCcChangedCallback.connect(self.slot_handleParameterMidiCcChangedCallback)
  224. parent.ProgramChangedCallback.connect(self.slot_handleProgramChangedCallback)
  225. parent.MidiProgramChangedCallback.connect(self.slot_handleMidiProgramChangedCallback)
  226. parent.UiStateChangedCallback.connect(self.slot_handleUiStateChangedCallback)
  227. parent.NoteOnCallback.connect(self.slot_handleNoteOnCallback)
  228. parent.NoteOffCallback.connect(self.slot_handleNoteOffCallback)
  229. parent.UpdateCallback.connect(self.slot_handleUpdateCallback)
  230. parent.ReloadInfoCallback.connect(self.slot_handleReloadInfoCallback)
  231. parent.ReloadParametersCallback.connect(self.slot_handleReloadParametersCallback)
  232. parent.ReloadProgramsCallback.connect(self.slot_handleReloadProgramsCallback)
  233. parent.ReloadAllCallback.connect(self.slot_handleReloadAllCallback)
  234. # -----------------------------------------------------------------
  235. def getPluginCount(self):
  236. return self.fPluginCount
  237. # -----------------------------------------------------------------
  238. def addPlugin(self, pluginId, isProjectLoading):
  239. pitem = CarlaRackItem(self.fRack, pluginId)
  240. self.fPluginList.append(pitem)
  241. self.fPluginCount += 1
  242. if not isProjectLoading:
  243. pitem.widget.setActive(True, True, True)
  244. def removePlugin(self, pluginId):
  245. if pluginId >= self.fPluginCount:
  246. return
  247. pitem = self.fPluginList[pluginId]
  248. if pitem is None:
  249. return
  250. self.fPluginCount -= 1
  251. self.fPluginList.pop(pluginId)
  252. self.fRack.takeItem(pluginId)
  253. pitem.close()
  254. del pitem
  255. # push all plugins 1 slot back
  256. for i in range(pluginId, self.fPluginCount):
  257. pitem = self.fPluginList[i]
  258. pitem.widget.setId(i)
  259. def renamePlugin(self, pluginId, newName):
  260. if pluginId >= self.fPluginCount:
  261. return
  262. pitem = self.fPluginList[pluginId]
  263. if pitem is None:
  264. return
  265. pitem.widget.setName(newName)
  266. def disablePlugin(self, pluginId, errorMsg):
  267. if pluginId >= self.fPluginCount:
  268. return
  269. pitem = self.fPluginList[pluginId]
  270. if pitem is None:
  271. return
  272. def removeAllPlugins(self):
  273. while self.fRack.takeItem(0):
  274. pass
  275. for i in range(self.fPluginCount):
  276. pitem = self.fPluginList[i]
  277. if pitem is None:
  278. break
  279. pitem.close()
  280. del pitem
  281. self.fPluginCount = 0
  282. self.fPluginList = []
  283. # -----------------------------------------------------------------
  284. def engineStarted(self):
  285. pass
  286. def engineStopped(self):
  287. pass
  288. def engineChanged(self):
  289. pass
  290. # -----------------------------------------------------------------
  291. def idleFast(self):
  292. for i in range(self.fPluginCount):
  293. pitem = self.fPluginList[i]
  294. if pitem is None:
  295. break
  296. pitem.widget.idleFast()
  297. def idleSlow(self):
  298. for i in range(self.fPluginCount):
  299. pitem = self.fPluginList[i]
  300. if pitem is None:
  301. break
  302. pitem.widget.idleSlow()
  303. # -----------------------------------------------------------------
  304. def projectLoadingStarted(self):
  305. self.fRack.setEnabled(False)
  306. def projectLoadingFinished(self):
  307. self.fRack.setEnabled(True)
  308. # -----------------------------------------------------------------
  309. def saveSettings(self, settings):
  310. pass
  311. def showEditDialog(self, pluginId):
  312. if pluginId >= self.fPluginCount:
  313. return
  314. pitem = self.fPluginList[pluginId]
  315. if pitem is None:
  316. return
  317. pitem.widget.slot_showEditDialog(True)
  318. # -----------------------------------------------------------------
  319. @pyqtSlot()
  320. def slot_pluginsEnable(self):
  321. if not gCarla.host.is_engine_running():
  322. return
  323. for i in range(self.fPluginCount):
  324. pitem = self.fPluginList[i]
  325. if pitem is None:
  326. break
  327. pitem.widget.setActive(True, True, True)
  328. @pyqtSlot()
  329. def slot_pluginsDisable(self):
  330. if not gCarla.host.is_engine_running():
  331. return
  332. for i in range(self.fPluginCount):
  333. pitem = self.fPluginList[i]
  334. if pitem is None:
  335. break
  336. pitem.widget.setActive(False, True, True)
  337. @pyqtSlot()
  338. def slot_pluginsVolume100(self):
  339. if not gCarla.host.is_engine_running():
  340. return
  341. for i in range(self.fPluginCount):
  342. pitem = self.fPluginList[i]
  343. if pitem is None:
  344. break
  345. pitem.widget.setInternalParameter(PLUGIN_CAN_VOLUME, 1.0)
  346. @pyqtSlot()
  347. def slot_pluginsMute(self):
  348. if not gCarla.host.is_engine_running():
  349. return
  350. for i in range(self.fPluginCount):
  351. pitem = self.fPluginList[i]
  352. if pitem is None:
  353. break
  354. pitem.widget.setInternalParameter(PLUGIN_CAN_VOLUME, 0.0)
  355. @pyqtSlot()
  356. def slot_pluginsWet100(self):
  357. if not gCarla.host.is_engine_running():
  358. return
  359. for i in range(self.fPluginCount):
  360. pitem = self.fPluginList[i]
  361. if pitem is None:
  362. break
  363. pitem.widget.setInternalParameter(PLUGIN_CAN_DRYWET, 1.0)
  364. @pyqtSlot()
  365. def slot_pluginsBypass(self):
  366. if not gCarla.host.is_engine_running():
  367. return
  368. for i in range(self.fPluginCount):
  369. pitem = self.fPluginList[i]
  370. if pitem is None:
  371. break
  372. pitem.widget.setInternalParameter(PLUGIN_CAN_DRYWET, 0.0)
  373. @pyqtSlot()
  374. def slot_pluginsCenter(self):
  375. if not gCarla.host.is_engine_running():
  376. return
  377. for i in range(self.fPluginCount):
  378. pitem = self.fPluginList[i]
  379. if pitem is None:
  380. break
  381. pitem.widget.setInternalParameter(PARAMETER_BALANCE_LEFT, -1.0)
  382. pitem.widget.setInternalParameter(PARAMETER_BALANCE_RIGHT, 1.0)
  383. pitem.widget.setInternalParameter(PARAMETER_PANNING, 0.0)
  384. # -----------------------------------------------------------------
  385. @pyqtSlot()
  386. def slot_configureCarla(self):
  387. if self.fParent is None or not self.fParent.openSettingsWindow(False, False):
  388. return
  389. self.fParent.loadSettings(False)
  390. # -----------------------------------------------------------------
  391. @pyqtSlot(int, int, float)
  392. def slot_handleParameterValueChangedCallback(self, pluginId, index, value):
  393. if pluginId >= self.fPluginCount:
  394. return
  395. pitem = self.fPluginList[pluginId]
  396. if pitem is None:
  397. return
  398. pitem.widget.setParameterValue(index, value, True)
  399. @pyqtSlot(int, int, float)
  400. def slot_handleParameterDefaultChangedCallback(self, pluginId, index, value):
  401. if pluginId >= self.fPluginCount:
  402. return
  403. pitem = self.fPluginList[pluginId]
  404. if pitem is None:
  405. return
  406. pitem.widget.setParameterDefault(index, value)
  407. @pyqtSlot(int, int, int)
  408. def slot_handleParameterMidiCcChangedCallback(self, pluginId, index, cc):
  409. if pluginId >= self.fPluginCount:
  410. return
  411. pitem = self.fPluginList[pluginId]
  412. if pitem is None:
  413. return
  414. pitem.widget.setParameterMidiControl(index, cc)
  415. @pyqtSlot(int, int, int)
  416. def slot_handleParameterMidiChannelChangedCallback(self, pluginId, index, channel):
  417. if pluginId >= self.fPluginCount:
  418. return
  419. pitem = self.fPluginList[pluginId]
  420. if pitem is None:
  421. return
  422. pitem.widget.setParameterMidiChannel(index, channel)
  423. # -----------------------------------------------------------------
  424. @pyqtSlot(int, int)
  425. def slot_handleProgramChangedCallback(self, pluginId, index):
  426. if pluginId >= self.fPluginCount:
  427. return
  428. pitem = self.fPluginList[pluginId]
  429. if pitem is None:
  430. return
  431. pitem.widget.setProgram(index, True)
  432. @pyqtSlot(int, int)
  433. def slot_handleMidiProgramChangedCallback(self, pluginId, index):
  434. if pluginId >= self.fPluginCount:
  435. return
  436. pitem = self.fPluginList[pluginId]
  437. if pitem is None:
  438. return
  439. pitem.widget.setMidiProgram(index, True)
  440. # -----------------------------------------------------------------
  441. @pyqtSlot(int, int)
  442. def slot_handleUiStateChangedCallback(self, pluginId, state):
  443. if pluginId >= self.fPluginCount:
  444. return
  445. pitem = self.fPluginList[pluginId]
  446. if pitem is None:
  447. return
  448. pitem.widget.customUiStateChanged(state)
  449. # -----------------------------------------------------------------
  450. @pyqtSlot(int, int, int, int)
  451. def slot_handleNoteOnCallback(self, pluginId, channel, note, velo):
  452. if pluginId >= self.fPluginCount:
  453. return
  454. pitem = self.fPluginList[pluginId]
  455. if pitem is None:
  456. return
  457. pitem.widget.sendNoteOn(channel, note)
  458. @pyqtSlot(int, int, int)
  459. def slot_handleNoteOffCallback(self, pluginId, channel, note):
  460. if pluginId >= self.fPluginCount:
  461. return
  462. pitem = self.fPluginList[pluginId]
  463. if pitem is None:
  464. return
  465. pitem.widget.sendNoteOff(channel, note)
  466. # -----------------------------------------------------------------
  467. @pyqtSlot(int)
  468. def slot_handleUpdateCallback(self, pluginId):
  469. if pluginId >= self.fPluginCount:
  470. return
  471. pitem = self.fPluginList[pluginId]
  472. if pitem is None:
  473. return
  474. pitem.widget.fEditDialog.updateInfo()
  475. @pyqtSlot(int)
  476. def slot_handleReloadInfoCallback(self, pluginId):
  477. if pluginId >= self.fPluginCount:
  478. return
  479. pitem = self.fPluginList[pluginId]
  480. if pitem is None:
  481. return
  482. pitem.widget.fEditDialog.reloadInfo()
  483. @pyqtSlot(int)
  484. def slot_handleReloadParametersCallback(self, pluginId):
  485. if pluginId >= self.fPluginCount:
  486. return
  487. pitem = self.fPluginList[pluginId]
  488. if pitem is None:
  489. return
  490. pitem.widget.fEditDialog.reloadParameters()
  491. @pyqtSlot(int)
  492. def slot_handleReloadProgramsCallback(self, pluginId):
  493. if pluginId >= self.fPluginCount:
  494. return
  495. pitem = self.fPluginList[pluginId]
  496. if pitem is None:
  497. return
  498. pitem.widget.fEditDialog.reloadPrograms()
  499. @pyqtSlot(int)
  500. def slot_handleReloadAllCallback(self, pluginId):
  501. if pluginId >= self.fPluginCount:
  502. return
  503. pitem = self.fPluginList[pluginId]
  504. if pitem is None:
  505. return
  506. self.fRack.setCurrentRow(-1)
  507. self.fCurrentRow = -1
  508. self.fLastSelectedItem = None
  509. pitem.reloadAll(pluginId)
  510. # -----------------------------------------------------------------
  511. @pyqtSlot(int)
  512. def slot_currentRowChanged(self, row):
  513. self.fCurrentRow = row
  514. if self.fLastSelectedItem is not None:
  515. self.fLastSelectedItem.setSelected(False)
  516. if row < 0 or row >= self.fPluginCount or self.fPluginList[row] is None:
  517. self.fLastSelectedItem = None
  518. return
  519. pitem = self.fPluginList[row]
  520. pitem.widget.setSelected(True)
  521. self.fLastSelectedItem = pitem.widget
  522. # -----------------------------------------------------------------