#! /usr/bin/env python3 # -*- coding: utf-8 -*- """ Copyright 2022, Nils Hilbricht, Germany ( https://www.hilbricht.net ) This file is part of the Laborejo Software Suite ( https://www.laborejo.org ), This application is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ import logging; logger = logging.getLogger(__name__); logger.info("import") #Standard Library #Third Party from PyQt5 import QtCore, QtGui, QtWidgets #Our Qt #Engine import engine.api as api class SelectedInstrumentController(object): """Not a qt class. We externally control a collection of widgets. There is only one set of widgets. We change their contents dynamically. """ def __init__(self, parentMainWindow): self.parentMainWindow = parentMainWindow self.currentIdKey = None self.engineData = {} # id-key tuple : engine library metadata dict. self.statusUpdates = {} # same as engineData, but with incremental status updates. One is guranteed to exist at startup #Our Widgets self.ui = parentMainWindow.ui self.ui.details_groupBox.setTitle("") self.ui.details_scrollArea.hide() #until the first instrument was selected self.ui.variants_comboBox.activated.connect(self._newVariantChosen) #Callbacks api.callbacks.instrumentListMetadata.append(self.react_initialInstrumentList) api.callbacks.instrumentStatusChanged.append(self.react_instrumentStatusChanged) def directLibrary(self, idkey:tuple): """User clicked on a library treeItem""" libraryId, instrumentId = idkey self.currentIdKey = None self.ui.details_scrollArea.show() self.ui.variants_comboBox.hide() self.ui.variant_label.hide() metadata = self.engineData[libraryId]["library"] self.ui.details_groupBox.setTitle(metadata["name"]) self.ui.info_label.setText(self._metadataToDescriptionLabel(metadata)) def _metadataToDescriptionLabel(self, metadata:dict)->str: """Can work with instruments and libraries alike""" if "variants" in metadata: #this is an instrument fullText = metadata["description"] + "\n\nVendor: " + metadata["vendor"] + "\n\nLicense: " + metadata["license"] else: fullText = metadata["description"] + "\n\nVendor: " + metadata["vendor"] return fullText def _newVariantChosen(self, index:int): """User chose a new variant through the combo box""" assert self.ui.variants_comboBox.currentIndex() == index assert self.currentIdKey api.chooseVariantByIndex(self.currentIdKey, index) def instrumentChanged(self, idkey:tuple): """This is a GUI-internal function. The user selected a different instrument from the list. Single click, arrow keys etc. We combine static metadata, which we saved ourselves, with the current instrument status (e.g. which variant was chosen). """ libraryId, instrumentId = idkey self.currentIdKey = idkey self.ui.details_scrollArea.show() #Static instrumentData = self.engineData[libraryId][instrumentId] self.ui.details_groupBox.setTitle(instrumentData["name"]) self.ui.variant_label.show() self.ui.variants_comboBox.show() self.ui.variants_comboBox.clear() self.ui.variants_comboBox.addItems(instrumentData["variantsWithoutSfzExtension"]) self.ui.info_label.setText(self._metadataToDescriptionLabel(instrumentData)) #Dynamic self.react_instrumentStatusChanged(self.statusUpdates[libraryId][instrumentId]) def react_instrumentStatusChanged(self, instrumentStatus:dict): """Callback from the api. Has nothing to do with any GUI state or selection. Data: #Static ids result["id"] = self.metadata["id"] result["id-key"] = self.idKey #redundancy for convenience. #Dynamic data result["currentVariant"] = self.currentVariant # str result["state"] = self.enabled #bool """ idkey = instrumentStatus["id-key"] libraryId, instrumentId = idkey if not libraryId in self.statusUpdates: self.statusUpdates[libraryId] = {} #empty library. status dict self.statusUpdates[libraryId][instrumentId] = instrumentStatus #create or overwrite / keep up to date loadState = instrumentStatus["state"] instrumentData = self.engineData[libraryId][instrumentId] instrumentStatus = self.statusUpdates[libraryId][instrumentId] if loadState: #None if not loaded self.ui.variants_comboBox.setEnabled(True) currentVariantIndex = instrumentData["variantsWithoutSfzExtension"].index(instrumentStatus["currentVariantWithoutSfzExtension"]) self.ui.variants_comboBox.setCurrentIndex(currentVariantIndex) else: self.ui.variants_comboBox.setEnabled(False) defaultVariantIndex = instrumentData["variantsWithoutSfzExtension"].index(instrumentData["defaultVariantWithoutSfzExtension"]) self.ui.variants_comboBox.setCurrentIndex(defaultVariantIndex) def react_initialInstrumentList(self, data:dict): """For data form see docstring of instrument.py buildTree() Summary: libraryid : dict -> instrumentid : metadatadict Dict-Keys are always the same. Some always have data, some can be empty. We receive this once at program start and build our permanent GUI widgets from it. The additional status update callback for dynamic data is handled in self.react_instrumentStatusChanged """ self.engineData = data