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.
 
 

127 lines
5.3 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 == 1: #or true
self.buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self.process)
self.buttonBox.rejected.connect(self.reject)
elif hasOkCancelButtons == 2: #only cancel. #TODO: unpythonic.
self.buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Cancel)
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)