2800 lines
111 KiB
Python
Executable File
2800 lines
111 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# LADISH frontend
|
|
# Copyright (C) 2010-2018 Filipe Coelho <falktx@falktx.com>
|
|
#
|
|
# This program 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 2 of the License, or
|
|
# 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.
|
|
#
|
|
# For a full copy of the GNU General Public License see the COPYING file
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Imports (Global)
|
|
|
|
from time import ctime
|
|
|
|
if True:
|
|
from PyQt5.QtCore import QPointF
|
|
from PyQt5.QtWidgets import QAction, QApplication, QCheckBox, QHBoxLayout, QVBoxLayout, QTableWidgetItem, QTreeWidgetItem
|
|
else:
|
|
from PyQt4.QtCore import QPointF
|
|
from PyQt4.QtGui import QAction, QApplication, QCheckBox, QHBoxLayout, QVBoxLayout, QTableWidgetItem, QTreeWidgetItem
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Imports (Custom Stuff)
|
|
|
|
import claudia_launcher
|
|
import systray
|
|
import ui_claudia
|
|
import ui_claudia_studioname
|
|
import ui_claudia_studiolist
|
|
import ui_claudia_createroom
|
|
import ui_claudia_projectname
|
|
import ui_claudia_projectproperties
|
|
import ui_claudia_runcustom
|
|
from shared_canvasjack import *
|
|
from shared_settings import *
|
|
from shared_i18n import *
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Try Import DBus
|
|
|
|
try:
|
|
import dbus
|
|
from dbus.mainloop.pyqt5 import DBusMainLoop
|
|
haveDBus = True
|
|
except:
|
|
try:
|
|
# Try falling back to GMainLoop
|
|
from dbus.mainloop.glib import DBusGMainLoop as DBusMainLoop
|
|
haveDBus = True
|
|
except:
|
|
haveDBus = False
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Try Import OpenGL
|
|
|
|
try:
|
|
from PyQt5.QtOpenGL import QGLWidget
|
|
hasGL = True
|
|
except:
|
|
hasGL = False
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Static Variables
|
|
|
|
# NOTE - set to true when supported
|
|
USE_CLAUDIA_ADD_NEW = True
|
|
|
|
# internal indexes
|
|
iConnId = 0
|
|
iConnOutput = 1
|
|
iConnInput = 2
|
|
|
|
iAppCommand = 0
|
|
iAppName = 1
|
|
iAppTerminal = 2
|
|
iAppLevel = 3
|
|
iAppActive = 4
|
|
|
|
iAppPropName = 0
|
|
iAppPropDescription = 1
|
|
iAppPropNotes = 2
|
|
iAppPropSaveNow = 3
|
|
|
|
iItemPropNumber = 0
|
|
iItemPropName = 1
|
|
iItemPropActive = 2
|
|
iItemPropTerminal = 3
|
|
iItemPropLevel = 4
|
|
|
|
iItemPropRoomPath = 0
|
|
iItemPropRoomName = 1
|
|
|
|
# jackdbus indexes
|
|
iGraphVersion = 0
|
|
iJackClientId = 1
|
|
iJackClientName = 2
|
|
iJackPortId = 3
|
|
iJackPortName = 4
|
|
iJackPortNewName = 5
|
|
iJackPortFlags = 5
|
|
iJackPortType = 6
|
|
|
|
iRenamedId = 1
|
|
iRenamedOldName = 2
|
|
iRenamedNewName = 3
|
|
|
|
iSourceClientId = 1
|
|
iSourceClientName = 2
|
|
iSourcePortId = 3
|
|
iSourcePortName = 4
|
|
iTargetClientId = 5
|
|
iTargetClientName = 6
|
|
iTargetPortId = 7
|
|
iTargetPortName = 8
|
|
iJackConnId = 9
|
|
|
|
# ladish indexes
|
|
iStudioListName = 0
|
|
iStudioListDict = 1
|
|
|
|
iStudioRenamedName = 0
|
|
|
|
iRoomAppearedPath = 0
|
|
iRoomAppearedDict = 1
|
|
|
|
iProjChangedId = 0
|
|
iProjChangedDict = 1
|
|
|
|
iAppChangedNumber = 1
|
|
iAppChangedName = 2
|
|
iAppChangedActive = 3
|
|
iAppChangedTerminal = 4
|
|
iAppChangedLevel = 5
|
|
|
|
# internal defines
|
|
ITEM_TYPE_NULL = 0
|
|
ITEM_TYPE_STUDIO = 1
|
|
ITEM_TYPE_STUDIO_APP = 2
|
|
ITEM_TYPE_ROOM = 3
|
|
ITEM_TYPE_ROOM_APP = 4
|
|
|
|
# C defines
|
|
JACKDBUS_PORT_FLAG_INPUT = 0x01
|
|
JACKDBUS_PORT_FLAG_OUTPUT = 0x02
|
|
JACKDBUS_PORT_FLAG_PHYSICAL = 0x04
|
|
JACKDBUS_PORT_FLAG_CAN_MONITOR = 0x08
|
|
JACKDBUS_PORT_FLAG_TERMINAL = 0x10
|
|
|
|
JACKDBUS_PORT_TYPE_AUDIO = 0
|
|
JACKDBUS_PORT_TYPE_MIDI = 1
|
|
|
|
GRAPH_DICT_OBJECT_TYPE_GRAPH = 0
|
|
GRAPH_DICT_OBJECT_TYPE_CLIENT = 1
|
|
GRAPH_DICT_OBJECT_TYPE_PORT = 2
|
|
GRAPH_DICT_OBJECT_TYPE_CONNECTION = 3
|
|
|
|
URI_A2J_PORT = "http://ladish.org/ns/a2j"
|
|
URI_CANVAS_WIDTH = "http://ladish.org/ns/canvas/width"
|
|
URI_CANVAS_HEIGHT = "http://ladish.org/ns/canvas/height"
|
|
URI_CANVAS_X = "http://ladish.org/ns/canvas/x"
|
|
URI_CANVAS_Y = "http://ladish.org/ns/canvas/y"
|
|
URI_CANVAS_SPLIT = "http://kxstudio.sf.net/ns/canvas/split"
|
|
URI_CANVAS_X_SPLIT = "http://kxstudio.sf.net/ns/canvas/x_split"
|
|
URI_CANVAS_Y_SPLIT = "http://kxstudio.sf.net/ns/canvas/y_split"
|
|
URI_CANVAS_ICON = "http://kxstudio.sf.net/ns/canvas/icon"
|
|
|
|
DEFAULT_CANVAS_WIDTH = 3100
|
|
DEFAULT_CANVAS_HEIGHT = 2400
|
|
|
|
RECENT_PROJECTS_STORE_MAX_ITEMS = 50
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Set default project folder
|
|
|
|
DEFAULT_PROJECT_FOLDER = os.path.join(HOME, "ladish-projects")
|
|
setDefaultProjectFolder(DEFAULT_PROJECT_FOLDER)
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Studio Name Dialog
|
|
|
|
class StudioNameW(QDialog):
|
|
NEW = 1
|
|
RENAME = 2
|
|
SAVE_AS = 3
|
|
|
|
def __init__(self, parent, mode):
|
|
QDialog.__init__(self, parent)
|
|
self.ui = ui_claudia_studioname.Ui_StudioNameW()
|
|
self.ui.setupUi(self)
|
|
|
|
self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
if mode == self.NEW:
|
|
self.setWindowTitle(self.tr("New studio"))
|
|
elif mode == self.RENAME:
|
|
self.setWindowTitle(self.tr("Rename studio"))
|
|
elif mode == self.SAVE_AS:
|
|
self.setWindowTitle(self.tr("Save studio as"))
|
|
|
|
self.fMode = mode
|
|
self.fStudioList = []
|
|
|
|
if mode == self.RENAME and bool(gDBus.ladish_control.IsStudioLoaded()):
|
|
currentName = str(gDBus.ladish_studio.GetName())
|
|
self.fStudioList.append(currentName)
|
|
self.ui.le_name.setText(currentName)
|
|
|
|
studioList = gDBus.ladish_control.GetStudioList()
|
|
for studio in studioList:
|
|
self.fStudioList.append(str(studio[iStudioListName]))
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.ui.le_name.textChanged.connect(self.slot_checkText)
|
|
|
|
self.fRetStudioName = ""
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText(self, text):
|
|
if self.fMode == self.SAVE_AS:
|
|
check = bool(text)
|
|
else:
|
|
check = bool(text and text not in self.fStudioList)
|
|
|
|
self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
self.fRetStudioName = self.ui.le_name.text()
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# Studio List Dialog
|
|
class StudioListW(QDialog, ui_claudia_studiolist.Ui_StudioListW):
|
|
def __init__(self, parent):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
self.tableWidget.setColumnWidth(0, 125)
|
|
|
|
index = 0
|
|
studio_list = gDBus.ladish_control.GetStudioList()
|
|
for studio in studio_list:
|
|
name = str(studio[iStudioListName])
|
|
date = ctime(float(studio[iStudioListDict]["Modification Time"]))
|
|
|
|
w_name = QTableWidgetItem(name)
|
|
w_date = QTableWidgetItem(date)
|
|
self.tableWidget.insertRow(index)
|
|
self.tableWidget.setItem(index, 0, w_name)
|
|
self.tableWidget.setItem(index, 1, w_date)
|
|
|
|
index += 1
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.tableWidget.cellDoubleClicked.connect(self.accept)
|
|
self.tableWidget.currentCellChanged.connect(self.slot_checkSelection)
|
|
|
|
if self.tableWidget.rowCount() > 0:
|
|
self.tableWidget.setCurrentCell(0, 0)
|
|
|
|
self.ret_studio_name = ""
|
|
|
|
@pyqtSlot(int)
|
|
def slot_checkSelection(self, row):
|
|
check = bool(row >= 0)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.tableWidget.rowCount() >= 0:
|
|
self.ret_studio_name = self.tableWidget.item(self.tableWidget.currentRow(), 0).text()
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# Create Room Dialog
|
|
class CreateRoomW(QDialog, ui_claudia_createroom.Ui_CreateRoomW):
|
|
def __init__(self, parent):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
templates_list = gDBus.ladish_control.GetRoomTemplateList()
|
|
for template_name, template_dict in templates_list:
|
|
self.lw_templates.addItem(template_name)
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.le_name.textChanged.connect(self.slot_checkText)
|
|
|
|
if self.lw_templates.count() > 0:
|
|
self.lw_templates.setCurrentRow(0)
|
|
|
|
self.ret_room_name = ""
|
|
self.ret_room_template = ""
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText(self, text):
|
|
check = bool(text and self.lw_templates.currentRow() >= 0)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.lw_templates.count() > 0:
|
|
self.ret_room_name = self.le_name.text()
|
|
self.ret_room_template = self.lw_templates.currentItem().text()
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# Project Name Dialog
|
|
class ProjectNameW(QDialog, ui_claudia_projectname.Ui_ProjectNameW):
|
|
NEW = 1
|
|
SAVE_AS = 2
|
|
|
|
def __init__(self, parent, mode, proj_folder, path="", name=""):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
if mode == self.NEW:
|
|
self.setWindowTitle(self.tr("New project"))
|
|
elif mode == self.SAVE_AS:
|
|
self.setWindowTitle(self.tr("Save project as"))
|
|
self.le_path.setText(path)
|
|
self.le_name.setText(name)
|
|
self.checkText(path, name)
|
|
|
|
self.m_proj_folder = proj_folder
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.b_open.clicked.connect(self.slot_checkFolder)
|
|
self.le_path.textChanged.connect(self.slot_checkText_path)
|
|
self.le_name.textChanged.connect(self.slot_checkText_name)
|
|
|
|
self.ret_project_name = ""
|
|
self.ret_project_path = ""
|
|
|
|
def checkText(self, name, path):
|
|
check = bool(name and path and os.path.exists(path) and os.path.isdir(path))
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_checkFolder(self):
|
|
# Create default project folder if the project has not been set yet
|
|
if not self.le_path.text():
|
|
if not os.path.exists(self.m_proj_folder):
|
|
os.mkdir(self.m_proj_folder)
|
|
|
|
if self.le_path.text():
|
|
proj_path = self.le_path.text()
|
|
else:
|
|
proj_path = self.m_proj_folder
|
|
|
|
getAndSetPath(self, proj_path, self.le_path)
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText_name(self, text):
|
|
self.checkText(text, self.le_path.text())
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText_path(self, text):
|
|
self.checkText(self.le_name.text(), text)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
self.ret_project_name = self.le_name.text()
|
|
self.ret_project_path = self.le_path.text()
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# Project Properties Dialog
|
|
class ProjectPropertiesW(QDialog, ui_claudia_projectproperties.Ui_ProjectPropertiesW):
|
|
def __init__(self, parent, name, description, notes):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.m_default_name = name
|
|
self.m_last_name = name
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.le_name.textChanged.connect(self.slot_checkText_name)
|
|
self.cb_save_now.clicked.connect(self.slot_checkSaveNow)
|
|
|
|
self.le_name.setText(name)
|
|
self.le_description.setText(description)
|
|
self.le_notes.setPlainText(notes)
|
|
|
|
self.ret_obj = None
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
self.ret_obj = [None, None, None, None]
|
|
self.ret_obj[iAppPropName] = self.le_name.text()
|
|
self.ret_obj[iAppPropDescription] = self.le_description.text()
|
|
self.ret_obj[iAppPropNotes] = self.le_notes.toPlainText() # plainText()
|
|
self.ret_obj[iAppPropSaveNow] = self.cb_save_now.isChecked()
|
|
|
|
@pyqtSlot(bool)
|
|
def slot_checkSaveNow(self, save):
|
|
if save:
|
|
self.le_name.setText(self.m_last_name)
|
|
else:
|
|
self.m_last_name = self.le_name.text()
|
|
self.le_name.setText(self.m_default_name)
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText_name(self, text):
|
|
check = bool(text)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# Run Custom App Dialog
|
|
class RunCustomW(QDialog, ui_claudia_runcustom.Ui_RunCustomW):
|
|
def __init__(self, parent, isRoom, app_obj=None):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(bool(app_obj))
|
|
|
|
if app_obj:
|
|
self.le_command.setText(app_obj[iAppCommand])
|
|
self.le_name.setText(app_obj[iAppName])
|
|
self.cb_terminal.setChecked(app_obj[iAppTerminal])
|
|
|
|
level = app_obj[iAppLevel]
|
|
if level == "0":
|
|
self.rb_level_0.setChecked(True)
|
|
elif level == "1":
|
|
self.rb_level_1.setChecked(True)
|
|
elif level == "lash":
|
|
self.rb_level_lash.setChecked(True)
|
|
elif level == "jacksession":
|
|
self.rb_level_js.setChecked(True)
|
|
else:
|
|
self.rb_level_0.setChecked(True)
|
|
|
|
if app_obj[iAppActive]:
|
|
self.le_command.setEnabled(False)
|
|
self.cb_terminal.setEnabled(False)
|
|
self.rb_level_0.setEnabled(False)
|
|
self.rb_level_1.setEnabled(False)
|
|
self.rb_level_lash.setEnabled(False)
|
|
self.rb_level_js.setEnabled(False)
|
|
else:
|
|
self.rb_level_0.setChecked(True)
|
|
|
|
if not isRoom:
|
|
self.rb_level_lash.setEnabled(False)
|
|
self.rb_level_js.setEnabled(False)
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.le_command.textChanged.connect(self.slot_checkText)
|
|
|
|
self.ret_app_obj = None
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText(self, text):
|
|
check = bool(text)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.rb_level_0.isChecked():
|
|
level = "0"
|
|
elif self.rb_level_1.isChecked():
|
|
level = "1"
|
|
elif self.rb_level_lash.isChecked():
|
|
level = "lash"
|
|
elif self.rb_level_js.isChecked():
|
|
level = "jacksession"
|
|
else:
|
|
return
|
|
|
|
self.ret_app_obj = [None, None, None, None, None]
|
|
self.ret_app_obj[iAppCommand] = self.le_command.text()
|
|
self.ret_app_obj[iAppName] = self.le_name.text()
|
|
self.ret_app_obj[iAppTerminal] = self.cb_terminal.isChecked()
|
|
self.ret_app_obj[iAppLevel] = level
|
|
self.ret_app_obj[iAppActive] = False
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# Add Application Dialog
|
|
class ClaudiaLauncherW(QDialog):
|
|
def __init__(self, parent, appBus, proj_folder, is_room, bpm, sample_rate):
|
|
QDialog.__init__(self, parent)
|
|
|
|
self.launcher = claudia_launcher.ClaudiaLauncher(self)
|
|
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Close, Qt.Horizontal, self)
|
|
self.checkBox = QCheckBox(self)
|
|
self.checkBox.setText(self.tr("Auto-close"))
|
|
self.checkBox.setChecked(True)
|
|
|
|
self.layoutV = QVBoxLayout(self)
|
|
self.layoutH = QHBoxLayout()
|
|
|
|
#if QDialogButtonBox.ButtonLayout:
|
|
self.layoutH.addWidget(self.checkBox)
|
|
self.layoutH.addWidget(self.buttonBox)
|
|
#else:
|
|
#self.layoutH.addWidget(self.buttonBox)
|
|
#self.layoutH.addWidget(self.checkBox)
|
|
|
|
self.layoutV.addWidget(self.launcher)
|
|
self.layoutV.addLayout(self.layoutH)
|
|
|
|
self.settings = QSettings("Cadence", "Claudia-Launcher")
|
|
self.launcher.setCallbackApp(self, self.settings, True)
|
|
self.loadSettings()
|
|
self.setWindowTitle("Claudia Launcher")
|
|
|
|
self.m_appBus = appBus
|
|
self.m_proj_folder = proj_folder
|
|
self.m_is_room = is_room
|
|
self.m_bpm = bpm
|
|
self.m_sampleRate = sample_rate
|
|
|
|
self.test_url = True
|
|
self.test_selected = False
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.slot_addAppToLADISH)
|
|
self.buttonBox.button(QDialogButtonBox.Close).clicked.connect(self.reject)
|
|
|
|
# ----------------------------------------
|
|
# Callbacks
|
|
|
|
def callback_checkGUI(self, test_selected=None):
|
|
if test_selected != None:
|
|
self.test_selected = test_selected
|
|
|
|
if self.test_url and self.test_selected:
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
|
|
else:
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
def callback_getProjectFolder(self):
|
|
return self.m_proj_folder
|
|
|
|
def callback_getAppBus(self):
|
|
return self.m_appBus
|
|
|
|
def callback_getBPM(self):
|
|
if self.m_bpm < 30:
|
|
return 120.0
|
|
else:
|
|
return self.m_bpm
|
|
|
|
def callback_getSampleRate(self):
|
|
return self.m_sampleRate
|
|
|
|
def callback_isLadishRoom(self):
|
|
return self.m_is_room
|
|
|
|
# ----------------------------------------
|
|
|
|
@pyqtSlot()
|
|
def slot_addAppToLADISH(self):
|
|
self.launcher.addAppToLADISH()
|
|
|
|
if self.checkBox.isChecked():
|
|
self.accept()
|
|
|
|
def saveSettings(self):
|
|
self.settings.setValue("Geometry", self.saveGeometry())
|
|
self.launcher.saveSettings()
|
|
|
|
def loadSettings(self):
|
|
if self.settings.contains("Geometry"):
|
|
self.restoreGeometry(self.settings.value("Geometry", b""))
|
|
else:
|
|
self.resize(850, 500)
|
|
self.launcher.loadSettings()
|
|
|
|
def closeEvent(self, event):
|
|
self.saveSettings()
|
|
QDialog.closeEvent(self, event)
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Claudia Main Window
|
|
|
|
class ClaudiaMainW(AbstractCanvasJackClass):
|
|
DBusCrashCallback = pyqtSignal(str)
|
|
DBusServerStartedCallback = pyqtSignal()
|
|
DBusServerStoppedCallback = pyqtSignal()
|
|
DBusClientAppearedCallback = pyqtSignal(int, str)
|
|
DBusClientDisappearedCallback = pyqtSignal(int)
|
|
DBusClientRenamedCallback = pyqtSignal(int, str)
|
|
DBusPortAppearedCallback = pyqtSignal(int, int, str, int, int)
|
|
DBusPortDisppearedCallback = pyqtSignal(int)
|
|
DBusPortRenamedCallback = pyqtSignal(int, str)
|
|
DBusPortsConnectedCallback = pyqtSignal(int, int, int)
|
|
DBusPortsDisconnectedCallback = pyqtSignal(int)
|
|
DBusStudioAppearedCallback = pyqtSignal()
|
|
DBusStudioDisappearedCallback = pyqtSignal()
|
|
DBusQueueExecutionHaltedCallback = pyqtSignal()
|
|
DBusCleanExitCallback = pyqtSignal()
|
|
DBusStudioStartedCallback = pyqtSignal()
|
|
DBusStudioStoppedCallback = pyqtSignal()
|
|
DBusStudioRenamedCallback = pyqtSignal(str)
|
|
DBusStudioCrashedCallback = pyqtSignal()
|
|
DBusRoomAppearedCallback = pyqtSignal(str, str)
|
|
DBusRoomDisappearedCallback = pyqtSignal(str)
|
|
DBusRoomChangedCallback = pyqtSignal()
|
|
DBusProjectPropertiesChanged = pyqtSignal(str, str)
|
|
DBusAppAdded2Callback = pyqtSignal(str, int, str, bool, bool, str)
|
|
DBusAppRemovedCallback = pyqtSignal(str, int)
|
|
DBusAppStateChanged2Callback = pyqtSignal(str, int, str, bool, bool, str)
|
|
|
|
def __init__(self, parent=None):
|
|
AbstractCanvasJackClass.__init__(self, "Claudia", ui_claudia.Ui_ClaudiaMainW, parent)
|
|
|
|
self.m_lastItemType = None
|
|
self.m_lastRoomPath = None
|
|
|
|
self.m_crashedJACK = False
|
|
self.m_crashedLADISH = False
|
|
|
|
self.loadSettings(True)
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up GUI
|
|
|
|
setIcons(self, ["canvas", "jack", "transport"])
|
|
|
|
self.ui.act_studio_new.setIcon(getIcon("document-new"))
|
|
self.ui.menu_studio_load.setIcon(getIcon("document-open"))
|
|
self.ui.act_studio_start.setIcon(getIcon("media-playback-start"))
|
|
self.ui.act_studio_stop.setIcon(getIcon("media-playback-stop"))
|
|
self.ui.act_studio_rename.setIcon(getIcon("edit-rename"))
|
|
self.ui.act_studio_save.setIcon(getIcon("document-save"))
|
|
self.ui.act_studio_save_as.setIcon(getIcon("document-save-as"))
|
|
self.ui.act_studio_unload.setIcon(getIcon("window-close"))
|
|
self.ui.menu_studio_delete.setIcon(getIcon("edit-delete"))
|
|
self.ui.b_studio_new.setIcon(getIcon("document-new"))
|
|
self.ui.b_studio_load.setIcon(getIcon("document-open"))
|
|
self.ui.b_studio_save.setIcon(getIcon("document-save"))
|
|
self.ui.b_studio_save_as.setIcon(getIcon("document-save-as"))
|
|
self.ui.b_studio_start.setIcon(getIcon("media-playback-start"))
|
|
self.ui.b_studio_stop.setIcon(getIcon("media-playback-stop"))
|
|
|
|
self.ui.act_room_create.setIcon(getIcon("list-add"))
|
|
self.ui.menu_room_delete.setIcon(getIcon("edit-delete"))
|
|
|
|
self.ui.act_project_new.setIcon(getIcon("document-new"))
|
|
self.ui.menu_project_load.setIcon(getIcon("document-open"))
|
|
self.ui.act_project_save.setIcon(getIcon("document-save"))
|
|
self.ui.act_project_save_as.setIcon(getIcon("document-save-as"))
|
|
self.ui.act_project_unload.setIcon(getIcon("window-close"))
|
|
self.ui.act_project_properties.setIcon(getIcon("edit-rename"))
|
|
self.ui.b_project_new.setIcon(getIcon("document-new"))
|
|
self.ui.b_project_load.setIcon(getIcon("document-open"))
|
|
self.ui.b_project_save.setIcon(getIcon("document-save"))
|
|
self.ui.b_project_save_as.setIcon(getIcon("document-save-as"))
|
|
|
|
self.ui.act_app_add_new.setIcon(getIcon("list-add"))
|
|
self.ui.act_app_run_custom.setIcon(getIcon("system-run"))
|
|
|
|
self.ui.act_tools_reactivate_ladishd.setIcon(getIcon("view-refresh"))
|
|
self.ui.act_quit.setIcon(getIcon("application-exit"))
|
|
self.ui.act_settings_configure.setIcon(getIcon("configure"))
|
|
|
|
self.ui.cb_buffer_size.clear()
|
|
self.ui.cb_sample_rate.clear()
|
|
|
|
for bufferSize in BUFFER_SIZE_LIST:
|
|
self.ui.cb_buffer_size.addItem(str(bufferSize))
|
|
|
|
for sampleRate in SAMPLE_RATE_LIST:
|
|
self.ui.cb_sample_rate.addItem(str(sampleRate))
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up Systray
|
|
|
|
if self.fSavedSettings["Main/UseSystemTray"]:
|
|
self.systray = systray.GlobalSysTray(self, "Claudia", "claudia")
|
|
|
|
self.systray.addAction("studio_new", self.tr("New Studio..."))
|
|
self.systray.addSeparator("sep1")
|
|
self.systray.addAction("studio_start", self.tr("Start Studio"))
|
|
self.systray.addAction("studio_stop", self.tr("Stop Studio"))
|
|
self.systray.addSeparator("sep2")
|
|
self.systray.addAction("studio_save", self.tr("Save Studio"))
|
|
self.systray.addAction("studio_save_as", self.tr("Save Studio As..."))
|
|
self.systray.addAction("studio_rename", self.tr("Rename Studio..."))
|
|
self.systray.addAction("studio_unload", self.tr("Unload Studio"))
|
|
self.systray.addSeparator("sep3")
|
|
self.systray.addMenu("tools", self.tr("Tools"))
|
|
self.systray.addMenuAction("tools", "tools_configure_jack", self.tr("Configure JACK"))
|
|
self.systray.addMenuAction("tools", "tools_render", self.tr("JACK Render"))
|
|
self.systray.addMenuAction("tools", "tools_logs", self.tr("Logs"))
|
|
self.systray.addMenuSeparator("tools", "tools_sep")
|
|
self.systray.addMenuAction("tools", "tools_clear_xruns", self.tr("Clear Xruns"))
|
|
self.systray.addAction("configure", self.tr("Configure Claudia"))
|
|
|
|
self.systray.setActionIcon("studio_new", "document-new")
|
|
self.systray.setActionIcon("studio_start", "media-playback-start")
|
|
self.systray.setActionIcon("studio_stop", "media-playback-stop")
|
|
self.systray.setActionIcon("studio_save", "document-save")
|
|
self.systray.setActionIcon("studio_save_as", "document-save-as")
|
|
self.systray.setActionIcon("studio_rename", "edit-rename")
|
|
self.systray.setActionIcon("studio_unload", "dialog-close")
|
|
self.systray.setActionIcon("tools_configure_jack", "configure")
|
|
self.systray.setActionIcon("tools_render", "media-record")
|
|
self.systray.setActionIcon("tools_clear_xruns", "edit-clear")
|
|
self.systray.setActionIcon("configure", "configure")
|
|
|
|
self.systray.connect("studio_new", self.slot_studio_new)
|
|
self.systray.connect("studio_start", self.slot_studio_start)
|
|
self.systray.connect("studio_stop", self.slot_studio_stop)
|
|
self.systray.connect("studio_save", self.slot_studio_save)
|
|
self.systray.connect("studio_save_as", self.slot_studio_save_as)
|
|
self.systray.connect("studio_rename", self.slot_studio_rename)
|
|
self.systray.connect("studio_unload", self.slot_studio_unload)
|
|
self.systray.connect("tools_configure_jack", self.slot_showJackSettings)
|
|
self.systray.connect("tools_render", self.slot_showRender)
|
|
self.systray.connect("tools_logs", self.slot_showLogs)
|
|
self.systray.connect("tools_clear_xruns", self.slot_JackClearXruns)
|
|
self.systray.connect("configure", self.slot_configureClaudia)
|
|
|
|
self.systray.setToolTip("LADISH Frontend")
|
|
self.systray.show()
|
|
|
|
else:
|
|
self.systray = None
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up Canvas
|
|
|
|
self.scene = patchcanvas.PatchScene(self, self.ui.graphicsView)
|
|
self.ui.graphicsView.setScene(self.scene)
|
|
self.ui.graphicsView.setRenderHint(QPainter.Antialiasing, bool(self.fSavedSettings["Canvas/Antialiasing"] == patchcanvas.ANTIALIASING_FULL))
|
|
if self.fSavedSettings["Canvas/UseOpenGL"] and hasGL:
|
|
self.ui.graphicsView.setViewport(QGLWidget(self.ui.graphicsView))
|
|
self.ui.graphicsView.setRenderHint(QPainter.HighQualityAntialiasing, self.fSavedSettings["Canvas/HighQualityAntialiasing"])
|
|
|
|
pOptions = patchcanvas.options_t()
|
|
pOptions.theme_name = self.fSavedSettings["Canvas/Theme"]
|
|
pOptions.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
|
|
pOptions.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
|
|
pOptions.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
|
|
pOptions.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
|
|
|
|
pFeatures = patchcanvas.features_t()
|
|
pFeatures.group_info = False
|
|
pFeatures.group_rename = True
|
|
pFeatures.port_info = True
|
|
pFeatures.port_rename = True
|
|
pFeatures.handle_group_pos = False
|
|
|
|
patchcanvas.setOptions(pOptions)
|
|
patchcanvas.setFeatures(pFeatures)
|
|
patchcanvas.init("Claudia", self.scene, self.canvasCallback, DEBUG)
|
|
|
|
patchcanvas.setCanvasSize(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
|
|
patchcanvas.setInitialPos(DEFAULT_CANVAS_WIDTH / 2, DEFAULT_CANVAS_HEIGHT / 2)
|
|
self.ui.graphicsView.setSceneRect(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up Canvas Preview
|
|
|
|
self.ui.miniCanvasPreview.setRealParent(self)
|
|
self.ui.miniCanvasPreview.setViewTheme(patchcanvas.canvas.theme.canvas_bg, patchcanvas.canvas.theme.rubberband_brush, patchcanvas.canvas.theme.rubberband_pen.color())
|
|
self.ui.miniCanvasPreview.init(self.scene, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
|
|
QTimer.singleShot(100, self.slot_miniCanvasInit)
|
|
|
|
# -------------------------------------------------------------
|
|
# Check DBus
|
|
|
|
if gDBus.jack.IsStarted():
|
|
self.jackStarted()
|
|
else:
|
|
self.jackStopped()
|
|
|
|
if gDBus.a2j:
|
|
if gDBus.a2j.is_started():
|
|
self.a2jStarted()
|
|
else:
|
|
self.a2jStopped()
|
|
else:
|
|
self.ui.act_tools_a2j_start.setEnabled(False)
|
|
self.ui.act_tools_a2j_stop.setEnabled(False)
|
|
self.ui.act_tools_a2j_export_hw.setEnabled(False)
|
|
self.ui.menu_A2J_Bridge.setEnabled(False)
|
|
|
|
if gDBus.ladish_control.IsStudioLoaded():
|
|
self.studioLoaded()
|
|
if gDBus.ladish_studio.IsStarted():
|
|
self.studioStarted()
|
|
self.initPorts()
|
|
else:
|
|
self.studioStopped()
|
|
else:
|
|
self.studioUnloaded()
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up Timers
|
|
|
|
self.m_timer120 = self.startTimer(self.fSavedSettings["Main/RefreshInterval"])
|
|
self.m_timer600 = self.startTimer(self.fSavedSettings["Main/RefreshInterval"] * 5)
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up Connections
|
|
|
|
self.setCanvasConnections()
|
|
self.setJackConnections(["jack", "transport", "misc"])
|
|
|
|
self.ui.act_studio_new.triggered.connect(self.slot_studio_new)
|
|
self.ui.act_studio_start.triggered.connect(self.slot_studio_start)
|
|
self.ui.act_studio_stop.triggered.connect(self.slot_studio_stop)
|
|
self.ui.act_studio_save.triggered.connect(self.slot_studio_save)
|
|
self.ui.act_studio_save_as.triggered.connect(self.slot_studio_save_as)
|
|
self.ui.act_studio_rename.triggered.connect(self.slot_studio_rename)
|
|
self.ui.act_studio_unload.triggered.connect(self.slot_studio_unload)
|
|
self.ui.act_tools_a2j_start.triggered.connect(self.slot_A2JBridgeStart)
|
|
self.ui.act_tools_a2j_stop.triggered.connect(self.slot_A2JBridgeStop)
|
|
self.ui.act_tools_a2j_export_hw.triggered.connect(self.slot_A2JBridgeExportHW)
|
|
self.ui.b_studio_new.clicked.connect(self.slot_studio_new)
|
|
self.ui.b_studio_load.clicked.connect(self.slot_studio_load_b)
|
|
self.ui.b_studio_save.clicked.connect(self.slot_studio_save)
|
|
self.ui.b_studio_save_as.clicked.connect(self.slot_studio_save_as)
|
|
self.ui.b_studio_start.clicked.connect(self.slot_studio_start)
|
|
self.ui.b_studio_stop.clicked.connect(self.slot_studio_stop)
|
|
self.ui.menu_studio_load.aboutToShow.connect(self.slot_updateMenuStudioList_Load)
|
|
self.ui.menu_studio_delete.aboutToShow.connect(self.slot_updateMenuStudioList_Delete)
|
|
|
|
self.ui.act_room_create.triggered.connect(self.slot_room_create)
|
|
self.ui.menu_room_delete.aboutToShow.connect(self.slot_updateMenuRoomList)
|
|
|
|
self.ui.act_project_new.triggered.connect(self.slot_project_new)
|
|
self.ui.act_project_save.triggered.connect(self.slot_project_save)
|
|
self.ui.act_project_save_as.triggered.connect(self.slot_project_save_as)
|
|
self.ui.act_project_unload.triggered.connect(self.slot_project_unload)
|
|
self.ui.act_project_properties.triggered.connect(self.slot_project_properties)
|
|
self.ui.b_project_new.clicked.connect(self.slot_project_new)
|
|
self.ui.b_project_load.clicked.connect(self.slot_project_load)
|
|
self.ui.b_project_save.clicked.connect(self.slot_project_save)
|
|
self.ui.b_project_save_as.clicked.connect(self.slot_project_save_as)
|
|
self.ui.menu_project_load.aboutToShow.connect(self.slot_updateMenuProjectList)
|
|
|
|
self.ui.act_app_add_new.triggered.connect(self.slot_app_add_new)
|
|
self.ui.act_app_run_custom.triggered.connect(self.slot_app_run_custom)
|
|
|
|
self.ui.treeWidget.itemSelectionChanged.connect(self.slot_checkCurrentRoom)
|
|
#self.ui.treeWidget.itemPressed.connect(self.slot_checkCurrentRoom)
|
|
self.ui.treeWidget.itemDoubleClicked.connect(self.slot_doubleClickedAppList)
|
|
self.ui.treeWidget.customContextMenuRequested.connect(self.slot_showAppListCustomMenu)
|
|
|
|
self.ui.miniCanvasPreview.miniCanvasMoved.connect(self.slot_miniCanvasMoved)
|
|
|
|
self.ui.graphicsView.horizontalScrollBar().valueChanged.connect(self.slot_horizontalScrollBarChanged)
|
|
self.ui.graphicsView.verticalScrollBar().valueChanged.connect(self.slot_verticalScrollBarChanged)
|
|
|
|
self.scene.sceneGroupMoved.connect(self.slot_canvasItemMoved)
|
|
self.scene.scaleChanged.connect(self.slot_canvasScaleChanged)
|
|
|
|
self.ui.act_settings_configure.triggered.connect(self.slot_configureClaudia)
|
|
|
|
self.ui.act_help_about.triggered.connect(self.slot_aboutClaudia)
|
|
self.ui.act_help_about_qt.triggered.connect(app.aboutQt)
|
|
|
|
# org.freedesktop.DBus
|
|
self.DBusCrashCallback.connect(self.slot_DBusCrashCallback)
|
|
|
|
# org.jackaudio.JackControl
|
|
self.DBusServerStartedCallback.connect(self.slot_DBusServerStartedCallback)
|
|
self.DBusServerStoppedCallback.connect(self.slot_DBusServerStoppedCallback)
|
|
|
|
# org.jackaudio.JackPatchbay
|
|
self.DBusClientAppearedCallback.connect(self.slot_DBusClientAppearedCallback)
|
|
self.DBusClientDisappearedCallback.connect(self.slot_DBusClientDisappearedCallback)
|
|
self.DBusClientRenamedCallback.connect(self.slot_DBusClientRenamedCallback)
|
|
self.DBusPortAppearedCallback.connect(self.slot_DBusPortAppearedCallback)
|
|
self.DBusPortDisppearedCallback.connect(self.slot_DBusPortDisppearedCallback)
|
|
self.DBusPortRenamedCallback.connect(self.slot_DBusPortRenamedCallback)
|
|
self.DBusPortsConnectedCallback.connect(self.slot_DBusPortsConnectedCallback)
|
|
self.DBusPortsDisconnectedCallback.connect(self.slot_DBusPortsDisconnectedCallback)
|
|
|
|
# org.ladish.Control
|
|
self.DBusStudioAppearedCallback.connect(self.slot_DBusStudioAppearedCallback)
|
|
self.DBusStudioDisappearedCallback.connect(self.slot_DBusStudioDisappearedCallback)
|
|
self.DBusQueueExecutionHaltedCallback.connect(self.slot_DBusQueueExecutionHaltedCallback)
|
|
self.DBusCleanExitCallback.connect(self.slot_DBusCleanExitCallback)
|
|
|
|
# org.ladish.Studio
|
|
self.DBusStudioStartedCallback.connect(self.slot_DBusStudioStartedCallback)
|
|
self.DBusStudioStoppedCallback.connect(self.slot_DBusStudioStoppedCallback)
|
|
self.DBusStudioRenamedCallback.connect(self.slot_DBusStudioRenamedCallback)
|
|
self.DBusStudioCrashedCallback.connect(self.slot_DBusStudioCrashedCallback)
|
|
self.DBusRoomAppearedCallback.connect(self.slot_DBusRoomAppearedCallback)
|
|
self.DBusRoomDisappearedCallback.connect(self.slot_DBusRoomDisappearedCallback)
|
|
#self.DBusRoomChangedCallback.connect(self.slot_DBusRoomChangedCallback)
|
|
|
|
# org.ladish.Room
|
|
self.DBusProjectPropertiesChanged.connect(self.slot_DBusProjectPropertiesChanged)
|
|
|
|
# org.ladish.AppSupervisor
|
|
self.DBusAppAdded2Callback.connect(self.slot_DBusAppAdded2Callback)
|
|
self.DBusAppRemovedCallback.connect(self.slot_DBusAppRemovedCallback)
|
|
self.DBusAppStateChanged2Callback.connect(self.slot_DBusAppStateChanged2Callback)
|
|
|
|
# JACK
|
|
self.BufferSizeCallback.connect(self.slot_JackBufferSizeCallback)
|
|
self.SampleRateCallback.connect(self.slot_JackSampleRateCallback)
|
|
self.ShutdownCallback.connect(self.slot_JackShutdownCallback)
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up DBus
|
|
|
|
gDBus.bus.add_signal_receiver(self.DBusSignalReceiver, destination_keyword="dest", path_keyword="path",
|
|
member_keyword="member", interface_keyword="interface", sender_keyword="sender")
|
|
|
|
# -------------------------------------------------------------
|
|
|
|
def canvasCallback(self, action, value1, value2, value_str):
|
|
if action == patchcanvas.ACTION_GROUP_INFO:
|
|
pass
|
|
|
|
elif action == patchcanvas.ACTION_GROUP_RENAME:
|
|
group_id = value1
|
|
group_name = value_str
|
|
gDBus.ladish_manager.RenameClient(group_id, group_name)
|
|
|
|
elif action == patchcanvas.ACTION_GROUP_SPLIT:
|
|
group_id = value1
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, URI_CANVAS_SPLIT, "true")
|
|
|
|
patchcanvas.splitGroup(group_id)
|
|
self.ui.miniCanvasPreview.update()
|
|
|
|
elif action == patchcanvas.ACTION_GROUP_JOIN:
|
|
group_id = value1
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, URI_CANVAS_SPLIT, "false")
|
|
|
|
patchcanvas.joinGroup(group_id)
|
|
self.ui.miniCanvasPreview.update()
|
|
|
|
elif action == patchcanvas.ACTION_PORT_INFO:
|
|
this_port_id = value1
|
|
breakNow = False
|
|
|
|
port_id = 0
|
|
port_flags = 0
|
|
port_name = ""
|
|
port_type_jack = 0
|
|
|
|
version, groups, conns = gDBus.patchbay.GetGraph(0)
|
|
|
|
for group in groups:
|
|
group_id, group_name, ports = group
|
|
|
|
for port in ports:
|
|
port_id, port_name, port_flags, port_type_jack = port
|
|
|
|
if this_port_id == port_id:
|
|
breakNow = True
|
|
break
|
|
|
|
if breakNow:
|
|
break
|
|
|
|
else:
|
|
return
|
|
|
|
flags = []
|
|
if port_flags & JACKDBUS_PORT_FLAG_INPUT:
|
|
flags.append(self.tr("Input"))
|
|
if port_flags & JACKDBUS_PORT_FLAG_OUTPUT:
|
|
flags.append(self.tr("Output"))
|
|
if port_flags & JACKDBUS_PORT_FLAG_PHYSICAL:
|
|
flags.append(self.tr("Physical"))
|
|
if port_flags & JACKDBUS_PORT_FLAG_CAN_MONITOR:
|
|
flags.append(self.tr("Can Monitor"))
|
|
if port_flags & JACKDBUS_PORT_FLAG_TERMINAL:
|
|
flags.append(self.tr("Terminal"))
|
|
|
|
flags_text = ""
|
|
for flag in flags:
|
|
if flags_text:
|
|
flags_text += " | "
|
|
flags_text += flag
|
|
|
|
if port_type_jack == JACKDBUS_PORT_TYPE_AUDIO:
|
|
type_text = self.tr("Audio")
|
|
elif port_type_jack == JACKDBUS_PORT_TYPE_MIDI:
|
|
type_text = self.tr("MIDI")
|
|
else:
|
|
type_text = self.tr("Unknown")
|
|
|
|
port_full_name = "%s:%s" % (group_name, port_name)
|
|
|
|
info = self.tr(""
|
|
"<table>"
|
|
"<tr><td align='right'><b>Group ID:</b></td><td> %i</td></tr>"
|
|
"<tr><td align='right'><b>Group Name:</b></td><td> %s</td></tr>"
|
|
"<tr><td align='right'><b>Port ID:</b></td><td> %i</i></td></tr>"
|
|
"<tr><td align='right'><b>Port Name:</b></td><td> %s</td></tr>"
|
|
"<tr><td align='right'><b>Full Port Name:</b></td><td> %s</td></tr>"
|
|
"<tr><td colspan='2'> </td></tr>"
|
|
"<tr><td align='right'><b>Port Flags:</b></td><td> %s</td></tr>"
|
|
"<tr><td align='right'><b>Port Type:</b></td><td> %s</td></tr>"
|
|
"</table>"
|
|
% (group_id, group_name, port_id, port_name, port_full_name, flags_text, type_text))
|
|
|
|
QMessageBox.information(self, self.tr("Port Information"), info)
|
|
|
|
elif action == patchcanvas.ACTION_PORT_RENAME:
|
|
port_id = value1
|
|
port_name = value_str
|
|
gDBus.ladish_manager.RenamePort(port_id, port_name)
|
|
|
|
elif action == patchcanvas.ACTION_PORTS_CONNECT:
|
|
port_a = value1
|
|
port_b = value2
|
|
gDBus.patchbay.ConnectPortsByID(port_a, port_b)
|
|
|
|
elif action == patchcanvas.ACTION_PORTS_DISCONNECT:
|
|
connection_id = value1
|
|
gDBus.patchbay.DisconnectPortsByConnectionID(connection_id)
|
|
|
|
def init_jack(self):
|
|
self.fXruns = -1
|
|
self.fNextSampleRate = 0.0
|
|
|
|
self.fLastBPM = None
|
|
self.fLastTransportState = None
|
|
|
|
bufferSize = int(jacklib.get_buffer_size(gJack.client))
|
|
sampleRate = int(jacklib.get_sample_rate(gJack.client))
|
|
realtime = bool(int(jacklib.is_realtime(gJack.client)))
|
|
|
|
self.ui_setBufferSize(bufferSize)
|
|
self.ui_setSampleRate(sampleRate)
|
|
self.ui_setRealTime(realtime)
|
|
|
|
self.refreshDSPLoad()
|
|
self.refreshTransport()
|
|
self.refreshXruns()
|
|
|
|
self.init_callbacks()
|
|
|
|
jacklib.activate(gJack.client)
|
|
|
|
def init_callbacks(self):
|
|
jacklib.set_buffer_size_callback(gJack.client, self.JackBufferSizeCallback, None)
|
|
jacklib.set_sample_rate_callback(gJack.client, self.JackSampleRateCallback, None)
|
|
jacklib.on_shutdown(gJack.client, self.JackShutdownCallback, None)
|
|
|
|
def init_studio(self):
|
|
self.ui.treeWidget.clear()
|
|
|
|
studio_item = QTreeWidgetItem(ITEM_TYPE_STUDIO)
|
|
studio_item.setText(0, str(gDBus.ladish_studio.GetName()))
|
|
self.ui.treeWidget.insertTopLevelItem(0, studio_item)
|
|
self.ui.treeWidget.setCurrentItem(studio_item)
|
|
|
|
self.m_lastItemType = ITEM_TYPE_STUDIO
|
|
self.m_lastRoomPath = None
|
|
|
|
self.init_apps()
|
|
|
|
def init_apps(self):
|
|
studio_iface = dbus.Interface(gDBus.ladish_studio, 'org.ladish.AppSupervisor')
|
|
studio_item = self.ui.treeWidget.topLevelItem(0)
|
|
|
|
graph_version, app_list = studio_iface.GetAll2()
|
|
|
|
for app in app_list:
|
|
number, name, active, terminal, level = app
|
|
|
|
prop_obj = [None, None, None, None, None]
|
|
prop_obj[iItemPropNumber] = int(number)
|
|
prop_obj[iItemPropName] = str(name)
|
|
prop_obj[iItemPropActive] = bool(active)
|
|
prop_obj[iItemPropTerminal] = bool(terminal)
|
|
prop_obj[iItemPropLevel] = str(level)
|
|
|
|
text = "["
|
|
if level.isdigit():
|
|
text += "L%s" % level
|
|
elif level == "jacksession":
|
|
text += "JS"
|
|
else:
|
|
text += level.upper()
|
|
text += "] "
|
|
if not active:
|
|
text += "(inactive) "
|
|
text += name
|
|
|
|
item = QTreeWidgetItem(ITEM_TYPE_STUDIO_APP)
|
|
item.properties = prop_obj
|
|
item.setText(0, text)
|
|
studio_item.addChild(item)
|
|
|
|
room_list = gDBus.ladish_studio.GetRoomList()
|
|
|
|
for room in room_list:
|
|
room_path, room_dict = room
|
|
ladish_room = gDBus.bus.get_object("org.ladish", room_path)
|
|
room_name = ladish_room.GetName()
|
|
|
|
room_app_iface = dbus.Interface(ladish_room, 'org.ladish.AppSupervisor')
|
|
room_item = self.room_add(room_path, room_name)
|
|
|
|
graph_version, app_list = room_app_iface.GetAll2()
|
|
|
|
for app in app_list:
|
|
number, name, active, terminal, level = app
|
|
|
|
prop_obj = [None, None, None, None, None]
|
|
prop_obj[iItemPropNumber] = int(number)
|
|
prop_obj[iItemPropName] = str(name)
|
|
prop_obj[iItemPropActive] = bool(active)
|
|
prop_obj[iItemPropTerminal] = bool(terminal)
|
|
prop_obj[iItemPropLevel] = str(level)
|
|
|
|
text = "["
|
|
if level.isdigit():
|
|
text += "L%s" % level
|
|
elif level == "jacksession":
|
|
text += "JS"
|
|
else:
|
|
text += level.upper()
|
|
text += "] "
|
|
if not active:
|
|
text += "(inactive) "
|
|
text += name
|
|
|
|
item = QTreeWidgetItem(ITEM_TYPE_ROOM_APP)
|
|
item.properties = prop_obj
|
|
item.setText(0, text)
|
|
room_item.addChild(item)
|
|
|
|
self.ui.treeWidget.expandAll()
|
|
|
|
def initPorts(self):
|
|
if not (gJack.client and gDBus.patchbay):
|
|
return
|
|
|
|
version, groups, conns = gDBus.patchbay.GetGraph(0)
|
|
|
|
# Graph Ports
|
|
for group in groups:
|
|
group_id, group_name, ports = group
|
|
self.canvas_add_group(int(group_id), str(group_name))
|
|
|
|
for port in ports:
|
|
port_id, port_name, port_flags, port_type_jack = port
|
|
|
|
if port_flags & JACKDBUS_PORT_FLAG_INPUT:
|
|
port_mode = patchcanvas.PORT_MODE_INPUT
|
|
elif port_flags & JACKDBUS_PORT_FLAG_OUTPUT:
|
|
port_mode = patchcanvas.PORT_MODE_OUTPUT
|
|
else:
|
|
port_mode = patchcanvas.PORT_MODE_NULL
|
|
|
|
if port_type_jack == JACKDBUS_PORT_TYPE_AUDIO:
|
|
port_type = patchcanvas.PORT_TYPE_AUDIO_JACK
|
|
elif port_type_jack == JACKDBUS_PORT_TYPE_MIDI:
|
|
if gDBus.ladish_graph.Get(GRAPH_DICT_OBJECT_TYPE_PORT, port_id, URI_A2J_PORT) == "yes":
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_A2J
|
|
else:
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_JACK
|
|
else:
|
|
port_type = patchcanvas.PORT_TYPE_NULL
|
|
|
|
self.canvas_add_port(int(group_id), int(port_id), str(port_name), port_mode, port_type)
|
|
|
|
# Graph Connections
|
|
for conn in conns:
|
|
source_group_id, source_group_name, source_port_id, source_port_name, target_group_id, target_group_name, target_port_id, target_port_name, conn_id = conn
|
|
self.canvas_connect_ports(int(conn_id), int(source_port_id), int(target_port_id))
|
|
|
|
QTimer.singleShot(1000 if (self.fSavedSettings['Canvas/EyeCandy']) else 0, self.ui.miniCanvasPreview.update)
|
|
|
|
def room_add(self, room_path, room_name):
|
|
room_index = int(room_path.replace("/org/ladish/Room", ""))
|
|
room_object = gDBus.bus.get_object("org.ladish", room_path)
|
|
room_project_properties = room_object.GetProjectProperties()
|
|
|
|
# Remove old unused item if needed
|
|
iItem = self.ui.treeWidget.topLevelItem(room_index)
|
|
if iItem and not iItem.isVisible():
|
|
self.ui.treeWidget.takeTopLevelItem(room_index)
|
|
|
|
# Insert padding of items if needed
|
|
for i in range(room_index):
|
|
if not self.ui.treeWidget.topLevelItem(i):
|
|
fake_item = QTreeWidgetItem(ITEM_TYPE_NULL)
|
|
self.ui.treeWidget.insertTopLevelItem(i, fake_item)
|
|
fake_item.setHidden(True)
|
|
|
|
graph_version, project_properties = room_project_properties
|
|
|
|
if len(project_properties) > 0:
|
|
item_string = " (%s)" % project_properties['name']
|
|
else:
|
|
item_string = ""
|
|
|
|
prop_obj = [None, None]
|
|
prop_obj[iItemPropRoomPath] = room_path
|
|
prop_obj[iItemPropRoomName] = room_name
|
|
|
|
item = QTreeWidgetItem(ITEM_TYPE_ROOM)
|
|
item.properties = prop_obj
|
|
item.setText(0, "%s%s" % (room_name, item_string))
|
|
|
|
self.ui.treeWidget.insertTopLevelItem(room_index, item)
|
|
self.ui.treeWidget.expandItem(item)
|
|
|
|
return item
|
|
|
|
def canvas_add_group(self, groupId, groupName):
|
|
# TODO - request ladish client type
|
|
|
|
#if (False):
|
|
#icon = patchcanvas.ICON_HARDWARE
|
|
#split = patchcanvas.SPLIT_NO
|
|
#elif (False):
|
|
#icon = patchcanvas.ICON_LADISH_ROOM
|
|
#split = patchcanvas.SPLIT_NO
|
|
#else:
|
|
|
|
splitTry = gDBus.ladish_graph.Get(GRAPH_DICT_OBJECT_TYPE_CLIENT, groupId, URI_CANVAS_SPLIT)
|
|
|
|
if splitTry == "true":
|
|
groupSplit = patchcanvas.SPLIT_YES
|
|
elif splitTry == "false":
|
|
groupSplit = patchcanvas.SPLIT_NO
|
|
else:
|
|
groupSplit = patchcanvas.SPLIT_UNDEF
|
|
|
|
groupIcon = patchcanvas.ICON_APPLICATION
|
|
|
|
if gJack.client:
|
|
ret, data, dataSize = jacklib.custom_get_data(gJack.client, groupName, URI_CANVAS_ICON)
|
|
|
|
if ret == 0:
|
|
iconName = voidptr2str(data)
|
|
jacklib.free(data)
|
|
|
|
if iconName == "hardware":
|
|
groupIcon = patchcanvas.ICON_HARDWARE
|
|
if groupSplit == patchcanvas.SPLIT_UNDEF:
|
|
groupSplit = patchcanvas.SPLIT_YES
|
|
#elif iconName =="carla":
|
|
#groupIcon = patchcanvas.ICON_CARLA
|
|
elif iconName =="distrho":
|
|
groupIcon = patchcanvas.ICON_DISTRHO
|
|
elif iconName =="file":
|
|
groupIcon = patchcanvas.ICON_FILE
|
|
elif iconName =="plugin":
|
|
groupIcon = patchcanvas.ICON_PLUGIN
|
|
|
|
patchcanvas.addGroup(groupId, groupName, groupSplit, groupIcon)
|
|
|
|
x = gDBus.ladish_graph.Get(GRAPH_DICT_OBJECT_TYPE_CLIENT, groupId, URI_CANVAS_X)
|
|
y = gDBus.ladish_graph.Get(GRAPH_DICT_OBJECT_TYPE_CLIENT, groupId, URI_CANVAS_Y)
|
|
x2 = gDBus.ladish_graph.Get(GRAPH_DICT_OBJECT_TYPE_CLIENT, groupId, URI_CANVAS_X_SPLIT)
|
|
y2 = gDBus.ladish_graph.Get(GRAPH_DICT_OBJECT_TYPE_CLIENT, groupId, URI_CANVAS_Y_SPLIT)
|
|
|
|
if x != None and y != None:
|
|
if x2 is None: x2 = "%f" % (float(x) + 50)
|
|
if y2 is None: y2 = "%f" % (float(y) + 50)
|
|
patchcanvas.setGroupPosFull(groupId, float(x), float(y), float(x2), float(y2))
|
|
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def canvas_remove_group(self, group_id):
|
|
patchcanvas.removeGroup(group_id)
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def canvas_rename_group(self, group_id, new_group_name):
|
|
patchcanvas.renameGroup(group_id, new_group_name)
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def canvas_add_port(self, group_id, port_id, port_name, port_mode, port_type):
|
|
patchcanvas.addPort(group_id, port_id, port_name, port_mode, port_type)
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def canvas_remove_port(self, port_id):
|
|
patchcanvas.removePort(port_id)
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def canvas_rename_port(self, port_id, new_port_name):
|
|
patchcanvas.renamePort(port_id, new_port_name)
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def canvas_connect_ports(self, connection_id, port_a, port_b):
|
|
patchcanvas.connectPorts(connection_id, port_a, port_b)
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def canvas_disconnect_ports(self, connection_id):
|
|
patchcanvas.disconnectPorts(connection_id)
|
|
QTimer.singleShot(0, self.ui.miniCanvasPreview.update)
|
|
|
|
def jackStarted(self):
|
|
if jacksettings.needsInit():
|
|
self.DBusReconnect()
|
|
|
|
if not gJack.client:
|
|
gJack.client = jacklib.client_open("claudia", jacklib.JackNoStartServer, None)
|
|
if not gJack.client:
|
|
return self.jackStopped()
|
|
|
|
canRender = render.canRender()
|
|
|
|
self.ui.act_jack_render.setEnabled(canRender)
|
|
self.ui.b_jack_render.setEnabled(canRender)
|
|
self.menuJackTransport(True)
|
|
self.menuA2JBridge(False)
|
|
|
|
self.ui.cb_buffer_size.setEnabled(True)
|
|
self.ui.cb_sample_rate.setEnabled(True) # jacksettings.getSampleRate() != -1
|
|
|
|
if self.systray:
|
|
self.systray.setActionEnabled("tools_render", canRender)
|
|
|
|
self.ui.pb_dsp_load.setMaximum(100)
|
|
self.ui.pb_dsp_load.setValue(0)
|
|
self.ui.pb_dsp_load.update()
|
|
|
|
self.init_jack()
|
|
|
|
self.m_crashedJACK = False
|
|
|
|
def jackStopped(self):
|
|
#self.DBusReconnect()
|
|
|
|
# client already closed
|
|
gJack.client = None
|
|
|
|
if self.fNextSampleRate:
|
|
self.jack_setSampleRate(self.fNextSampleRate)
|
|
|
|
bufferSize = jacksettings.getBufferSize()
|
|
sampleRate = jacksettings.getSampleRate()
|
|
bufferSizeTest = bool(bufferSize != -1)
|
|
sampleRateTest = bool(sampleRate != -1)
|
|
|
|
if bufferSizeTest:
|
|
self.ui_setBufferSize(bufferSize)
|
|
|
|
if sampleRateTest:
|
|
self.ui_setSampleRate(sampleRate)
|
|
|
|
self.ui_setRealTime(jacksettings.isRealtime())
|
|
self.ui_setXruns(-1)
|
|
|
|
self.ui.cb_buffer_size.setEnabled(bufferSizeTest)
|
|
self.ui.cb_sample_rate.setEnabled(sampleRateTest)
|
|
|
|
self.ui.act_jack_render.setEnabled(False)
|
|
self.ui.b_jack_render.setEnabled(False)
|
|
self.menuJackTransport(False)
|
|
self.menuA2JBridge(False)
|
|
|
|
if self.systray:
|
|
self.systray.setActionEnabled("tools_render", False)
|
|
|
|
if self.fCurTransportView == TRANSPORT_VIEW_HMS:
|
|
self.ui.label_time.setText("00:00:00")
|
|
elif self.fCurTransportView == TRANSPORT_VIEW_BBT:
|
|
self.ui.label_time.setText("000|0|0000")
|
|
elif self.fCurTransportView == TRANSPORT_VIEW_FRAMES:
|
|
self.ui.label_time.setText("000'000'000")
|
|
|
|
self.ui.pb_dsp_load.setValue(0)
|
|
self.ui.pb_dsp_load.setMaximum(0)
|
|
self.ui.pb_dsp_load.update()
|
|
|
|
def studioStarted(self):
|
|
self.ui.act_studio_start.setEnabled(False)
|
|
self.ui.act_studio_stop.setEnabled(True)
|
|
self.ui.act_studio_save.setEnabled(True)
|
|
self.ui.act_studio_save_as.setEnabled(True)
|
|
|
|
self.ui.b_studio_save.setEnabled(True)
|
|
self.ui.b_studio_save_as.setEnabled(True)
|
|
self.ui.b_studio_start.setEnabled(False)
|
|
self.ui.b_studio_stop.setEnabled(True)
|
|
|
|
if self.systray:
|
|
self.systray.setActionEnabled("studio_start", False)
|
|
self.systray.setActionEnabled("studio_stop", True)
|
|
self.systray.setActionEnabled("studio_save", True)
|
|
self.systray.setActionEnabled("studio_save_as", True)
|
|
|
|
def studioStopped(self):
|
|
self.ui.act_studio_start.setEnabled(True)
|
|
self.ui.act_studio_stop.setEnabled(False)
|
|
self.ui.act_studio_save.setEnabled(False)
|
|
self.ui.act_studio_save_as.setEnabled(False)
|
|
|
|
self.ui.b_studio_save.setEnabled(False)
|
|
self.ui.b_studio_save_as.setEnabled(False)
|
|
self.ui.b_studio_start.setEnabled(True)
|
|
self.ui.b_studio_stop.setEnabled(False)
|
|
|
|
if self.systray:
|
|
self.systray.setActionEnabled("studio_start", True)
|
|
self.systray.setActionEnabled("studio_stop", False)
|
|
self.systray.setActionEnabled("studio_save", False)
|
|
self.systray.setActionEnabled("studio_save_as", False)
|
|
|
|
def studioLoaded(self):
|
|
gDBus.ladish_studio = gDBus.bus.get_object("org.ladish", "/org/ladish/Studio")
|
|
gDBus.ladish_graph = dbus.Interface(gDBus.ladish_studio, 'org.ladish.GraphDict')
|
|
gDBus.ladish_manager = dbus.Interface(gDBus.ladish_studio, 'org.ladish.GraphManager')
|
|
gDBus.ladish_app_iface = dbus.Interface(gDBus.ladish_studio, 'org.ladish.AppSupervisor')
|
|
gDBus.patchbay = dbus.Interface(gDBus.ladish_studio, 'org.jackaudio.JackPatchbay')
|
|
|
|
self.ui.label_first_time.setVisible(False)
|
|
self.ui.graphicsView.setVisible(True)
|
|
self.ui.miniCanvasPreview.setVisible(True)
|
|
#if (self.ui.miniCanvasPreview.is_initiated):
|
|
#self.checkMiniCanvasSize()
|
|
|
|
self.ui.menu_Room.setEnabled(True)
|
|
self.ui.menu_Project.setEnabled(False)
|
|
self.ui.menu_Application.setEnabled(True)
|
|
self.ui.group_project.setEnabled(False)
|
|
|
|
self.ui.act_studio_rename.setEnabled(True)
|
|
self.ui.act_studio_unload.setEnabled(True)
|
|
|
|
if self.systray:
|
|
self.systray.setActionEnabled("studio_rename", True)
|
|
self.systray.setActionEnabled("studio_unload", True)
|
|
|
|
self.init_studio()
|
|
|
|
self.m_crashedLADISH = False
|
|
|
|
def studioUnloaded(self):
|
|
gDBus.ladish_studio = None
|
|
gDBus.ladish_graph = None
|
|
gDBus.ladish_manager = None
|
|
gDBus.ladish_app_iface = None
|
|
gDBus.patchbay = None
|
|
|
|
self.m_lastItemType = None
|
|
self.m_lastRoomPath = None
|
|
|
|
self.ui.label_first_time.setVisible(True)
|
|
self.ui.graphicsView.setVisible(False)
|
|
self.ui.miniCanvasPreview.setVisible(False)
|
|
|
|
self.ui.menu_Room.setEnabled(False)
|
|
self.ui.menu_Project.setEnabled(False)
|
|
self.ui.menu_Application.setEnabled(False)
|
|
self.ui.group_project.setEnabled(False)
|
|
|
|
self.ui.act_studio_start.setEnabled(False)
|
|
self.ui.act_studio_stop.setEnabled(False)
|
|
self.ui.act_studio_rename.setEnabled(False)
|
|
self.ui.act_studio_save.setEnabled(False)
|
|
self.ui.act_studio_save_as.setEnabled(False)
|
|
self.ui.act_studio_unload.setEnabled(False)
|
|
|
|
self.ui.b_studio_save.setEnabled(False)
|
|
self.ui.b_studio_save_as.setEnabled(False)
|
|
self.ui.b_studio_start.setEnabled(False)
|
|
self.ui.b_studio_stop.setEnabled(False)
|
|
|
|
if self.systray:
|
|
self.systray.setActionEnabled("studio_start", False)
|
|
self.systray.setActionEnabled("studio_stop", False)
|
|
self.systray.setActionEnabled("studio_rename", False)
|
|
self.systray.setActionEnabled("studio_save", False)
|
|
self.systray.setActionEnabled("studio_save_as", False)
|
|
self.systray.setActionEnabled("studio_unload", False)
|
|
|
|
self.ui.treeWidget.clear()
|
|
|
|
patchcanvas.clear()
|
|
|
|
def a2jStarted(self):
|
|
self.menuA2JBridge(True)
|
|
|
|
def a2jStopped(self):
|
|
self.menuA2JBridge(False)
|
|
|
|
def menuJackTransport(self, enabled):
|
|
self.ui.act_transport_play.setEnabled(enabled)
|
|
self.ui.act_transport_stop.setEnabled(enabled)
|
|
self.ui.act_transport_backwards.setEnabled(enabled)
|
|
self.ui.act_transport_forwards.setEnabled(enabled)
|
|
self.ui.menu_Transport.setEnabled(enabled)
|
|
self.ui.group_transport.setEnabled(enabled)
|
|
|
|
def menuA2JBridge(self, started):
|
|
if not gDBus.jack.IsStarted():
|
|
self.ui.act_tools_a2j_start.setEnabled(False)
|
|
self.ui.act_tools_a2j_stop.setEnabled(False)
|
|
self.ui.act_tools_a2j_export_hw.setEnabled(bool(gDBus.a2j) and not gDBus.a2j.is_started())
|
|
else:
|
|
self.ui.act_tools_a2j_start.setEnabled(not started)
|
|
self.ui.act_tools_a2j_stop.setEnabled(started)
|
|
self.ui.act_tools_a2j_export_hw.setEnabled(not started)
|
|
|
|
def DBusSignalReceiver(self, *args, **kwds):
|
|
if kwds['interface'] == "org.freedesktop.DBus" and kwds['path'] == "/org/freedesktop/DBus" and kwds['member'] == "NameOwnerChanged":
|
|
appInterface, appId, newId = args
|
|
#print("appInterface crashed", appInterface)
|
|
|
|
if not newId:
|
|
# Something crashed
|
|
if appInterface == "org.gna.home.a2jmidid":
|
|
QTimer.singleShot(0, self.slot_handleCrash_a2j)
|
|
elif appInterface in ("org.jackaudio.service", "org.ladish"):
|
|
# Prevent any more dbus calls
|
|
gDBus.jack = None
|
|
gJack.client = None
|
|
jacksettings.initBus(None)
|
|
self.DBusCrashCallback.emit(appInterface)
|
|
|
|
elif kwds['interface'] == "org.jackaudio.JackControl":
|
|
if DEBUG: print("DBus signal @org.jackaudio.JackControl,", kwds['member'])
|
|
if kwds['member'] == "ServerStarted":
|
|
self.DBusServerStartedCallback.emit()
|
|
elif kwds['member'] == "ServerStopped":
|
|
self.DBusServerStoppedCallback.emit()
|
|
|
|
elif kwds['interface'] == "org.jackaudio.JackPatchbay":
|
|
if gDBus.patchbay and kwds['path'] == gDBus.patchbay.object_path:
|
|
if DEBUG: print("DBus signal @org.jackaudio.JackPatchbay,", kwds['member'])
|
|
if kwds['member'] == "ClientAppeared":
|
|
self.DBusClientAppearedCallback.emit(args[iJackClientId], args[iJackClientName])
|
|
elif kwds['member'] == "ClientDisappeared":
|
|
self.DBusClientDisappearedCallback.emit(args[iJackClientId])
|
|
elif kwds['member'] == "ClientRenamed":
|
|
self.DBusClientRenamedCallback.emit(args[iRenamedId], args[iRenamedNewName])
|
|
elif kwds['member'] == "PortAppeared":
|
|
self.DBusPortAppearedCallback.emit(args[iJackClientId], args[iJackPortId], args[iJackPortName], args[iJackPortFlags], args[iJackPortType])
|
|
elif kwds['member'] == "PortDisappeared":
|
|
self.DBusPortDisppearedCallback.emit(args[iJackPortId])
|
|
elif kwds['member'] == "PortRenamed":
|
|
self.DBusPortRenamedCallback.emit(args[iJackPortId], args[iJackPortNewName])
|
|
elif kwds['member'] == "PortsConnected":
|
|
self.DBusPortsConnectedCallback.emit(args[iJackConnId], args[iSourcePortId], args[iTargetPortId])
|
|
elif kwds['member'] == "PortsDisconnected":
|
|
self.DBusPortsDisconnectedCallback.emit(args[iJackConnId])
|
|
|
|
elif kwds['interface'] == "org.ladish.Control":
|
|
if DEBUG: print("DBus signal @org.ladish.Control,", kwds['member'])
|
|
if kwds['member'] == "StudioAppeared":
|
|
self.DBusStudioAppearedCallback.emit()
|
|
elif kwds['member'] == "StudioDisappeared":
|
|
self.DBusStudioDisappearedCallback.emit()
|
|
elif kwds['member'] == "QueueExecutionHalted":
|
|
self.DBusQueueExecutionHaltedCallback.emit()
|
|
elif kwds['member'] == "CleanExit":
|
|
self.DBusCleanExitCallback.emit()
|
|
|
|
elif kwds['interface'] == "org.ladish.Studio":
|
|
if DEBUG: print("DBus signal @org.ladish.Studio,", kwds['member'])
|
|
if kwds['member'] == "StudioStarted":
|
|
self.DBusStudioStartedCallback.emit()
|
|
elif kwds['member'] == "StudioStopped":
|
|
self.DBusStudioStoppedCallback.emit()
|
|
elif kwds['member'] == "StudioRenamed":
|
|
self.DBusStudioRenamedCallback.emit(args[iStudioRenamedName])
|
|
elif kwds['member'] == "StudioCrashed":
|
|
self.DBusStudioCrashedCallback.emit()
|
|
elif kwds['member'] == "RoomAppeared":
|
|
self.DBusRoomAppearedCallback.emit(args[iRoomAppearedPath], args[iRoomAppearedDict]['name'])
|
|
elif kwds['member'] == "RoomDisappeared":
|
|
self.DBusRoomDisappearedCallback.emit(args[iRoomAppearedPath])
|
|
#elif kwds['member'] == "RoomChanged":
|
|
#self.DBusRoomChangedCallback.emit()
|
|
|
|
elif kwds['interface'] == "org.ladish.Room":
|
|
if DEBUG: print("DBus signal @org.ladish.Room,", kwds['member'])
|
|
if kwds['member'] == "ProjectPropertiesChanged":
|
|
if "name" in args[iProjChangedDict].keys():
|
|
self.DBusProjectPropertiesChanged.emit(kwds['path'], args[iProjChangedDict]['name'])
|
|
else:
|
|
self.DBusProjectPropertiesChanged.emit(kwds['path'], "")
|
|
|
|
elif kwds['interface'] == "org.ladish.AppSupervisor":
|
|
if DEBUG: print("DBus signal @org.ladish.AppSupervisor,", kwds['member'])
|
|
if kwds['member'] == "AppAdded2":
|
|
self.DBusAppAdded2Callback.emit(kwds['path'], args[iAppChangedNumber], args[iAppChangedName], args[iAppChangedActive], args[iAppChangedTerminal], args[iAppChangedLevel])
|
|
elif kwds['member'] == "AppRemoved":
|
|
self.DBusAppRemovedCallback.emit(kwds['path'], args[iAppChangedNumber])
|
|
elif kwds['member'] == "AppStateChanged2":
|
|
self.DBusAppStateChanged2Callback.emit(kwds['path'], args[iAppChangedNumber], args[iAppChangedName], args[iAppChangedActive], args[iAppChangedTerminal], args[iAppChangedLevel])
|
|
|
|
elif kwds['interface'] == "org.gna.home.a2jmidid.control":
|
|
if kwds['member'] == "bridge_started":
|
|
self.a2jStarted()
|
|
elif kwds['member'] == "bridge_stopped":
|
|
self.a2jStopped()
|
|
|
|
def DBusReconnect(self):
|
|
gDBus.jack = gDBus.bus.get_object("org.jackaudio.service", "/org/jackaudio/Controller")
|
|
gDBus.ladish_control = gDBus.bus.get_object("org.ladish", "/org/ladish/Control")
|
|
gDBus.ladish_studio = None
|
|
gDBus.ladish_room = None
|
|
gDBus.ladish_graph = None
|
|
gDBus.ladish_manager = None
|
|
gDBus.ladish_app_iface = None
|
|
gDBus.patchbay = None
|
|
|
|
try:
|
|
gDBus.ladish_app_daemon = gDBus.bus.get_object("org.ladish.appdb", "/")
|
|
except:
|
|
gDBus.ladish_app_daemon = None
|
|
|
|
try:
|
|
gDBus.a2j = dbus.Interface(gDBus.bus.get_object("org.gna.home.a2jmidid", "/"), "org.gna.home.a2jmidid.control")
|
|
except:
|
|
gDBus.a2j = None
|
|
|
|
jacksettings.initBus(gDBus.bus)
|
|
|
|
def refreshXruns(self):
|
|
if not gDBus.jack:
|
|
#if not self.m_crashedJACK:
|
|
#self.DBusReconnect()
|
|
return
|
|
|
|
xruns = int(gDBus.jack.GetXruns())
|
|
if self.fXruns != xruns:
|
|
self.ui_setXruns(xruns)
|
|
self.fXruns = xruns
|
|
|
|
def JackBufferSizeCallback(self, buffer_size, arg):
|
|
if DEBUG: print("JackBufferSizeCallback(%i)" % buffer_size)
|
|
self.BufferSizeCallback.emit(buffer_size)
|
|
return 0
|
|
|
|
def JackSampleRateCallback(self, sample_rate, arg):
|
|
if DEBUG: print("JackSampleRateCallback(%i)" % sample_rate)
|
|
self.SampleRateCallback.emit(sample_rate)
|
|
return 0
|
|
|
|
def JackShutdownCallback(self, arg):
|
|
if DEBUG: print("JackShutdownCallback")
|
|
self.ShutdownCallback.emit()
|
|
return 0
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_new(self):
|
|
dialog = StudioNameW(self, StudioNameW.NEW)
|
|
if dialog.exec_():
|
|
gDBus.ladish_control.NewStudio(dialog.fRetStudioName)
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_load_b(self):
|
|
dialog = StudioListW(self)
|
|
if dialog.exec_():
|
|
gDBus.ladish_control.LoadStudio(dialog.ret_studio_name)
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_load_m(self):
|
|
studio_name = self.sender().property("data")
|
|
if studio_name:
|
|
gDBus.ladish_control.LoadStudio(studio_name)
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_start(self):
|
|
gDBus.ladish_studio.Start()
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_stop(self):
|
|
gDBus.ladish_studio.Stop()
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_rename(self):
|
|
dialog = StudioNameW(self, StudioNameW.RENAME)
|
|
if dialog.exec_():
|
|
gDBus.ladish_studio.Rename(dialog.fRetStudioName)
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_save(self):
|
|
gDBus.ladish_studio.Save()
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_save_as(self):
|
|
dialog = StudioNameW(self, StudioNameW.SAVE_AS)
|
|
if dialog.exec_():
|
|
gDBus.ladish_studio.SaveAs(dialog.fRetStudioName)
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_unload(self):
|
|
gDBus.ladish_studio.Unload()
|
|
|
|
@pyqtSlot()
|
|
def slot_studio_delete_m(self):
|
|
studio_name = self.sender().property("data")
|
|
if studio_name:
|
|
gDBus.ladish_control.DeleteStudio(studio_name)
|
|
|
|
@pyqtSlot()
|
|
def slot_room_create(self):
|
|
dialog = CreateRoomW(self)
|
|
if dialog.exec_():
|
|
gDBus.ladish_studio.CreateRoom(dialog.ret_room_name, dialog.ret_room_template)
|
|
|
|
@pyqtSlot()
|
|
def slot_room_delete_m(self):
|
|
room_name = self.sender().property("data")
|
|
if room_name:
|
|
gDBus.ladish_studio.DeleteRoom(room_name)
|
|
|
|
@pyqtSlot()
|
|
def slot_project_new(self):
|
|
dialog = ProjectNameW(self, ProjectNameW.NEW, self.fSavedSettings["Main/DefaultProjectFolder"])
|
|
if dialog.exec_():
|
|
# Check if a project is already loaded, if yes unload it first
|
|
project_graph_version, project_properties = gDBus.ladish_room.GetProjectProperties()
|
|
if len(project_properties) > 0:
|
|
gDBus.ladish_room.UnloadProject()
|
|
gDBus.ladish_room.SaveProject(dialog.ret_project_path, dialog.ret_project_name)
|
|
|
|
@pyqtSlot()
|
|
def slot_project_load(self):
|
|
project_path = QFileDialog.getExistingDirectory(self, self.tr("Open Project"), self.fSavedSettings["Main/DefaultProjectFolder"])
|
|
if project_path:
|
|
if os.path.exists(os.path.join(project_path, "ladish-project.xml")):
|
|
gDBus.ladish_room.LoadProject(project_path)
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("The selected folder does not contain a ladish project"))
|
|
|
|
@pyqtSlot()
|
|
def slot_project_load_m(self):
|
|
act_x_text = self.sender().property("data")
|
|
if act_x_text:
|
|
proj_path = "/" + act_x_text.rsplit("[/", 1)[-1].rsplit("]", 1)[0]
|
|
gDBus.ladish_room.LoadProject(proj_path)
|
|
|
|
@pyqtSlot()
|
|
def slot_project_save(self):
|
|
project_graph_version, project_properties = gDBus.ladish_room.GetProjectProperties()
|
|
if len(project_properties) > 0:
|
|
path = dbus.String(project_properties['dir'])
|
|
name = dbus.String(project_properties['name'])
|
|
gDBus.ladish_room.SaveProject(path, name)
|
|
else:
|
|
self.slot_project_new()
|
|
|
|
@pyqtSlot()
|
|
def slot_project_save_as(self):
|
|
project_graph_version, project_properties = gDBus.ladish_room.GetProjectProperties()
|
|
|
|
if len(project_properties) > 0:
|
|
path = str(project_properties['dir'])
|
|
name = str(project_properties['name'])
|
|
dialog = ProjectNameW(self, ProjectNameW.SAVE_AS, self.fSavedSettings["Main/DefaultProjectFolder"], path, name)
|
|
|
|
if dialog.exec_():
|
|
gDBus.ladish_room.SaveProject(dialog.ret_project_path, dialog.ret_project_name)
|
|
|
|
else:
|
|
self.slot_project_new()
|
|
|
|
@pyqtSlot()
|
|
def slot_project_unload(self):
|
|
gDBus.ladish_room.UnloadProject()
|
|
|
|
@pyqtSlot()
|
|
def slot_project_properties(self):
|
|
project_graph_version, project_properties = gDBus.ladish_room.GetProjectProperties()
|
|
|
|
path = str(project_properties['dir'])
|
|
name = str(project_properties['name'])
|
|
|
|
if "description" in project_properties.keys():
|
|
description = str(project_properties['description'])
|
|
else:
|
|
description = ""
|
|
|
|
if "notes" in project_properties.keys():
|
|
notes = str(project_properties['notes'])
|
|
else:
|
|
notes = ""
|
|
|
|
dialog = ProjectPropertiesW(self, name, description, notes)
|
|
|
|
if dialog.exec_():
|
|
gDBus.ladish_room.SetProjectDescription(dialog.ret_obj[iAppPropDescription])
|
|
gDBus.ladish_room.SetProjectNotes(dialog.ret_obj[iAppPropNotes])
|
|
|
|
if dialog.ret_obj[iAppPropSaveNow]:
|
|
gDBus.ladish_room.SaveProject(path, dialog.ret_obj[iAppPropName])
|
|
|
|
@pyqtSlot()
|
|
def slot_app_add_new(self):
|
|
proj_folder = ""
|
|
|
|
if self.m_lastItemType == ITEM_TYPE_STUDIO or self.m_lastItemType == ITEM_TYPE_STUDIO_APP:
|
|
proj_folder = self.fSavedSettings['Main/DefaultProjectFolder']
|
|
is_room = False
|
|
|
|
elif self.m_lastItemType == ITEM_TYPE_ROOM or self.m_lastItemType == ITEM_TYPE_ROOM_APP:
|
|
project_graph_version, project_properties = gDBus.ladish_room.GetProjectProperties()
|
|
|
|
if len(project_properties) > 0:
|
|
proj_folder = str(project_properties['dir'])
|
|
is_room = True
|
|
else:
|
|
proj_folder = self.fSavedSettings['Main/DefaultProjectFolder']
|
|
is_room = False
|
|
|
|
else:
|
|
print("Invalid m_last_item_type value")
|
|
return
|
|
|
|
dialog = ClaudiaLauncherW(self, gDBus.ladish_app_iface, proj_folder, is_room, self.fLastBPM, self.fSampleRate)
|
|
dialog.exec_()
|
|
|
|
@pyqtSlot()
|
|
def slot_app_run_custom(self):
|
|
dialog = RunCustomW(self, bool(self.m_lastItemType in (ITEM_TYPE_ROOM, ITEM_TYPE_ROOM_APP)))
|
|
if dialog.exec_() and dialog.ret_app_obj:
|
|
app_obj = dialog.ret_app_obj
|
|
gDBus.ladish_app_iface.RunCustom2(app_obj[iAppTerminal], app_obj[iAppCommand], app_obj[iAppName], app_obj[iAppLevel])
|
|
|
|
@pyqtSlot()
|
|
def slot_checkCurrentRoom(self):
|
|
item = self.ui.treeWidget.currentItem()
|
|
room_path = None
|
|
|
|
if not item:
|
|
return
|
|
|
|
if item.type() in (ITEM_TYPE_STUDIO, ITEM_TYPE_STUDIO_APP):
|
|
self.ui.menu_Project.setEnabled(False)
|
|
self.ui.group_project.setEnabled(False)
|
|
self.ui.menu_Application.setEnabled(True)
|
|
|
|
gDBus.ladish_room = None
|
|
gDBus.ladish_app_iface = dbus.Interface(gDBus.ladish_studio, "org.ladish.AppSupervisor")
|
|
ITEM_TYPE = ITEM_TYPE_STUDIO
|
|
|
|
elif item.type() in (ITEM_TYPE_ROOM, ITEM_TYPE_ROOM_APP):
|
|
self.ui.menu_Project.setEnabled(True)
|
|
self.ui.group_project.setEnabled(True)
|
|
|
|
if item.type() == ITEM_TYPE_ROOM:
|
|
room_path = item.properties[iItemPropRoomPath]
|
|
elif item.type() == ITEM_TYPE_ROOM_APP:
|
|
room_path = item.parent().properties[iItemPropRoomPath]
|
|
else:
|
|
return
|
|
|
|
gDBus.ladish_room = gDBus.bus.get_object("org.ladish", room_path)
|
|
gDBus.ladish_app_iface = dbus.Interface(gDBus.ladish_room, "org.ladish.AppSupervisor")
|
|
ITEM_TYPE = ITEM_TYPE_ROOM
|
|
|
|
project_graph_version, project_properties = gDBus.ladish_room.GetProjectProperties()
|
|
|
|
has_project = bool(len(project_properties) > 0)
|
|
self.ui.act_project_save.setEnabled(has_project)
|
|
self.ui.act_project_save_as.setEnabled(has_project)
|
|
self.ui.act_project_unload.setEnabled(has_project)
|
|
self.ui.act_project_properties.setEnabled(has_project)
|
|
self.ui.b_project_save.setEnabled(has_project)
|
|
self.ui.b_project_save_as.setEnabled(has_project)
|
|
self.ui.menu_Application.setEnabled(has_project)
|
|
|
|
else:
|
|
return
|
|
|
|
if ITEM_TYPE != self.m_lastItemType or room_path != self.m_lastRoomPath:
|
|
if ITEM_TYPE == ITEM_TYPE_STUDIO:
|
|
object_path = gDBus.ladish_studio
|
|
elif ITEM_TYPE == ITEM_TYPE_ROOM:
|
|
object_path = gDBus.ladish_room
|
|
else:
|
|
return
|
|
|
|
patchcanvas.clear()
|
|
gDBus.patchbay = dbus.Interface(object_path, 'org.jackaudio.JackPatchbay')
|
|
gDBus.ladish_graph = dbus.Interface(object_path, 'org.ladish.GraphDict')
|
|
gDBus.ladish_manager = dbus.Interface(object_path, 'org.ladish.GraphManager')
|
|
self.initPorts()
|
|
|
|
self.m_lastItemType = ITEM_TYPE
|
|
self.m_lastRoomPath = room_path
|
|
|
|
@pyqtSlot(QTreeWidgetItem, int)
|
|
def slot_doubleClickedAppList(self, item, row):
|
|
if item.type() in (ITEM_TYPE_STUDIO_APP, ITEM_TYPE_ROOM_APP):
|
|
if item.properties[iItemPropActive]:
|
|
gDBus.ladish_app_iface.StopApp(item.properties[iItemPropNumber])
|
|
else:
|
|
gDBus.ladish_app_iface.StartApp(item.properties[iItemPropNumber])
|
|
|
|
@pyqtSlot()
|
|
def slot_updateMenuStudioList_Load(self):
|
|
self.ui.menu_studio_load.clear()
|
|
|
|
studio_list = gDBus.ladish_control.GetStudioList()
|
|
if len(studio_list) == 0:
|
|
act_no_studio = QAction(self.tr("Empty studio list"), self.ui.menu_studio_load)
|
|
act_no_studio.setEnabled(False)
|
|
self.ui.menu_studio_load.addAction(act_no_studio)
|
|
else:
|
|
for studio in studio_list:
|
|
studio_name = str(studio[iStudioListName])
|
|
act_x_studio = QAction(studio_name, self.ui.menu_studio_load)
|
|
act_x_studio.setProperty("data", studio_name);
|
|
self.ui.menu_studio_load.addAction(act_x_studio)
|
|
act_x_studio.triggered.connect(self.slot_studio_load_m)
|
|
|
|
@pyqtSlot()
|
|
def slot_updateMenuStudioList_Delete(self):
|
|
self.ui.menu_studio_delete.clear()
|
|
|
|
studio_list = gDBus.ladish_control.GetStudioList()
|
|
if len(studio_list) == 0:
|
|
act_no_studio = QAction(self.tr("Empty studio list"), self.ui.menu_studio_delete)
|
|
act_no_studio.setEnabled(False)
|
|
self.ui.menu_studio_delete.addAction(act_no_studio)
|
|
else:
|
|
for studio in studio_list:
|
|
studio_name = str(studio[iStudioListName])
|
|
act_x_studio = QAction(studio_name, self.ui.menu_studio_delete)
|
|
act_x_studio.setProperty("data", studio_name);
|
|
self.ui.menu_studio_delete.addAction(act_x_studio)
|
|
act_x_studio.triggered.connect(self.slot_studio_delete_m)
|
|
|
|
@pyqtSlot()
|
|
def slot_updateMenuRoomList(self):
|
|
self.ui.menu_room_delete.clear()
|
|
if gDBus.ladish_control.IsStudioLoaded():
|
|
room_list = gDBus.ladish_studio.GetRoomList()
|
|
if len(room_list) == 0:
|
|
self.createEmptyMenuRoomActon()
|
|
else:
|
|
for room_path, room_dict in room_list:
|
|
ladish_room = gDBus.bus.get_object("org.ladish", room_path)
|
|
room_name = ladish_room.GetName()
|
|
act_x_room = QAction(room_name, self.ui.menu_room_delete)
|
|
act_x_room.setProperty("data", room_name);
|
|
self.ui.menu_room_delete.addAction(act_x_room)
|
|
act_x_room.triggered.connect(self.slot_room_delete_m)
|
|
else:
|
|
self.createEmptyMenuRoomActon()
|
|
|
|
def createEmptyMenuRoomActon(self):
|
|
act_no_room = QAction(self.tr("Empty room list"), self.ui.menu_room_delete)
|
|
act_no_room.setEnabled(False)
|
|
self.ui.menu_room_delete.addAction(act_no_room)
|
|
|
|
@pyqtSlot()
|
|
def slot_updateMenuProjectList(self):
|
|
self.ui.menu_project_load.clear()
|
|
act_project_load = QAction(self.tr("Load from folder..."), self.ui.menu_project_load)
|
|
self.ui.menu_project_load.addAction(act_project_load)
|
|
act_project_load.triggered.connect(self.slot_project_load)
|
|
|
|
ladish_recent_iface = dbus.Interface(gDBus.ladish_room, "org.ladish.RecentItems")
|
|
proj_list = ladish_recent_iface.get(RECENT_PROJECTS_STORE_MAX_ITEMS)
|
|
|
|
if len(proj_list) > 0:
|
|
self.ui.menu_project_load.addSeparator()
|
|
for proj_path, proj_dict in proj_list:
|
|
if "name" in proj_dict.keys():
|
|
proj_name = proj_dict['name']
|
|
else:
|
|
continue
|
|
|
|
act_x_text = "%s [%s]" % (proj_name, proj_path)
|
|
act_x_proj = QAction(act_x_text, self.ui.menu_project_load)
|
|
act_x_proj.setProperty("data", act_x_text);
|
|
self.ui.menu_project_load.addAction(act_x_proj)
|
|
act_x_proj.triggered.connect(self.slot_project_load_m)
|
|
|
|
@pyqtSlot()
|
|
def slot_showAppListCustomMenu(self):
|
|
item = self.ui.treeWidget.currentItem()
|
|
if item:
|
|
cMenu = QMenu()
|
|
if item.type() == ITEM_TYPE_STUDIO:
|
|
act_x_add_new = cMenu.addAction(self.tr("Add New..."))
|
|
act_x_run_custom = cMenu.addAction(self.tr("Run Custom..."))
|
|
cMenu.addSeparator()
|
|
act_x_create_room = cMenu.addAction(self.tr("Create Room..."))
|
|
|
|
act_x_add_new.setIcon(QIcon.fromTheme("list-add", QIcon(":/16x16/list-add.png")))
|
|
act_x_run_custom.setIcon(QIcon.fromTheme("system-run", QIcon(":/16x16/system-run.png")))
|
|
act_x_create_room.setIcon(QIcon.fromTheme("list-add", QIcon(":/16x16/list-add.png")))
|
|
act_x_add_new.setEnabled(self.ui.act_app_add_new.isEnabled())
|
|
|
|
elif item.type() == ITEM_TYPE_ROOM:
|
|
act_x_add_new = cMenu.addAction(self.tr("Add New..."))
|
|
act_x_run_custom = cMenu.addAction(self.tr("Run Custom..."))
|
|
cMenu.addSeparator()
|
|
act_x_new = cMenu.addAction(self.tr("New Project..."))
|
|
cMenu.addMenu(self.ui.menu_project_load)
|
|
act_x_save = cMenu.addAction(self.tr("Save Project"))
|
|
act_x_save_as = cMenu.addAction(self.tr("Save Project As..."))
|
|
act_x_unload = cMenu.addAction(self.tr("Unload Project"))
|
|
cMenu.addSeparator()
|
|
act_x_properties = cMenu.addAction(self.tr("Project Properties..."))
|
|
cMenu.addSeparator()
|
|
act_x_delete_room = cMenu.addAction(self.tr("Delete Room"))
|
|
|
|
act_x_add_new.setIcon(QIcon.fromTheme("list-add", QIcon(":/16x16/list-add.png")))
|
|
act_x_run_custom.setIcon(QIcon.fromTheme("system-run", QIcon(":/16x16/system-run.png")))
|
|
act_x_new.setIcon(QIcon.fromTheme("document-new", QIcon(":/16x16/document-new.png")))
|
|
act_x_save.setIcon(QIcon.fromTheme("document-save", QIcon(":/16x16/document-save.png")))
|
|
act_x_save_as.setIcon(QIcon.fromTheme("document-save-as", QIcon(":/16x16/document-save-as.png")))
|
|
act_x_unload.setIcon(QIcon.fromTheme("window-close", QIcon(":/16x16/dialog-close.png")))
|
|
act_x_properties.setIcon(QIcon.fromTheme("edit-rename", QIcon(":/16x16/edit-rename.png")))
|
|
act_x_delete_room.setIcon(QIcon.fromTheme("edit-delete", QIcon(":/16x16/edit-delete.png")))
|
|
|
|
act_x_add_new.setEnabled(self.ui.menu_Application.isEnabled() and self.ui.act_app_add_new.isEnabled())
|
|
|
|
project_graph_version, project_properties = gDBus.ladish_room.GetProjectProperties()
|
|
|
|
if len(project_properties) == 0:
|
|
act_x_run_custom.setEnabled(False)
|
|
act_x_save.setEnabled(False)
|
|
act_x_save_as.setEnabled(False)
|
|
act_x_unload.setEnabled(False)
|
|
act_x_properties.setEnabled(False)
|
|
|
|
elif item.type() in (ITEM_TYPE_STUDIO_APP, ITEM_TYPE_ROOM_APP):
|
|
if item.properties[iItemPropActive]:
|
|
act_x_start = None
|
|
act_x_stop = cMenu.addAction(self.tr("Stop"))
|
|
act_x_kill = cMenu.addAction(self.tr("Kill"))
|
|
act_x_stop.setIcon(QIcon.fromTheme("media-playback-stop", QIcon(":/16x16/media-playback-stop.png")))
|
|
act_x_kill.setIcon(QIcon.fromTheme("dialog-close", QIcon(":/16x16/dialog-close.png")))
|
|
else:
|
|
act_x_start = cMenu.addAction(self.tr("Start"))
|
|
act_x_stop = None
|
|
act_x_kill = None
|
|
act_x_start.setIcon(QIcon.fromTheme("media-playback-start", QIcon(":/16x16/media-playback-start.png")))
|
|
act_x_properties = cMenu.addAction(self.tr("Properties"))
|
|
cMenu.addSeparator()
|
|
act_x_remove = cMenu.addAction(self.tr("Remove"))
|
|
act_x_properties.setIcon(QIcon.fromTheme("edit-rename", QIcon(":/16x16/edit-rename.png")))
|
|
act_x_remove.setIcon(QIcon.fromTheme("edit-delete", QIcon(":/16x16/edit-delete.png")))
|
|
|
|
else:
|
|
return
|
|
|
|
act_x_sel = cMenu.exec_(QCursor.pos())
|
|
|
|
if act_x_sel:
|
|
if item.type() == ITEM_TYPE_STUDIO:
|
|
if act_x_sel == act_x_add_new:
|
|
self.slot_app_add_new()
|
|
elif act_x_sel == act_x_run_custom:
|
|
self.slot_app_run_custom()
|
|
elif act_x_sel == act_x_create_room:
|
|
self.slot_room_create()
|
|
|
|
elif item.type() == ITEM_TYPE_ROOM:
|
|
if act_x_sel == act_x_add_new:
|
|
self.slot_app_add_new()
|
|
elif act_x_sel == act_x_run_custom:
|
|
self.slot_app_run_custom()
|
|
elif act_x_sel == act_x_new:
|
|
self.slot_project_new()
|
|
elif act_x_sel == act_x_save:
|
|
self.slot_project_save()
|
|
elif act_x_sel == act_x_save_as:
|
|
self.slot_project_save_as()
|
|
elif act_x_sel == act_x_unload:
|
|
self.slot_project_unload()
|
|
elif act_x_sel == act_x_properties:
|
|
self.slot_project_properties()
|
|
elif act_x_sel == act_x_delete_room:
|
|
room_name = gDBus.ladish_room.GetName()
|
|
gDBus.ladish_studio.DeleteRoom(room_name)
|
|
|
|
elif item.type() in (ITEM_TYPE_STUDIO_APP, ITEM_TYPE_ROOM_APP):
|
|
number = item.properties[iItemPropNumber]
|
|
|
|
if act_x_sel == act_x_start:
|
|
gDBus.ladish_app_iface.StartApp(number)
|
|
elif act_x_sel == act_x_stop:
|
|
gDBus.ladish_app_iface.StopApp(number)
|
|
elif act_x_sel == act_x_kill:
|
|
gDBus.ladish_app_iface.KillApp(number)
|
|
elif act_x_sel == act_x_properties:
|
|
name, command, active, terminal, level = gDBus.ladish_app_iface.GetAppProperties2(number)
|
|
|
|
app_obj = [None, None, None, None, None]
|
|
app_obj[iAppCommand] = str(command)
|
|
app_obj[iAppName] = str(name)
|
|
app_obj[iAppTerminal] = bool(terminal)
|
|
app_obj[iAppLevel] = str(level)
|
|
app_obj[iAppActive] = bool(active)
|
|
|
|
dialog = RunCustomW(self, bool(item.type() == ITEM_TYPE_ROOM_APP), app_obj)
|
|
dialog.setWindowTitle(self.tr("App properties"))
|
|
if dialog.exec_():
|
|
app_obj = dialog.ret_app_obj
|
|
gDBus.ladish_app_iface.SetAppProperties2(number, app_obj[iAppName], app_obj[iAppCommand], app_obj[iAppTerminal], app_obj[iAppLevel])
|
|
|
|
elif act_x_sel == act_x_remove:
|
|
gDBus.ladish_app_iface.RemoveApp(number)
|
|
|
|
@pyqtSlot(float)
|
|
def slot_canvasScaleChanged(self, scale):
|
|
self.ui.miniCanvasPreview.setViewScale(scale)
|
|
|
|
@pyqtSlot(int, int, QPointF)
|
|
def slot_canvasItemMoved(self, group_id, split_mode, pos):
|
|
if split_mode == patchcanvas.PORT_MODE_INPUT:
|
|
canvas_x = URI_CANVAS_X_SPLIT
|
|
canvas_y = URI_CANVAS_Y_SPLIT
|
|
else:
|
|
canvas_x = URI_CANVAS_X
|
|
canvas_y = URI_CANVAS_Y
|
|
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, canvas_x, str(pos.x()))
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, canvas_y, str(pos.y()))
|
|
|
|
self.ui.miniCanvasPreview.update()
|
|
|
|
@pyqtSlot(int)
|
|
def slot_horizontalScrollBarChanged(self, value):
|
|
maximum = self.ui.graphicsView.horizontalScrollBar().maximum()
|
|
if maximum == 0:
|
|
xp = 0
|
|
else:
|
|
xp = float(value) / maximum
|
|
self.ui.miniCanvasPreview.setViewPosX(xp)
|
|
|
|
@pyqtSlot(int)
|
|
def slot_verticalScrollBarChanged(self, value):
|
|
maximum = self.ui.graphicsView.verticalScrollBar().maximum()
|
|
if maximum == 0:
|
|
yp = 0
|
|
else:
|
|
yp = float(value) / maximum
|
|
self.ui.miniCanvasPreview.setViewPosY(yp)
|
|
|
|
@pyqtSlot()
|
|
def slot_miniCanvasInit(self):
|
|
settings = QSettings()
|
|
self.ui.graphicsView.horizontalScrollBar().setValue(settings.value("HorizontalScrollBarValue", int(DEFAULT_CANVAS_WIDTH / 3), type=int))
|
|
self.ui.graphicsView.verticalScrollBar().setValue(settings.value("VerticalScrollBarValue", int(DEFAULT_CANVAS_HEIGHT * 3 / 8), type=int))
|
|
|
|
@pyqtSlot(float, float)
|
|
def slot_miniCanvasMoved(self, xp, yp):
|
|
self.ui.graphicsView.horizontalScrollBar().setValue(int(xp * DEFAULT_CANVAS_WIDTH))
|
|
self.ui.graphicsView.verticalScrollBar().setValue(int(yp * DEFAULT_CANVAS_HEIGHT))
|
|
|
|
@pyqtSlot()
|
|
def slot_miniCanvasCheckAll(self):
|
|
self.slot_miniCanvasCheckSize()
|
|
self.slot_horizontalScrollBarChanged(self.ui.graphicsView.horizontalScrollBar().value())
|
|
self.slot_verticalScrollBarChanged(self.ui.graphicsView.verticalScrollBar().value())
|
|
|
|
@pyqtSlot()
|
|
def slot_miniCanvasCheckSize(self):
|
|
self.ui.miniCanvasPreview.setViewSize(float(self.ui.graphicsView.width()) / DEFAULT_CANVAS_WIDTH,
|
|
float(self.ui.graphicsView.height()) / DEFAULT_CANVAS_HEIGHT)
|
|
|
|
@pyqtSlot()
|
|
def slot_handleCrash_jack(self):
|
|
patchcanvas.clear()
|
|
self.DBusReconnect()
|
|
self.studioUnloaded()
|
|
|
|
if gDBus.a2j:
|
|
if gDBus.a2j.is_started():
|
|
self.a2jStarted()
|
|
else:
|
|
self.a2jStopped()
|
|
else:
|
|
self.ui.act_tools_a2j_start.setEnabled(False)
|
|
self.ui.act_tools_a2j_stop.setEnabled(False)
|
|
self.ui.act_tools_a2j_export_hw.setEnabled(False)
|
|
self.ui.menu_A2J_Bridge.setEnabled(False)
|
|
|
|
@pyqtSlot()
|
|
def slot_handleCrash_ladish(self):
|
|
self.ui.treeWidget.clear()
|
|
patchcanvas.clear()
|
|
self.DBusReconnect()
|
|
QMessageBox.warning(self, self.tr("Error"), self.tr("ladish daemon has crashed"))
|
|
|
|
@pyqtSlot()
|
|
def slot_handleCrash_studio(self):
|
|
QMessageBox.warning(self, self.tr("Error"), self.tr("jackdbus has crashed"))
|
|
|
|
@pyqtSlot()
|
|
def slot_handleCrash_a2j(self):
|
|
try:
|
|
gDBus.a2j = dbus.Interface(gDBus.bus.get_object("org.gna.home.a2jmidid", "/"), "org.gna.home.a2jmidid.control")
|
|
except:
|
|
gDBus.a2j = None
|
|
|
|
if gDBus.a2j:
|
|
if gDBus.a2j.is_started():
|
|
self.a2jStarted()
|
|
else:
|
|
self.a2jStopped()
|
|
else:
|
|
self.ui.act_tools_a2j_start.setEnabled(False)
|
|
self.ui.act_tools_a2j_stop.setEnabled(False)
|
|
self.ui.act_tools_a2j_export_hw.setEnabled(False)
|
|
self.ui.menu_A2J_Bridge.setEnabled(False)
|
|
|
|
@pyqtSlot(str)
|
|
def slot_DBusCrashCallback(self, appInterface):
|
|
if appInterface == "org.jackaudio.service":
|
|
if not (self.m_crashedJACK or self.m_crashedLADISH):
|
|
self.m_crashedJACK = True
|
|
QTimer.singleShot(1000, self.slot_handleCrash_jack)
|
|
elif appInterface == "org.ladish":
|
|
if not (self.m_crashedJACK or self.m_crashedLADISH):
|
|
self.m_crashedLADISH = True
|
|
QTimer.singleShot(1000, self.slot_handleCrash_ladish)
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusServerStartedCallback(self):
|
|
self.jackStarted()
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusServerStoppedCallback(self):
|
|
self.jackStopped()
|
|
|
|
@pyqtSlot(int, str)
|
|
def slot_DBusClientAppearedCallback(self, group_id, group_name):
|
|
self.canvas_add_group(group_id, group_name)
|
|
|
|
@pyqtSlot(int)
|
|
def slot_DBusClientDisappearedCallback(self, group_id):
|
|
self.canvas_remove_group(group_id)
|
|
|
|
@pyqtSlot(int, str)
|
|
def slot_DBusClientRenamedCallback(self, group_id, new_group_name):
|
|
self.canvas_rename_group(group_id, new_group_name)
|
|
|
|
@pyqtSlot(int, int, str, int, int)
|
|
def slot_DBusPortAppearedCallback(self, group_id, port_id, port_name, port_flags, port_type_jack):
|
|
if port_flags & JACKDBUS_PORT_FLAG_INPUT:
|
|
port_mode = patchcanvas.PORT_MODE_INPUT
|
|
elif port_flags & JACKDBUS_PORT_FLAG_OUTPUT:
|
|
port_mode = patchcanvas.PORT_MODE_OUTPUT
|
|
else:
|
|
port_mode = patchcanvas.PORT_MODE_NULL
|
|
|
|
if port_type_jack == JACKDBUS_PORT_TYPE_AUDIO:
|
|
port_type = patchcanvas.PORT_TYPE_AUDIO_JACK
|
|
elif port_type_jack == JACKDBUS_PORT_TYPE_MIDI:
|
|
if gDBus.ladish_graph.Get(GRAPH_DICT_OBJECT_TYPE_PORT, port_id, URI_A2J_PORT) == "yes":
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_A2J
|
|
else:
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_JACK
|
|
else:
|
|
port_type = patchcanvas.PORT_TYPE_NULL
|
|
|
|
self.canvas_add_port(group_id, port_id, port_name, port_mode, port_type)
|
|
|
|
@pyqtSlot(int)
|
|
def slot_DBusPortDisppearedCallback(self, port_id):
|
|
self.canvas_remove_port(port_id)
|
|
|
|
@pyqtSlot(int, str)
|
|
def slot_DBusPortRenamedCallback(self, port_id, new_port_name):
|
|
self.canvas_rename_port(port_id, new_port_name)
|
|
|
|
@pyqtSlot(int, int, int)
|
|
def slot_DBusPortsConnectedCallback(self, connection_id, source_port_id, target_port_id):
|
|
self.canvas_connect_ports(connection_id, source_port_id, target_port_id)
|
|
|
|
@pyqtSlot(int)
|
|
def slot_DBusPortsDisconnectedCallback(self, connection_id):
|
|
self.canvas_disconnect_ports(connection_id)
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusStudioAppearedCallback(self):
|
|
self.studioLoaded()
|
|
if gDBus.ladish_studio.IsStarted():
|
|
self.studioStarted()
|
|
else:
|
|
self.studioStopped()
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusStudioDisappearedCallback(self):
|
|
self.studioUnloaded()
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusQueueExecutionHaltedCallback(self):
|
|
log_path = os.path.join(HOME, ".log", "ladish", "ladish.log")
|
|
if os.path.exists(log_path):
|
|
log_file = open(log_path)
|
|
log_text = logs.fixLogText(log_file.read().split("ERROR: ")[-1].split("\n")[0])
|
|
log_file.close()
|
|
else:
|
|
log_text = None
|
|
|
|
msgbox = QMessageBox(QMessageBox.Critical, self.tr("Execution Halted"),
|
|
self.tr("Something went wrong with ladish so the last action was not sucessful.\n"), QMessageBox.Ok, self)
|
|
|
|
if log_text:
|
|
msgbox.setInformativeText(self.tr("You can check the ladish log file (or click in the 'Show Details' button) to find out what went wrong."))
|
|
msgbox.setDetailedText(log_text)
|
|
else:
|
|
msgbox.setInformativeText(self.tr("You can check the ladish log file to find out what went wrong."))
|
|
|
|
msgbox.show()
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusCleanExitCallback(self):
|
|
pass # TODO
|
|
#self.timer1000.stop()
|
|
#QTimer.singleShot(1000, self.DBusReconnect)
|
|
#QTimer.singleShot(1500, self.timer1000.start)
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusStudioStartedCallback(self):
|
|
self.studioStarted()
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusStudioStoppedCallback(self):
|
|
self.studioStopped()
|
|
|
|
@pyqtSlot(str)
|
|
def slot_DBusStudioRenamedCallback(self, new_name):
|
|
self.ui.treeWidget.topLevelItem(0).setText(0, new_name)
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusStudioCrashedCallback(self):
|
|
QTimer.singleShot(0, self.slot_handleCrash_studio)
|
|
|
|
@pyqtSlot(str, str)
|
|
def slot_DBusRoomAppearedCallback(self, room_path, room_name):
|
|
self.room_add(room_path, room_name)
|
|
|
|
@pyqtSlot(str)
|
|
def slot_DBusRoomDisappearedCallback(self, room_path):
|
|
for i in range(self.ui.treeWidget.topLevelItemCount()):
|
|
item = self.ui.treeWidget.topLevelItem(i)
|
|
|
|
if i == 0:
|
|
continue
|
|
|
|
if item and item.type() == ITEM_TYPE_ROOM and item.properties[iItemPropRoomPath] == room_path:
|
|
for j in range(item.childCount()):
|
|
item.takeChild(j)
|
|
|
|
self.ui.treeWidget.takeTopLevelItem(i)
|
|
break
|
|
|
|
else:
|
|
print("Claudia - room delete failed")
|
|
|
|
@pyqtSlot()
|
|
def slot_DBusRoomChangedCallback(self):
|
|
# Unused in ladish v1.0
|
|
return
|
|
|
|
@pyqtSlot(str, str)
|
|
def slot_DBusProjectPropertiesChanged(self, path, name):
|
|
has_project = bool(name)
|
|
|
|
if has_project:
|
|
item_string = " (%s)" % name
|
|
else:
|
|
item_string = ""
|
|
|
|
self.ui.act_project_save.setEnabled(has_project)
|
|
self.ui.act_project_save_as.setEnabled(has_project)
|
|
self.ui.act_project_unload.setEnabled(has_project)
|
|
self.ui.act_project_properties.setEnabled(has_project)
|
|
self.ui.b_project_save.setEnabled(has_project)
|
|
self.ui.b_project_save_as.setEnabled(has_project)
|
|
self.ui.menu_Application.setEnabled(has_project)
|
|
|
|
if path == "/org/ladish/Studio":
|
|
top_level_item = self.ui.treeWidget.topLevelItem(0)
|
|
room_name = ""
|
|
|
|
else:
|
|
for i in range(self.ui.treeWidget.topLevelItemCount()):
|
|
if i == 0:
|
|
continue
|
|
top_level_item = self.ui.treeWidget.topLevelItem(i)
|
|
if top_level_item and top_level_item.type() == ITEM_TYPE_ROOM and top_level_item.properties[iItemPropRoomPath] == path:
|
|
room_name = top_level_item.properties[iItemPropRoomName]
|
|
break
|
|
else:
|
|
return
|
|
|
|
top_level_item.setText(0, "%s%s" % (room_name, item_string))
|
|
|
|
@pyqtSlot(str, int, str, bool, bool, str)
|
|
def slot_DBusAppAdded2Callback(self, path, number, name, active, terminal, level):
|
|
if path == "/org/ladish/Studio":
|
|
ITEM_TYPE = ITEM_TYPE_STUDIO_APP
|
|
top_level_item = self.ui.treeWidget.topLevelItem(0)
|
|
else:
|
|
ITEM_TYPE = ITEM_TYPE_ROOM_APP
|
|
for i in range(self.ui.treeWidget.topLevelItemCount()):
|
|
if i == 0:
|
|
continue
|
|
top_level_item = self.ui.treeWidget.topLevelItem(i)
|
|
if top_level_item and top_level_item.type() == ITEM_TYPE_ROOM and top_level_item.properties[iItemPropRoomPath] == path:
|
|
break
|
|
else:
|
|
return
|
|
|
|
for i in range(top_level_item.childCount()):
|
|
if top_level_item.child(i).properties[iItemPropNumber] == number:
|
|
# App was added before, probably during reload/init
|
|
return
|
|
|
|
prop_obj = [None, None, None, None, None]
|
|
prop_obj[iItemPropNumber] = number
|
|
prop_obj[iItemPropName] = name
|
|
prop_obj[iItemPropActive] = active
|
|
prop_obj[iItemPropTerminal] = terminal
|
|
prop_obj[iItemPropLevel] = level
|
|
|
|
text = "["
|
|
if level.isdigit():
|
|
text += "L%s" % level
|
|
elif level == "jacksession":
|
|
text += "JS"
|
|
else:
|
|
text += level.upper()
|
|
text += "] "
|
|
if not active:
|
|
text += "(inactive) "
|
|
text += name
|
|
|
|
item = QTreeWidgetItem(ITEM_TYPE)
|
|
item.properties = prop_obj
|
|
item.setText(0, text)
|
|
top_level_item.addChild(item)
|
|
|
|
@pyqtSlot(str, int)
|
|
def slot_DBusAppRemovedCallback(self, path, number):
|
|
if path == "/org/ladish/Studio":
|
|
top_level_item = self.ui.treeWidget.topLevelItem(0)
|
|
else:
|
|
for i in range(self.ui.treeWidget.topLevelItemCount()):
|
|
if i == 0:
|
|
continue
|
|
top_level_item = self.ui.treeWidget.topLevelItem(i)
|
|
if top_level_item and top_level_item.type() == ITEM_TYPE_ROOM and top_level_item.properties[iItemPropRoomPath] == path:
|
|
break
|
|
else:
|
|
return
|
|
|
|
for i in range(top_level_item.childCount()):
|
|
if top_level_item.child(i).properties[iItemPropNumber] == number:
|
|
top_level_item.takeChild(i)
|
|
break
|
|
|
|
@pyqtSlot(str, int, str, bool, bool, str)
|
|
def slot_DBusAppStateChanged2Callback(self, path, number, name, active, terminal, level):
|
|
if path == "/org/ladish/Studio":
|
|
top_level_item = self.ui.treeWidget.topLevelItem(0)
|
|
else:
|
|
for i in range(self.ui.treeWidget.topLevelItemCount()):
|
|
if i == 0:
|
|
continue
|
|
top_level_item = self.ui.treeWidget.topLevelItem(i)
|
|
if top_level_item and top_level_item.type() == ITEM_TYPE_ROOM and top_level_item.properties[iItemPropRoomPath] == path:
|
|
break
|
|
else:
|
|
return
|
|
|
|
prop_obj = [None, None, None, None, None]
|
|
prop_obj[iItemPropNumber] = number
|
|
prop_obj[iItemPropName] = name
|
|
prop_obj[iItemPropActive] = active
|
|
prop_obj[iItemPropTerminal] = terminal
|
|
prop_obj[iItemPropLevel] = level
|
|
|
|
text = "["
|
|
if level.isdigit():
|
|
text += "L%s" % level
|
|
elif level == "jacksession":
|
|
text += "JS"
|
|
else:
|
|
text += level.upper()
|
|
text += "] "
|
|
if not active:
|
|
text += "(inactive) "
|
|
text += name
|
|
|
|
for i in range(top_level_item.childCount()):
|
|
item = top_level_item.child(i)
|
|
if item.properties[iItemPropNumber] == number:
|
|
item.properties = prop_obj
|
|
item.setText(0, text)
|
|
break
|
|
|
|
@pyqtSlot()
|
|
def slot_JackClearXruns(self):
|
|
if gJack.client:
|
|
gDBus.jack.ResetXruns()
|
|
|
|
@pyqtSlot(int)
|
|
def slot_JackBufferSizeCallback(self, bufferSize):
|
|
self.ui_setBufferSize(bufferSize)
|
|
|
|
@pyqtSlot(int)
|
|
def slot_JackSampleRateCallback(self, sampleRate):
|
|
self.ui_setSampleRate(sampleRate)
|
|
|
|
@pyqtSlot()
|
|
def slot_JackShutdownCallback(self):
|
|
self.jackStopped()
|
|
|
|
@pyqtSlot()
|
|
def slot_A2JBridgeStart(self):
|
|
ret = False
|
|
if gDBus.a2j:
|
|
ret = bool(gDBus.a2j.start())
|
|
return ret
|
|
|
|
@pyqtSlot()
|
|
def slot_A2JBridgeStop(self):
|
|
ret = False
|
|
if gDBus.a2j:
|
|
ret = bool(gDBus.a2j.stop())
|
|
return ret
|
|
|
|
@pyqtSlot()
|
|
def slot_A2JBridgeExportHW(self):
|
|
if gDBus.a2j:
|
|
ask = QMessageBox.question(self, self.tr("A2J Hardware Export"), self.tr("Enable Hardware Export on the A2J Bridge?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, QMessageBox.No)
|
|
if ask == QMessageBox.Yes:
|
|
gDBus.a2j.set_hw_export(True)
|
|
elif ask == QMessageBox.No:
|
|
gDBus.a2j.set_hw_export(False)
|
|
|
|
@pyqtSlot()
|
|
def slot_configureClaudia(self):
|
|
# Save groups position now
|
|
if gDBus.patchbay:
|
|
version, groups, conns = gDBus.patchbay.GetGraph(0)
|
|
|
|
for group in groups:
|
|
group_id, group_name, ports = group
|
|
|
|
group_pos_i = patchcanvas.getGroupPos(group_id, patchcanvas.PORT_MODE_OUTPUT)
|
|
group_pos_o = patchcanvas.getGroupPos(group_id, patchcanvas.PORT_MODE_INPUT)
|
|
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, URI_CANVAS_X, str(group_pos_o.x()))
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, URI_CANVAS_Y, str(group_pos_o.y()))
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, URI_CANVAS_X_SPLIT, str(group_pos_i.x()))
|
|
gDBus.ladish_graph.Set(GRAPH_DICT_OBJECT_TYPE_CLIENT, group_id, URI_CANVAS_Y_SPLIT, str(group_pos_i.y()))
|
|
|
|
try:
|
|
ladish_config = gDBus.bus.get_object("org.ladish.conf", "/org/ladish/conf")
|
|
except:
|
|
ladish_config = None
|
|
|
|
if ladish_config:
|
|
try:
|
|
key_notify = bool(ladish_config.get(LADISH_CONF_KEY_DAEMON_NOTIFY)[0] == "true")
|
|
except:
|
|
key_notify = LADISH_CONF_KEY_DAEMON_NOTIFY_DEFAULT
|
|
|
|
try:
|
|
key_shell = str(ladish_config.get(LADISH_CONF_KEY_DAEMON_SHELL)[0])
|
|
except:
|
|
key_shell = LADISH_CONF_KEY_DAEMON_SHELL_DEFAULT
|
|
|
|
try:
|
|
key_terminal = str(ladish_config.get(LADISH_CONF_KEY_DAEMON_TERMINAL)[0])
|
|
except:
|
|
key_terminal = LADISH_CONF_KEY_DAEMON_TERMINAL_DEFAULT
|
|
|
|
try:
|
|
key_studio_autostart = bool(ladish_config.get(LADISH_CONF_KEY_DAEMON_STUDIO_AUTOSTART)[0] == "true")
|
|
except:
|
|
key_studio_autostart = LADISH_CONF_KEY_DAEMON_STUDIO_AUTOSTART_DEFAULT
|
|
|
|
try:
|
|
key_js_save_delay = int(ladish_config.get(LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY)[0])
|
|
except:
|
|
key_js_save_delay = LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY_DEFAULT
|
|
|
|
settings = QSettings()
|
|
settings.setValue(LADISH_CONF_KEY_DAEMON_NOTIFY, key_notify)
|
|
settings.setValue(LADISH_CONF_KEY_DAEMON_SHELL, key_shell)
|
|
settings.setValue(LADISH_CONF_KEY_DAEMON_TERMINAL, key_terminal)
|
|
settings.setValue(LADISH_CONF_KEY_DAEMON_STUDIO_AUTOSTART, key_studio_autostart)
|
|
settings.setValue(LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY, key_js_save_delay)
|
|
del settings
|
|
|
|
dialog = SettingsW(self, "claudia", hasGL)
|
|
|
|
if not ladish_config:
|
|
dialog.ui.lw_page.hideRow(2)
|
|
|
|
if dialog.exec_():
|
|
if ladish_config:
|
|
settings = QSettings()
|
|
ladish_config.set(LADISH_CONF_KEY_DAEMON_NOTIFY, "true" if (settings.value(LADISH_CONF_KEY_DAEMON_NOTIFY, LADISH_CONF_KEY_DAEMON_NOTIFY_DEFAULT, type=bool)) else "false")
|
|
ladish_config.set(LADISH_CONF_KEY_DAEMON_SHELL, settings.value(LADISH_CONF_KEY_DAEMON_SHELL, LADISH_CONF_KEY_DAEMON_SHELL_DEFAULT, type=str))
|
|
ladish_config.set(LADISH_CONF_KEY_DAEMON_TERMINAL, settings.value(LADISH_CONF_KEY_DAEMON_TERMINAL, LADISH_CONF_KEY_DAEMON_TERMINAL_DEFAULT, type=str))
|
|
ladish_config.set(LADISH_CONF_KEY_DAEMON_STUDIO_AUTOSTART, "true" if (settings.value(LADISH_CONF_KEY_DAEMON_STUDIO_AUTOSTART, LADISH_CONF_KEY_DAEMON_STUDIO_AUTOSTART_DEFAULT, type=bool)) else "false")
|
|
ladish_config.set(LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY, str(settings.value(LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY, LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY_DEFAULT, type=int)))
|
|
del settings
|
|
|
|
self.loadSettings(False)
|
|
patchcanvas.clear()
|
|
|
|
pOptions = patchcanvas.options_t()
|
|
pOptions.theme_name = self.fSavedSettings["Canvas/Theme"]
|
|
pOptions.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
|
|
pOptions.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
|
|
pOptions.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
|
|
pOptions.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
|
|
|
|
pFeatures = patchcanvas.features_t()
|
|
pFeatures.group_info = False
|
|
pFeatures.group_rename = True
|
|
pFeatures.port_info = True
|
|
pFeatures.port_rename = True
|
|
pFeatures.handle_group_pos = False
|
|
|
|
patchcanvas.setOptions(pOptions)
|
|
patchcanvas.setFeatures(pFeatures)
|
|
patchcanvas.init("Claudia", self.scene, self.canvasCallback, DEBUG)
|
|
|
|
self.ui.miniCanvasPreview.setViewTheme(patchcanvas.canvas.theme.canvas_bg, patchcanvas.canvas.theme.rubberband_brush, patchcanvas.canvas.theme.rubberband_pen.color())
|
|
|
|
if gDBus.ladish_control.IsStudioLoaded() and gDBus.ladish_studio and gDBus.ladish_studio.IsStarted():
|
|
self.initPorts()
|
|
|
|
@pyqtSlot()
|
|
def slot_aboutClaudia(self):
|
|
QMessageBox.about(self, self.tr("About Claudia"), self.tr("<h3>Claudia</h3>"
|
|
"<br>Version %s"
|
|
"<br>Claudia is a Graphical User Interface to LADISH.<br>"
|
|
"<br>Copyright (C) 2010-2022 falkTX" % VERSION))
|
|
|
|
def saveSettings(self):
|
|
settings = QSettings()
|
|
|
|
settings.setValue("Geometry", self.saveGeometry())
|
|
settings.setValue("SplitterSizes", self.ui.splitter.saveState())
|
|
settings.setValue("ShowToolbar", self.ui.frame_toolbar.isEnabled())
|
|
settings.setValue("ShowStatusbar", self.ui.frame_statusbar.isEnabled())
|
|
settings.setValue("TransportView", self.fCurTransportView)
|
|
settings.setValue("HorizontalScrollBarValue", self.ui.graphicsView.horizontalScrollBar().value())
|
|
settings.setValue("VerticalScrollBarValue", self.ui.graphicsView.verticalScrollBar().value())
|
|
|
|
def loadSettings(self, geometry):
|
|
settings = QSettings()
|
|
|
|
if geometry:
|
|
self.restoreGeometry(settings.value("Geometry", b""))
|
|
|
|
splitterSizes = settings.value("SplitterSizes", "")
|
|
if splitterSizes:
|
|
self.ui.splitter.restoreState(splitterSizes)
|
|
else:
|
|
self.ui.splitter.setSizes((100, 400))
|
|
|
|
showToolbar = settings.value("ShowToolbar", True, type=bool)
|
|
self.ui.act_settings_show_toolbar.setChecked(showToolbar)
|
|
self.ui.frame_toolbar.setVisible(showToolbar)
|
|
|
|
showStatusbar = settings.value("ShowStatusbar", True, type=bool)
|
|
self.ui.act_settings_show_statusbar.setChecked(showStatusbar)
|
|
self.ui.frame_statusbar.setVisible(showStatusbar)
|
|
|
|
self.setTransportView(settings.value("TransportView", TRANSPORT_VIEW_HMS, type=int))
|
|
|
|
self.fSavedSettings = {
|
|
"Main/DefaultProjectFolder": settings.value("Main/DefaultProjectFolder", DEFAULT_PROJECT_FOLDER, type=str),
|
|
"Main/UseSystemTray": settings.value("Main/UseSystemTray", True, type=bool),
|
|
"Main/CloseToTray": settings.value("Main/CloseToTray", False, type=bool),
|
|
"Main/RefreshInterval": settings.value("Main/RefreshInterval", 120, type=int),
|
|
"Canvas/Theme": settings.value("Canvas/Theme", patchcanvas.getDefaultThemeName(), type=str),
|
|
"Canvas/AutoHideGroups": settings.value("Canvas/AutoHideGroups", False, type=bool),
|
|
"Canvas/UseBezierLines": settings.value("Canvas/UseBezierLines", True, type=bool),
|
|
"Canvas/EyeCandy": settings.value("Canvas/EyeCandy", patchcanvas.EYECANDY_SMALL, type=int),
|
|
"Canvas/UseOpenGL": settings.value("Canvas/UseOpenGL", False, type=bool),
|
|
"Canvas/Antialiasing": settings.value("Canvas/Antialiasing", patchcanvas.ANTIALIASING_SMALL, type=int),
|
|
"Canvas/HighQualityAntialiasing": settings.value("Canvas/HighQualityAntialiasing", False, type=bool)
|
|
}
|
|
|
|
self.ui.act_app_add_new.setEnabled(USE_CLAUDIA_ADD_NEW)
|
|
|
|
def resizeEvent(self, event):
|
|
QTimer.singleShot(0, self.slot_miniCanvasCheckSize)
|
|
QMainWindow.resizeEvent(self, event)
|
|
|
|
def timerEvent(self, event):
|
|
if event.timerId() == self.m_timer120:
|
|
if gJack.client:
|
|
self.refreshTransport()
|
|
self.refreshXruns()
|
|
elif event.timerId() == self.m_timer600:
|
|
if gJack.client:
|
|
self.refreshDSPLoad()
|
|
else:
|
|
self.update()
|
|
QMainWindow.timerEvent(self, event)
|
|
|
|
def closeEvent(self, event):
|
|
self.saveSettings()
|
|
if self.systray:
|
|
if self.fSavedSettings["Main/CloseToTray"]:
|
|
if self.systray.handleQtCloseEvent(event):
|
|
patchcanvas.clear()
|
|
return
|
|
self.systray.close()
|
|
patchcanvas.clear()
|
|
QMainWindow.closeEvent(self, event)
|
|
|
|
#--------------- main ------------------
|
|
if __name__ == '__main__':
|
|
# App initialization
|
|
app = QApplication(sys.argv)
|
|
app.setApplicationName("Claudia")
|
|
app.setApplicationVersion(VERSION)
|
|
app.setOrganizationName("LADI")
|
|
app.setWindowIcon(QIcon(":/scalable/claudia.svg"))
|
|
setup_i18n()
|
|
|
|
if not haveDBus:
|
|
QMessageBox.critical(None, app.translate("ClaudiaMainW", "Error"), app.translate("ClaudiaMainW",
|
|
"DBus is not available, Claudia cannot start without it!"))
|
|
sys.exit(1)
|
|
|
|
gDBus.loop = DBusMainLoop(set_as_default=True)
|
|
gDBus.bus = dbus.SessionBus(mainloop=gDBus.loop)
|
|
gDBus.jack = gDBus.bus.get_object("org.jackaudio.service", "/org/jackaudio/Controller")
|
|
gDBus.ladish_control = gDBus.bus.get_object("org.ladish", "/org/ladish/Control")
|
|
|
|
try:
|
|
gDBus.ladish_app_daemon = gDBus.bus.get_object("org.ladish.appdb", "/")
|
|
except:
|
|
gDBus.ladish_app_daemon = None
|
|
|
|
try:
|
|
gDBus.a2j = dbus.Interface(gDBus.bus.get_object("org.gna.home.a2jmidid", "/"), "org.gna.home.a2jmidid.control")
|
|
except:
|
|
gDBus.a2j = None
|
|
|
|
jacksettings.initBus(gDBus.bus)
|
|
|
|
# Show GUI
|
|
gui = ClaudiaMainW()
|
|
|
|
if gui.systray and "--minimized" in app.arguments():
|
|
gui.hide()
|
|
gui.systray.setActionText("show", gui.tr("Restore"))
|
|
else:
|
|
gui.show()
|
|
|
|
# Set-up custom signal handling
|
|
setUpSignals(gui)
|
|
|
|
# App-Loop
|
|
if gui.systray:
|
|
ret = gui.systray.exec_(app)
|
|
else:
|
|
ret = app.exec_()
|
|
|
|
# Close Jack
|
|
if gJack.client:
|
|
jacklib.deactivate(gJack.client)
|
|
jacklib.client_close(gJack.client)
|
|
|
|
# Exit properly
|
|
sys.exit(ret)
|