diff --git a/template/engine/api.py b/template/engine/api.py index 9d0d41f..ca562b8 100644 --- a/template/engine/api.py +++ b/template/engine/api.py @@ -295,9 +295,9 @@ def startEngine(nsmClient): assert callbacks session.nsmClient = nsmClient + session.eventLoop.directConnect(callbacks._checkPlaybackStatusAndSendSignal) session.eventLoop.fastConnect(callbacks._setPlaybackTicks) session.eventLoop.fastConnect(cbox.get_new_events) #global cbox.get_new_events does not eat dynamic midi port events. - session.eventLoop.slowConnect(callbacks._checkPlaybackStatusAndSendSignal) session.eventLoop.slowConnect(callbacks._checkBBTAndSendSignal) #session.eventLoop.slowConnect(lambda: print(cbox.Transport.status().tempo)) #asession.eventLoop.slowConnect(lambda: print(cbox.Transport.status())) diff --git a/template/qtgui/flowlayout.py b/template/qtgui/flowlayout.py deleted file mode 100755 index 5173a49..0000000 --- a/template/qtgui/flowlayout.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env python - - -############################################################################# -## -## Copyright (C) 2013 Riverbank Computing Limited. -## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -## All rights reserved. -## -## This file is part of the examples of PyQt. -## -## $QT_BEGIN_LICENSE:BSD$ -## You may use this file under the terms of the BSD license as follows: -## -## "Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are -## met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in -## the documentation and/or other materials provided with the -## distribution. -## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor -## the names of its contributors may be used to endorse or promote -## products derived from this software without specific prior written -## permission. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -## $QT_END_LICENSE$ -## -############################################################################# - - -from PyQt5.QtCore import QPoint, QRect, QSize, Qt -from PyQt5.QtWidgets import (QApplication, QLayout, QPushButton, QSizePolicy, - QWidget) - - -class Window(QWidget): - def __init__(self): - super(Window, self).__init__() - - flowLayout = FlowLayout() - flowLayout.addWidget(QPushButton("Short")) - flowLayout.addWidget(QPushButton("Longer")) - flowLayout.addWidget(QPushButton("Different text")) - flowLayout.addWidget(QPushButton("More text")) - flowLayout.addWidget(QPushButton("Even longer button text")) - self.setLayout(flowLayout) - - self.setWindowTitle("Flow Layout") - - -class FlowLayout(QLayout): - def __init__(self, parent=None, margin=0, spacing=-1): - super(FlowLayout, self).__init__(parent) - - if parent is not None: - self.setContentsMargins(margin, margin, margin, margin) - - self.setSpacing(spacing) - - self.itemList = [] - - def __del__(self): - item = self.takeAt(0) - while item: - item = self.takeAt(0) - - def addItem(self, item): - self.itemList.append(item) - - def count(self): - return len(self.itemList) - - def itemAt(self, index): - if index >= 0 and index < len(self.itemList): - return self.itemList[index] - - return None - - def takeAt(self, index): - if index >= 0 and index < len(self.itemList): - return self.itemList.pop(index) - - return None - - def expandingDirections(self): - return Qt.Orientations(Qt.Orientation(0)) - - def hasHeightForWidth(self): - return True - - def heightForWidth(self, width): - height = self.doLayout(QRect(0, 0, width, 0), True) - return height - - def setGeometry(self, rect): - super(FlowLayout, self).setGeometry(rect) - self.doLayout(rect, False) - - def sizeHint(self): - return self.minimumSize() - - def minimumSize(self): - size = QSize() - - for item in self.itemList: - size = size.expandedTo(item.minimumSize()) - - margin, _, _, _ = self.getContentsMargins() - - size += QSize(2 * margin, 2 * margin) - return size - - def doLayout(self, rect, testOnly): - x = rect.x() - y = rect.y() - lineHeight = 0 - - for item in self.itemList: - wid = item.widget() - spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal) - spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical) - nextX = x + item.sizeHint().width() + spaceX - if nextX - spaceX > rect.right() and lineHeight > 0: - x = rect.x() - y = y + lineHeight + spaceY - nextX = x + item.sizeHint().width() + spaceX - lineHeight = 0 - - if not testOnly: - item.setGeometry(QRect(QPoint(x, y), item.sizeHint())) - - x = nextX - lineHeight = max(lineHeight, item.sizeHint().height()) - - return y + lineHeight - rect.y() - - -if __name__ == '__main__': - - import sys - - app = QApplication(sys.argv) - mainWin = Window() - mainWin.show() - sys.exit(app.exec_()) diff --git a/template/qtgui/mainwindow.py b/template/qtgui/mainwindow.py index 1861601..9e52197 100644 --- a/template/qtgui/mainwindow.py +++ b/template/qtgui/mainwindow.py @@ -53,7 +53,10 @@ class EventLoop(object): def __init__(self): """The loop for all things GUI and controlling the GUI (e.g. by a control midi in port) - By default use fastConnect. + directConnect is 0ms (see below) + fastConnect 20ms + slowConnect 100ms + verySlowConnect 200ms 0 ms means "if there is time". 10ms-20ms is smooth. 100ms is still ok. Influences everything. Control Midi In Latency, playback cursor scrolling smoothnes etc. @@ -69,10 +72,14 @@ class EventLoop(object): We init the event loop outside of main but call start from the mainWindow. """ + self.directLoop = QtCore.QTimer() self.fastLoop = QtCore.QTimer() self.slowLoop = QtCore.QTimer() self.verySlowLoop = QtCore.QTimer() + def directConnect(self, function): + self.directLoop.timeout.connect(function) + def fastConnect(self, function): self.fastLoop.timeout.connect(function) @@ -97,6 +104,8 @@ class EventLoop(object): def start(self): """The event loop MUST be started after the Qt Application instance creation""" + logger.info("Starting direct qt event loop") + self.directLoop.start(0) logger.info("Starting fast qt event loop") self.fastLoop.start(20) logger.info("Starting slow qt event loop") @@ -105,6 +114,8 @@ class EventLoop(object): self.verySlowLoop.start(200) def stop(self): + logger.info("Stopping direct qt event loop") + self.directLoop.stop() logger.info("Stopping fast qt event loop") self.fastLoop.stop() logger.info("Stopping slow qt event loop") @@ -143,9 +154,9 @@ class MainWindow(QtWidgets.QMainWindow): super().__init__() self.qtApp = qtApp self.qtApp.setWindowIcon(QtGui.QIcon(":icon.png")) #non-template part of the program - QtGui.QIcon.setThemeName("hicolor") #audio applications can be found here. We have no need for other icons. + QtGui.QIcon.setThemeName("hicolor") #audio applications can be found here. We have no need for other icons. logger.info("Init MainWindow") - + #Callbacks. Must be registered before startEngine. api.callbacks.message.append(self.callback_message) @@ -172,9 +183,9 @@ class MainWindow(QtWidgets.QMainWindow): self.setWindowTitle(self.nsmClient.ourClientNameUnderNSM) self.qtApp.setApplicationName(self.nsmClient.ourClientNameUnderNSM) self.qtApp.setApplicationDisplayName(self.nsmClient.ourClientNameUnderNSM) - self.qtApp.setOrganizationName("Laborejo Software Suite") - self.qtApp.setOrganizationDomain("laborejo.org") - self.qtApp.setApplicationVersion(METADATA["version"]) + self.qtApp.setOrganizationName("Laborejo Software Suite") + self.qtApp.setOrganizationDomain("laborejo.org") + self.qtApp.setApplicationVersion(METADATA["version"]) self.setAcceptDrops(True) self.debugScriptRunner = DebugScriptRunner(apilocals=locals()) #needs to have trueInit called after the session and nsm was set up. Which happens in startEngine.