Sampled Instrument Player with static and monolithic design. All instruments are built-in.
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.

166 lines
6.3 KiB

3 years ago
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, 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 <http://www.gnu.org/licenses/>.
"""
import logging; logger = logging.getLogger(__name__); logger.info("import")
#Standard Library
#Third Party
from PyQt5 import QtCore, QtGui, QtWidgets
#Our Qt
from template.qtgui.helper import ToggleSwitch
#Engine
import engine.api as api
class InstrumentTreeController(object):
"""Not a qt class. We externally controls the QTreeWidget
Why is this not a QTableWidget? As in Agordejo, a TableWidget is a complex item, and inconvenient
to use. You need to add an Item to each cell. While in TreeWidget you just create one item.
And we might use the TreeView to group by manufacturer etc. Eventhough we have a Filter.
"""
def __init__(self, parentMainWindow):
self.parentMainWindow = parentMainWindow
self.treeWidget = self.parentMainWindow.ui.instruments_treeWidget
self.sortByColumnValue = 1 #by instrId
self.sortDescendingValue = 0 # Qt::SortOrder which is 0 for ascending and 1 for descending
self._testData()
def newInstrument(self, instrumentDict):
gi = GuiInstrument(parentTreeController=self, instrumentDict=instrumentDict)
self.treeWidget.addTopLevelItem(gi)
gi.injectToggleSwitch() #only possible after gi.init was done and item inserted.
self._adjustColumnSize()
def _testData(self):
exampleInstrumentDict1 = {
"instrId" : 123,
"state": False,
"prettyName" : "My Instrument 2000",
"vendor" : "Nils Productions",
"version" : "1.0.3",
"logo" : None,
}
exampleInstrumentDict2 = {
"instrId" : 124,
"state": False,
"prettyName" : "Untuned Guitar",
"vendor" : "Merle Instrument Design",
"version" : "0.4.1",
"logo" : None,
}
self.newInstrument(exampleInstrumentDict1)
self.newInstrument(exampleInstrumentDict2)
def _adjustColumnSize(self):
self.treeWidget.sortItems(self.sortByColumnValue, self.sortDescendingValue)
for index in range(self.treeWidget.columnCount()):
self.treeWidget.resizeColumnToContents(index)
class GuiInstrument(QtWidgets.QTreeWidgetItem):
"""
Why is this not a QTableWidget? As in Agordejo, a TableWidget is a complex item, and inconvenient
to use. You need to add an Item to each cell. While in TreeWidget you just create one item.
All data is received at program start. No new items will be created, none will get deleted.
All instruments in Tembro are static.
By default all instruments are switched off. The user can switch them on/off here or
a loaded save state will send the state on program start.
Most parameters we receive are read only, like instrId, prettyName and version"""
allItems = {} # instrId : GuiInstrument
def __init__(self, parentTreeController, instrumentDict):
GuiInstrument.allItems[instrumentDict["instrId"]] = self
self.parentTreeController = parentTreeController
#Start with empty columns. We fill in later in _writeColumns
super().__init__([], type=1000) #type 0 is default qt type. 1000 is subclassed user type)
self.columns = ("state" , "instrId", "prettyName", "version", "vendor", "logo") #Same keys as instrumentDict. Keep in sync manually with Qt Designer. All code must use this, never number directly.
#Use with:
#nameColumnIndex = self.columns.index("prettyName")
#self.setText(nameColumnIndex, "hello")
self.state = None #by self.switch()
self.instrumentDict = None
self._writeColumns(instrumentDict)
self.toggleSwitch = ToggleSwitch()
self.toggleSwitch.setAutoFillBackground(True) #otherwise conflicts with setItemWidget
self.toggleSwitch.toggled.connect(lambda c: print('toggled', c))
self.toggleSwitch.clicked.connect(lambda c: print('clicked', c))
self.toggleSwitch.pressed.connect(lambda: print('pressed'))
self.toggleSwitch.released.connect(lambda: print('released'))
#We cannot add the ToggleSwitch Widget here.
#It must be inserted after self was added to the Tree. Use self.injectToggleSwitch from parent
def injectToggleSwitch(self):
"""Call this after the item was added to the tree"""
stateColumnIndex = self.columns.index("state")
self.parentTreeController.treeWidget.setItemWidget(self, stateColumnIndex, self.toggleSwitch)
def _writeColumns(self, instrumentDict):
self.instrumentDict = instrumentDict
for index, key in enumerate(self.columns):
value = instrumentDict[key]
QtCore.QCoreApplication.translate("OpenSession", "not saved")
if type(instrumentDict[key]) is str or key == "instrId":
self.setText(index, str(instrumentDict[key]))
elif key == "logo":
pass
elif key == "state": #use parameter for initial value. loaded from file or default = False.
state = instrumentDict[key]
assert type(state) is bool, state
self.switch(state)
def switch(self, state:bool):
"""This is not the Qt function but if an instrument is enabled, loaded to RAM and ready to
receive midi data.
Function will mimic Qt disabled behaviour by greying things out and deactivating individual
sub-widgets. But some, like the GUI switch itself, will always stay enabled."""
self.state = state
def toggleSwitchState(self):
self.switch(not self.state)