diff --git a/resources/16x16/bookmarks.svgz b/resources/16x16/bookmarks.svgz new file mode 100644 index 000000000..fd7d38b5e Binary files /dev/null and b/resources/16x16/bookmarks.svgz differ diff --git a/resources/resources.qrc b/resources/resources.qrc index 479416f29..51dc4a126 100644 --- a/resources/resources.qrc +++ b/resources/resources.qrc @@ -5,6 +5,7 @@ 16x16/application-exit.svgz 16x16/arrow-right.svgz + 16x16/bookmarks.svgz 16x16/configure.svgz 16x16/dialog-cancel.svgz 16x16/dialog-error.svgz diff --git a/resources/ui/carla_database.ui b/resources/ui/carla_database.ui index 929d9ada3..2844dc723 100644 --- a/resources/ui/carla_database.ui +++ b/resources/ui/carla_database.ui @@ -25,7 +25,7 @@ 0 0 164 - 268 + 254 @@ -253,37 +253,44 @@ - + - With Inline Display + With Custom GUI - - + + - Stereo only + With CV Ports - + Real-time safe only - - + + - With Custom GUI + Stereo only - - + + - With CV Ports + With Inline Display + + + + + + + Favorites only @@ -758,6 +765,9 @@ false + + 24 + true @@ -770,6 +780,21 @@ 22 + + + + + + + + + + + + + :/16x16/bookmarks.svgz:/16x16/bookmarks.svgz + + Name diff --git a/source/frontend/carla_database.py b/source/frontend/carla_database.py index ddfb787bd..414e97bb2 100755 --- a/source/frontend/carla_database.py +++ b/source/frontend/carla_database.py @@ -24,7 +24,7 @@ from subprocess import Popen, PIPE from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QEventLoop, QThread, QSettings from PyQt5.QtGui import QPixmap -from PyQt5.QtWidgets import QApplication, QDialog, QDialogButtonBox, QTableWidgetItem +from PyQt5.QtWidgets import QApplication, QDialog, QDialogButtonBox, QHeaderView, QTableWidgetItem # --------------------------------------------------------------------------------------------------------------------- # Imports (Custom) @@ -1380,10 +1380,11 @@ class PluginRefreshW(QDialog): # Plugin Database Dialog class PluginDatabaseW(QDialog): - TABLEWIDGET_ITEM_NAME = 0 - TABLEWIDGET_ITEM_LABEL = 1 - TABLEWIDGET_ITEM_MAKER = 2 - TABLEWIDGET_ITEM_BINARY = 3 + TABLEWIDGET_ITEM_FAVORITE = 0 + TABLEWIDGET_ITEM_NAME = 1 + TABLEWIDGET_ITEM_LABEL = 2 + TABLEWIDGET_ITEM_MAKER = 3 + TABLEWIDGET_ITEM_BINARY = 4 def __init__(self, parent, host): QDialog.__init__(self, parent) @@ -1402,6 +1403,8 @@ class PluginDatabaseW(QDialog): self.fLastTableIndex = 0 self.fRetPlugin = None self.fRealParent = parent + self.fFavoritePlugins = [] + self.fFavoritePluginsChanged = False self.fTrYes = self.tr("Yes") self.fTrNo = self.tr("No") @@ -1468,7 +1471,8 @@ class PluginDatabaseW(QDialog): self.ui.b_clear_filters.clicked.connect(self.slot_clearFilters) self.ui.lineEdit.textChanged.connect(self.slot_checkFilters) self.ui.tableWidget.currentCellChanged.connect(self.slot_checkPlugin) - self.ui.tableWidget.cellDoubleClicked.connect(self.slot_addPlugin) + self.ui.tableWidget.cellClicked.connect(self.slot_cellClicked) + self.ui.tableWidget.cellDoubleClicked.connect(self.slot_cellDoubleClicked) self.ui.ch_internal.clicked.connect(self.slot_checkFilters) self.ui.ch_ladspa.clicked.connect(self.slot_checkFilters) @@ -1485,6 +1489,7 @@ class PluginDatabaseW(QDialog): self.ui.ch_native.clicked.connect(self.slot_checkFilters) self.ui.ch_bridged.clicked.connect(self.slot_checkFilters) self.ui.ch_bridged_wine.clicked.connect(self.slot_checkFilters) + self.ui.ch_favorites.clicked.connect(self.slot_checkFilters) self.ui.ch_rtsafe.clicked.connect(self.slot_checkFilters) self.ui.ch_cv.clicked.connect(self.slot_checkFilters) self.ui.ch_gui.clicked.connect(self.slot_checkFilters) @@ -1499,10 +1504,34 @@ class PluginDatabaseW(QDialog): # -------------------------------------------------------------------------------------------------------- + @pyqtSlot(int, int) + def slot_cellClicked(self, row, column): + if column == self.TABLEWIDGET_ITEM_FAVORITE: + widget = self.ui.tableWidget.item(row, self.TABLEWIDGET_ITEM_FAVORITE) + plugin = self.ui.tableWidget.item(row, self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) + plugin = self._createFavoritePluginDict(plugin) + + if widget.checkState() == Qt.Checked: + if not plugin in self.fFavoritePlugins: + self.fFavoritePlugins.append(plugin) + self.fFavoritePluginsChanged = True + else: + try: + self.fFavoritePlugins.remove(plugin) + self.fFavoritePluginsChanged = True + except ValueError: + pass + + @pyqtSlot(int, int) + def slot_cellDoubleClicked(self, row, column): + if column != self.TABLEWIDGET_ITEM_FAVORITE: + self.slot_addPlugin() + @pyqtSlot() def slot_addPlugin(self): if self.ui.tableWidget.currentRow() >= 0: - self.fRetPlugin = self.ui.tableWidget.item(self.ui.tableWidget.currentRow(), 0).data(Qt.UserRole+1) + self.fRetPlugin = self.ui.tableWidget.item(self.ui.tableWidget.currentRow(), + self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) self.accept() else: self.reject() @@ -1511,7 +1540,8 @@ class PluginDatabaseW(QDialog): def slot_checkPlugin(self, row): if row >= 0: self.ui.b_add.setEnabled(True) - plugin = self.ui.tableWidget.item(self.ui.tableWidget.currentRow(), 0).data(Qt.UserRole+1) + plugin = self.ui.tableWidget.item(self.ui.tableWidget.currentRow(), + self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) isSynth = bool(plugin['hints'] & PLUGIN_IS_SYNTH) isEffect = bool(plugin['audio.ins'] > 0 < plugin['audio.outs'] and not isSynth) @@ -1610,6 +1640,7 @@ class PluginDatabaseW(QDialog): self.ui.ch_bridged.setChecked(False) self.ui.ch_bridged_wine.setChecked(False) + self.ui.ch_favorites.setChecked(False) self.ui.ch_rtsafe.setChecked(False) self.ui.ch_stereo.setChecked(False) self.ui.ch_cv.setChecked(False) @@ -1621,6 +1652,8 @@ class PluginDatabaseW(QDialog): if self.ui.ch_au.isEnabled(): self.ui.ch_au.setChecked(True) + self.ui.lineEdit.clear() + self.blockSignals(False) self._checkFilters() @@ -1631,7 +1664,7 @@ class PluginDatabaseW(QDialog): def slot_saveSettings(self): settings = QSettings("falkTX", "CarlaDatabase2") settings.setValue("PluginDatabase/Geometry", self.saveGeometry()) - settings.setValue("PluginDatabase/TableGeometry_5", self.ui.tableWidget.horizontalHeader().saveState()) + settings.setValue("PluginDatabase/TableGeometry_6", self.ui.tableWidget.horizontalHeader().saveState()) settings.setValue("PluginDatabase/ShowEffects", self.ui.ch_effects.isChecked()) settings.setValue("PluginDatabase/ShowInstruments", self.ui.ch_instruments.isChecked()) settings.setValue("PluginDatabase/ShowMIDI", self.ui.ch_midi.isChecked()) @@ -1647,6 +1680,7 @@ class PluginDatabaseW(QDialog): settings.setValue("PluginDatabase/ShowNative", self.ui.ch_native.isChecked()) settings.setValue("PluginDatabase/ShowBridged", self.ui.ch_bridged.isChecked()) settings.setValue("PluginDatabase/ShowBridgedWine", self.ui.ch_bridged_wine.isChecked()) + settings.setValue("PluginDatabase/ShowFavorites", self.ui.ch_favorites.isChecked()) settings.setValue("PluginDatabase/ShowRtSafe", self.ui.ch_rtsafe.isChecked()) settings.setValue("PluginDatabase/ShowHasCV", self.ui.ch_cv.isChecked()) settings.setValue("PluginDatabase/ShowHasGUI", self.ui.ch_gui.isChecked()) @@ -1654,10 +1688,16 @@ class PluginDatabaseW(QDialog): settings.setValue("PluginDatabase/ShowStereoOnly", self.ui.ch_stereo.isChecked()) settings.setValue("PluginDatabase/SearchText", self.ui.lineEdit.text()) + if self.fFavoritePluginsChanged: + settings.setValue("PluginDatabase/Favorites", self.fFavoritePlugins) + # -------------------------------------------------------------------------------------------------------- def loadSettings(self): settings = QSettings("falkTX", "CarlaDatabase2") + self.fFavoritePlugins = settings.value("PluginDatabase/Favorites", [], type=list) + self.fFavoritePluginsChanged = False + self.restoreGeometry(settings.value("PluginDatabase/Geometry", b"")) self.ui.ch_effects.setChecked(settings.value("PluginDatabase/ShowEffects", True, type=bool)) self.ui.ch_instruments.setChecked(settings.value("PluginDatabase/ShowInstruments", True, type=bool)) @@ -1674,6 +1714,7 @@ class PluginDatabaseW(QDialog): self.ui.ch_native.setChecked(settings.value("PluginDatabase/ShowNative", True, type=bool)) self.ui.ch_bridged.setChecked(settings.value("PluginDatabase/ShowBridged", True, type=bool)) self.ui.ch_bridged_wine.setChecked(settings.value("PluginDatabase/ShowBridgedWine", True, type=bool)) + self.ui.ch_favorites.setChecked(settings.value("PluginDatabase/ShowFavorites", False, type=bool)) self.ui.ch_rtsafe.setChecked(settings.value("PluginDatabase/ShowRtSafe", False, type=bool)) self.ui.ch_cv.setChecked(settings.value("PluginDatabase/ShowHasCV", False, type=bool)) self.ui.ch_gui.setChecked(settings.value("PluginDatabase/ShowHasGUI", False, type=bool)) @@ -1681,14 +1722,30 @@ class PluginDatabaseW(QDialog): self.ui.ch_stereo.setChecked(settings.value("PluginDatabase/ShowStereoOnly", False, type=bool)) self.ui.lineEdit.setText(settings.value("PluginDatabase/SearchText", "", type=str)) - tableGeometry = settings.value("PluginDatabase/TableGeometry_5") + tableGeometry = settings.value("PluginDatabase/TableGeometry_6") + horizontalHeader = self.ui.tableWidget.horizontalHeader() if tableGeometry: - self.ui.tableWidget.horizontalHeader().restoreState(tableGeometry) + horizontalHeader.restoreState(tableGeometry) else: - self.ui.tableWidget.sortByColumn(0, Qt.AscendingOrder) + horizontalHeader.setSectionResizeMode(self.TABLEWIDGET_ITEM_FAVORITE, QHeaderView.Fixed) + self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_FAVORITE, 24) + self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_NAME, 250) + self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_LABEL, 200) + self.ui.tableWidget.setColumnWidth(self.TABLEWIDGET_ITEM_MAKER, 150) + self.ui.tableWidget.sortByColumn(self.TABLEWIDGET_ITEM_NAME, Qt.AscendingOrder) # -------------------------------------------------------------------------------------------------------- + def _createFavoritePluginDict(self, plugin): + return { + 'name' : plugin['name'], + 'build' : plugin['build'], + 'type' : plugin['type'], + 'filename': plugin['filename'], + 'label' : plugin['label'], + 'uniqueId': plugin['uniqueId'], + } + def _checkFilters(self): text = self.ui.lineEdit.text().lower() @@ -1710,6 +1767,7 @@ class PluginDatabaseW(QDialog): hideBridged = not self.ui.ch_bridged.isChecked() hideBridgedWine = not self.ui.ch_bridged_wine.isChecked() + hideNonFavs = self.ui.ch_favorites.isChecked() hideNonRtSafe = self.ui.ch_rtsafe.isChecked() hideNonCV = self.ui.ch_cv.isChecked() hideNonGui = self.ui.ch_gui.isChecked() @@ -1729,8 +1787,8 @@ class PluginDatabaseW(QDialog): rowCount = self.ui.tableWidget.rowCount() for i in range(self.fLastTableIndex): - plugin = self.ui.tableWidget.item(i, 0).data(Qt.UserRole+1) - ptext = self.ui.tableWidget.item(i, 0).data(Qt.UserRole+2) + plugin = self.ui.tableWidget.item(i, self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+1) + ptext = self.ui.tableWidget.item(i, self.TABLEWIDGET_ITEM_NAME).data(Qt.UserRole+2) aIns = plugin['audio.ins'] aOuts = plugin['audio.outs'] cvIns = plugin['cv.ins'] @@ -1794,7 +1852,9 @@ class PluginDatabaseW(QDialog): self.ui.tableWidget.hideRow(i) elif hideNonStereo and not isStereo: self.ui.tableWidget.hideRow(i) - elif text and text not in ptext: + elif text and not all(t in ptext for t in text.strip().split(' ')): + self.ui.tableWidget.hideRow(i) + elif hideNonFavs and self._createFavoritePluginDict(plugin) not in self.fFavoritePlugins: self.ui.tableWidget.hideRow(i) else: self.ui.tableWidget.showRow(i) @@ -1809,13 +1869,17 @@ class PluginDatabaseW(QDialog): index = self.fLastTableIndex + favItem = QTableWidgetItem() + favItem.setCheckState(Qt.Checked if self._createFavoritePluginDict(plugin) in self.fFavoritePlugins else Qt.Unchecked) + pluginText = (plugin['name']+plugin['label']+plugin['maker']+plugin['filename']).lower() + self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_FAVORITE, favItem) self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_NAME, QTableWidgetItem(plugin['name'])) self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_LABEL, QTableWidgetItem(plugin['label'])) self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_MAKER, QTableWidgetItem(plugin['maker'])) self.ui.tableWidget.setItem(index, self.TABLEWIDGET_ITEM_BINARY, QTableWidgetItem(os.path.basename(plugin['filename']))) - self.ui.tableWidget.item(index, 0).setData(Qt.UserRole+1, plugin) - self.ui.tableWidget.item(index, 0).setData(Qt.UserRole+2, pluginText) + self.ui.tableWidget.item(index, self.TABLEWIDGET_ITEM_NAME).setData(Qt.UserRole+1, plugin) + self.ui.tableWidget.item(index, self.TABLEWIDGET_ITEM_NAME).setData(Qt.UserRole+2, pluginText) self.fLastTableIndex += 1