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.
124 lines
5.2 KiB
124 lines
5.2 KiB
#! /usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Copyright 2020, Nils Hilbricht, Germany ( https://www.hilbricht.net )
|
|
|
|
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),
|
|
|
|
Laborejo2 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")
|
|
|
|
|
|
from typing import Iterable, Callable, Tuple
|
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
import engine.api as api
|
|
from qtgui.constantsAndConfigs import constantsAndConfigs #Client constantsAndConfigs!
|
|
|
|
"""
|
|
There are two types of submenus in this file. The majority is created in menu.py during start up.
|
|
Like Clef, KeySig etc. These don't need to ask for any dynamic values.
|
|
|
|
The other is like SecondaryTempoChangeMenu. In menu.py this is bound with a lambda construct so a
|
|
new instance gets created each time the action is called by the user. Thats why this function has
|
|
self.__call__ in its init.
|
|
"""
|
|
|
|
|
|
class Submenu(QtWidgets.QDialog):
|
|
def __init__(self, mainWindow, labelString, hasOkCancelButtons=False):
|
|
super().__init__(mainWindow) #if you don't set the parent to the main window the whole screen will be the root and the dialog pops up in the middle of it.
|
|
#self.setModal(True) #we don't need this when called with self.exec() instead of self.show()
|
|
self.layout = QtWidgets.QFormLayout()
|
|
#self.layout = QtWidgets.QVBoxLayout()
|
|
self.setLayout(self.layout)
|
|
|
|
label = QtWidgets.QLabel(labelString) #"Choose a clef" or so.
|
|
self.layout.addWidget(label)
|
|
|
|
#self.setFocus(); #self.grabKeyboard(); #redundant for a proper modal dialog. Leave here for documentation reasons.
|
|
|
|
if hasOkCancelButtons:
|
|
self.buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
|
|
self.buttonBox.accepted.connect(self.process)
|
|
self.buttonBox.rejected.connect(self.reject)
|
|
else:
|
|
self.buttonBox = None
|
|
|
|
|
|
def keyPressEvent(self, event):
|
|
"""Escape closes the dialog by default.
|
|
We want Enter as "accept value"
|
|
All other methods of mixing editing, window focus and signals
|
|
results in strange qt behaviour, triggering the api function twice or more.
|
|
Especially unitbox.editingFinished is too easy to trigger.
|
|
|
|
The key-event method turned out to be the most straightforward way."""
|
|
try:
|
|
getattr(self, "process")
|
|
k = event.key() #49=1, 50=2 etc.
|
|
if k == 0x01000004 or k == 0x01000005: #normal enter or keypad enter
|
|
event.ignore()
|
|
self.process()
|
|
else: #Pressed Esc
|
|
self.abortHandler()
|
|
super().keyPressEvent(event)
|
|
except AttributeError:
|
|
super().keyPressEvent(event)
|
|
|
|
def showEvent(self, event):
|
|
#TODO: not optimal but better than nothing.
|
|
super().showEvent(event)
|
|
#self.resize(self.layout.geometry().width(), self.layout.geometry().height())
|
|
self.resize(self.childrenRect().height(), self.childrenRect().width())
|
|
self.updateGeometry()
|
|
|
|
def abortHandler(self):
|
|
pass
|
|
|
|
def process(self):
|
|
"""Careful! Calling this eats python errors without notice. Make sure your objects exists
|
|
and your syntax is correct"""
|
|
raise NotImplementedError()
|
|
self.done(True)
|
|
|
|
def __call__(self):
|
|
"""This instance can be called like a function"""
|
|
if self.buttonBox:
|
|
self.layout.addWidget(self.buttonBox)
|
|
self.setFixedSize(self.layout.geometry().size())
|
|
self.exec() #blocks until the dialog gets closed
|
|
|
|
"""
|
|
Most submenus have the line "lambda, r, value=value"...
|
|
the r is the return value we get automatically from the Qt buttons which need to be handled.
|
|
"""
|
|
|
|
|
|
class ChooseOne(Submenu):
|
|
"""A generic submenu that presents a list of options to the users.
|
|
Only supports up to ten entries, for number shortcuts"""
|
|
def __init__(self, mainWindow, title:str, lst:Iterable[Tuple[str, Callable]]):
|
|
if len(lst) > 9:
|
|
raise ValueError(f"ChooseOne submenu supports up to nine entries. You have {len(lst)}")
|
|
super().__init__(mainWindow, title)
|
|
|
|
for number, (prettyname, function) in enumerate(lst):
|
|
button = QtWidgets.QPushButton(f"[{number+1}] {prettyname}")
|
|
button.setShortcut(QtGui.QKeySequence(str(number+1)))
|
|
button.setStyleSheet("Text-align:left; padding: 5px;");
|
|
self.layout.addWidget(button)
|
|
button.clicked.connect(function)
|
|
button.clicked.connect(self.done)
|
|
|