1329 lines
54 KiB
Python
Executable File
1329 lines
54 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# PatchCanvas test application
|
|
# 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)
|
|
|
|
if True:
|
|
from PyQt5.QtCore import pyqtSlot, QSettings
|
|
from PyQt5.QtWidgets import QApplication, QDialog, QDialogButtonBox, QTableWidgetItem
|
|
from PyQt5.QtXml import QDomDocument
|
|
else:
|
|
from PyQt4.QtCore import pyqtSlot, QSettings
|
|
from PyQt4.QtGui import QApplication, QDialog, QDialogButtonBox, QTableWidgetItem
|
|
from PyQt4.QtXml import QDomDocument
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Imports (Custom Stuff)
|
|
|
|
import ui_catarina
|
|
import ui_catarina_addgroup
|
|
import ui_catarina_removegroup
|
|
import ui_catarina_renamegroup
|
|
import ui_catarina_addport
|
|
import ui_catarina_removeport
|
|
import ui_catarina_renameport
|
|
import ui_catarina_connectports
|
|
import ui_catarina_disconnectports
|
|
from shared_canvasjack import *
|
|
from shared_settings import *
|
|
from shared_i18n import *
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Try Import OpenGL
|
|
|
|
try:
|
|
from PyQt5.QtOpenGL import QGLWidget
|
|
hasGL = True
|
|
except:
|
|
hasGL = False
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Static Variables
|
|
|
|
iGroupId = 0
|
|
iGroupName = 1
|
|
iGroupSplit = 2
|
|
iGroupIcon = 3
|
|
|
|
iGroupPosId = 0
|
|
iGroupPosX_o = 1
|
|
iGroupPosY_o = 2
|
|
iGroupPosX_i = 3
|
|
iGroupPosY_i = 4
|
|
|
|
iPortGroup = 0
|
|
iPortId = 1
|
|
iPortName = 2
|
|
iPortMode = 3
|
|
iPortType = 4
|
|
|
|
iConnId = 0
|
|
iConnOutput = 1
|
|
iConnInput = 2
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Add Group Dialog
|
|
|
|
class CatarinaAddGroupW(QDialog, ui_catarina_addgroup.Ui_CatarinaAddGroupW):
|
|
def __init__(self, parent, group_list):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
self.m_group_list_names = []
|
|
|
|
for group in group_list:
|
|
self.m_group_list_names.append(group[iGroupName])
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.le_group_name.textChanged.connect(self.slot_checkText)
|
|
|
|
self.ret_group_name = ""
|
|
self.ret_group_split = False
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText(self, text):
|
|
check = bool(text and text not in self.m_group_list_names)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
self.ret_group_name = self.le_group_name.text()
|
|
self.ret_group_split = self.cb_split.isChecked()
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Remove Group Dialog
|
|
|
|
class CatarinaRemoveGroupW(QDialog, ui_catarina_removegroup.Ui_CatarinaRemoveGroupW):
|
|
def __init__(self, parent, group_list):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
index = 0
|
|
for group in group_list:
|
|
twi_group_id = QTableWidgetItem(str(group[iGroupId]))
|
|
twi_group_name = QTableWidgetItem(group[iGroupName])
|
|
twi_group_split = QTableWidgetItem("Yes" if (group[iGroupSplit]) else "No")
|
|
self.tw_group_list.insertRow(index)
|
|
self.tw_group_list.setItem(index, 0, twi_group_id)
|
|
self.tw_group_list.setItem(index, 1, twi_group_name)
|
|
self.tw_group_list.setItem(index, 2, twi_group_split)
|
|
index += 1
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.tw_group_list.cellDoubleClicked.connect(self.accept)
|
|
self.tw_group_list.currentCellChanged.connect(self.slot_checkCell)
|
|
|
|
self.ret_group_id = -1
|
|
|
|
@pyqtSlot(int)
|
|
def slot_checkCell(self, row):
|
|
check = bool(row >= 0)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.tw_group_list.rowCount() >= 0:
|
|
self.ret_group_id = int(self.tw_group_list.item(self.tw_group_list.currentRow(), 0).text())
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Rename Group Dialog
|
|
|
|
class CatarinaRenameGroupW(QDialog, ui_catarina_renamegroup.Ui_CatarinaRenameGroupW):
|
|
def __init__(self, parent, group_list):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
self.m_group_list_names = []
|
|
|
|
for group in group_list:
|
|
self.cb_group_to_rename.addItem("%i - %s" % (group[iGroupId], group[iGroupName]))
|
|
self.m_group_list_names.append(group[iGroupName])
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.cb_group_to_rename.currentIndexChanged[int].connect(self.slot_checkItem)
|
|
self.le_new_group_name.textChanged.connect(self.slot_checkText)
|
|
|
|
self.ret_group_id = -1
|
|
self.ret_new_group_name = ""
|
|
|
|
@pyqtSlot(int)
|
|
def slot_checkItem(self, ignored):
|
|
self.slot_checkText(self.le_new_group_name.text())
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText(self, text):
|
|
if self.cb_group_to_rename.count() > 0:
|
|
group_name = self.cb_group_to_rename.currentText().split(" - ", 1)[1]
|
|
check = bool(text and text != group_name and text not in self.m_group_list_names)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
self.ret_group_id = int(self.cb_group_to_rename.currentText().split(" - ", 1)[0])
|
|
self.ret_new_group_name = self.le_new_group_name.text()
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Add Port Dialog
|
|
|
|
class CatarinaAddPortW(QDialog, ui_catarina_addport.Ui_CatarinaAddPortW):
|
|
def __init__(self, parent, group_list, port_id):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.sb_port_id.setValue(port_id)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
for group in group_list:
|
|
self.cb_group.addItem("%i - %s" % (group[iGroupId], group[iGroupName]))
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.le_port_name.textChanged.connect(self.slot_checkText)
|
|
|
|
self.ret_group_id = -1
|
|
self.ret_port_name = ""
|
|
self.ret_port_mode = patchcanvas.PORT_MODE_NULL
|
|
self.ret_port_type = patchcanvas.PORT_TYPE_NULL
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText(self, text):
|
|
check = bool(text)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.cb_group.count() > 0:
|
|
self.ret_group_id = int(self.cb_group.currentText().split(" ", 1)[0])
|
|
self.ret_port_name = self.le_port_name.text()
|
|
self.ret_port_mode = patchcanvas.PORT_MODE_INPUT if self.rb_flags_input.isChecked() else patchcanvas.PORT_MODE_OUTPUT
|
|
self.ret_port_type = self.cb_port_type.currentIndex() + 1 # 1, 2, 3 or 4 for patchcanvas types
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Remove Port Dialog
|
|
|
|
class CatarinaRemovePortW(QDialog, ui_catarina_removeport.Ui_CatarinaRemovePortW):
|
|
def __init__(self, parent, group_list, port_list):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.tw_port_list.setColumnWidth(0, 25)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
self.m_group_list = group_list
|
|
self.m_port_list = port_list
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.tw_port_list.cellDoubleClicked.connect(self.accept)
|
|
self.tw_port_list.currentCellChanged.connect(self.slot_checkCell)
|
|
self.rb_input.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_output.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_audio_jack.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_midi_jack.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_midi_a2j.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_midi_alsa.clicked.connect(self.slot_reAddPorts)
|
|
|
|
self.ret_port_id = -1
|
|
self.reAddPorts()
|
|
|
|
def reAddPorts(self):
|
|
self.tw_port_list.clearContents()
|
|
for x in range(self.tw_port_list.rowCount()):
|
|
self.tw_port_list.removeRow(0)
|
|
|
|
port_mode = patchcanvas.PORT_MODE_INPUT if (self.rb_input.isChecked()) else patchcanvas.PORT_MODE_OUTPUT
|
|
|
|
if self.rb_audio_jack.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_AUDIO_JACK
|
|
elif self.rb_midi_jack.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_JACK
|
|
elif self.rb_midi_a2j.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_A2J
|
|
elif self.rb_midi_alsa.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_ALSA
|
|
else:
|
|
print("CatarinaRemovePortW::reAddPorts() - Invalid port type")
|
|
return
|
|
|
|
index = 0
|
|
for port in self.m_port_list:
|
|
if port[iPortMode] == port_mode and port[iPortType] == port_type:
|
|
port_name = port[iPortName]
|
|
group_name = self.findPortGroupName(port[iPortGroup])
|
|
tw_port_id = QTableWidgetItem(str(port[iPortId]))
|
|
tw_port_name = QTableWidgetItem("%s:%s" % (group_name, port_name))
|
|
self.tw_port_list.insertRow(index)
|
|
self.tw_port_list.setItem(index, 0, tw_port_id)
|
|
self.tw_port_list.setItem(index, 1, tw_port_name)
|
|
index += 1
|
|
|
|
def findPortGroupName(self, group_id):
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
return group[iGroupName]
|
|
return ""
|
|
|
|
@pyqtSlot()
|
|
def slot_reAddPorts(self):
|
|
self.reAddPorts()
|
|
|
|
@pyqtSlot(int)
|
|
def slot_checkCell(self, row):
|
|
check = bool(row >= 0)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.tw_port_list.rowCount() > 0:
|
|
self.ret_port_id = int(self.tw_port_list.item(self.tw_port_list.currentRow(), 0).text())
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Rename Port Dialog
|
|
|
|
class CatarinaRenamePortW(QDialog, ui_catarina_renameport.Ui_CatarinaRenamePortW):
|
|
def __init__(self, parent, group_list, port_list):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.tw_port_list.setColumnWidth(0, 25)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
self.m_group_list = group_list
|
|
self.m_port_list = port_list
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.tw_port_list.currentCellChanged.connect(self.slot_checkCell)
|
|
self.le_new_name.textChanged.connect(self.slot_checkText)
|
|
|
|
self.rb_input.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_output.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_audio_jack.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_midi_jack.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_midi_a2j.clicked.connect(self.slot_reAddPorts)
|
|
self.rb_midi_alsa.clicked.connect(self.slot_reAddPorts)
|
|
|
|
self.ret_port_id = -1
|
|
self.ret_new_port_name = ""
|
|
self.reAddPorts()
|
|
|
|
def reAddPorts(self):
|
|
self.tw_port_list.clearContents()
|
|
for x in range(self.tw_port_list.rowCount()):
|
|
self.tw_port_list.removeRow(0)
|
|
|
|
port_mode = patchcanvas.PORT_MODE_INPUT if (self.rb_input.isChecked()) else patchcanvas.PORT_MODE_OUTPUT
|
|
|
|
if self.rb_audio_jack.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_AUDIO_JACK
|
|
elif self.rb_midi_jack.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_JACK
|
|
elif self.rb_midi_a2j.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_A2J
|
|
elif self.rb_midi_alsa.isChecked():
|
|
port_type = patchcanvas.PORT_TYPE_MIDI_ALSA
|
|
else:
|
|
print("CatarinaRenamePortW::reAddPorts() - Invalid port type")
|
|
return
|
|
|
|
index = 0
|
|
for port in self.m_port_list:
|
|
if port[iPortMode] == port_mode and port[iPortType] == port_type:
|
|
port_name = port[iPortName]
|
|
group_name = self.findPortGroupName(port[iPortGroup])
|
|
tw_port_id = QTableWidgetItem(str(port[iPortId]))
|
|
tw_port_name = QTableWidgetItem("%s:%s" % (group_name, port_name))
|
|
self.tw_port_list.insertRow(index)
|
|
self.tw_port_list.setItem(index, 0, tw_port_id)
|
|
self.tw_port_list.setItem(index, 1, tw_port_name)
|
|
index += 1
|
|
|
|
self.tw_port_list.setCurrentCell(0, 0)
|
|
|
|
def findPortGroupName(self, group_id):
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
return group[iGroupName]
|
|
return ""
|
|
|
|
@pyqtSlot()
|
|
def slot_reAddPorts(self):
|
|
self.reAddPorts()
|
|
|
|
@pyqtSlot()
|
|
def slot_checkCell(self):
|
|
self.slot_checkText(self.le_new_name.text())
|
|
|
|
@pyqtSlot(str)
|
|
def slot_checkText(self, text):
|
|
check = bool(text and self.tw_port_list.currentRow() >= 0)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.tw_port_list.rowCount() > 0:
|
|
self.ret_port_id = int(self.tw_port_list.item(self.tw_port_list.currentRow(), 0).text())
|
|
self.ret_new_port_name = self.le_new_name.text()
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Connect Ports Dialog
|
|
|
|
class CatarinaConnectPortsW(QDialog, ui_catarina_connectports.Ui_CatarinaConnectPortsW):
|
|
def __init__(self, parent, group_list, port_list):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
self.m_group_list = group_list
|
|
self.m_port_list = port_list
|
|
self.m_ports_audio_jack = []
|
|
self.m_ports_midi_jack = []
|
|
self.m_ports_midi_a2j = []
|
|
self.m_ports_midi_alsa = []
|
|
|
|
for port in self.m_port_list:
|
|
if port[iPortType] == patchcanvas.PORT_TYPE_AUDIO_JACK:
|
|
self.m_ports_audio_jack.append(port)
|
|
elif port[iPortType] == patchcanvas.PORT_TYPE_MIDI_JACK:
|
|
self.m_ports_midi_jack.append(port)
|
|
elif port[iPortType] == patchcanvas.PORT_TYPE_MIDI_A2J:
|
|
self.m_ports_midi_a2j.append(port)
|
|
elif port[iPortType] == patchcanvas.PORT_TYPE_MIDI_ALSA:
|
|
self.m_ports_midi_alsa.append(port)
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.rb_audio_jack.clicked.connect(self.slot_portTypeChanged)
|
|
self.rb_midi_jack.clicked.connect(self.slot_portTypeChanged)
|
|
self.rb_midi_a2j.clicked.connect(self.slot_portTypeChanged)
|
|
self.rb_midi_alsa.clicked.connect(self.slot_portTypeChanged)
|
|
self.lw_outputs.currentRowChanged.connect(self.slot_checkOutSelection)
|
|
self.lw_inputs.currentRowChanged.connect(self.slot_checkInSelection)
|
|
|
|
self.ret_port_out_id = -1
|
|
self.ret_port_in_id = -1
|
|
self.slot_portTypeChanged()
|
|
|
|
def showPorts(self, ports):
|
|
self.lw_outputs.clear()
|
|
self.lw_inputs.clear()
|
|
|
|
for port in ports:
|
|
if port[iPortMode] == patchcanvas.PORT_MODE_INPUT:
|
|
self.lw_inputs.addItem("%i - %s:%s" % (port[iPortId], self.findPortGroupName(port[iPortGroup]), port[iPortName]))
|
|
elif port[iPortMode] == patchcanvas.PORT_MODE_OUTPUT:
|
|
self.lw_outputs.addItem("%i - %s:%s" % (port[iPortId], self.findPortGroupName(port[iPortGroup]), port[iPortName]))
|
|
|
|
def findPortGroupName(self, group_id):
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
return group[iGroupName]
|
|
return ""
|
|
|
|
def checkSelection(self, out_row, in_row):
|
|
check = bool(out_row >= 0 and in_row >= 0)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(check)
|
|
|
|
@pyqtSlot()
|
|
def slot_portTypeChanged(self):
|
|
if self.rb_audio_jack.isChecked():
|
|
ports = self.m_ports_audio_jack
|
|
elif self.rb_midi_jack.isChecked():
|
|
ports = self.m_ports_midi_jack
|
|
elif self.rb_midi_a2j.isChecked():
|
|
ports = self.m_ports_midi_a2j
|
|
elif self.rb_midi_alsa.isChecked():
|
|
ports = self.m_ports_midi_alsa
|
|
else:
|
|
print("CatarinaConnectPortstW::portTypeChanged() - Invalid port type")
|
|
return
|
|
|
|
self.showPorts(ports)
|
|
|
|
@pyqtSlot(int)
|
|
def slot_checkOutSelection(self, row):
|
|
self.checkSelection(row, self.lw_inputs.currentRow())
|
|
|
|
@pyqtSlot(int)
|
|
def slot_checkInSelection(self, row):
|
|
self.checkSelection(self.lw_outputs.currentRow(), row)
|
|
|
|
@pyqtSlot()
|
|
def slot_setReturn(self):
|
|
if self.lw_outputs.currentRow() >= 0 and self.lw_inputs.currentRow() >= 0:
|
|
self.ret_port_out_id = int(self.lw_outputs.currentItem().text().split(" - ", 1)[0])
|
|
self.ret_port_in_id = int(self.lw_inputs.currentItem().text().split(" - ", 1)[0])
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Disconnect Ports Dialog
|
|
|
|
class CatarinaDisconnectPortsW(QDialog, ui_catarina_disconnectports.Ui_CatarinaDisconnectPortsW):
|
|
def __init__(self, parent, group_list, port_list, connection_list):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
|
|
self.tw_connections.setColumnWidth(0, 225)
|
|
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
|
|
|
|
self.m_group_list = group_list
|
|
self.m_port_list = port_list
|
|
self.m_connection_list = connection_list
|
|
|
|
self.accepted.connect(self.slot_setReturn)
|
|
self.tw_connections.cellDoubleClicked.connect(self.accept)
|
|
self.tw_connections.currentCellChanged.connect(self.slot_checkSelection)
|
|
self.rb_audio_jack.clicked.connect(self.slot_portTypeChanged)
|
|
self.rb_midi_jack.clicked.connect(self.slot_portTypeChanged)
|
|
self.rb_midi_a2j.clicked.connect(self.slot_portTypeChanged)
|
|
self.rb_midi_alsa.clicked.connect(self.slot_portTypeChanged)
|
|
|
|
self.ret_port_out_id = -1
|
|
self.ret_port_in_id = -1
|
|
self.slot_portTypeChanged()
|
|
|
|
def showPorts(self, ptype):
|
|
self.tw_connections.clearContents()
|
|
for x in range(self.tw_connections.rowCount()):
|
|
self.tw_connections.removeRow(0)
|
|
|
|
index = 0
|
|
for connection in self.m_connection_list:
|
|
if self.findPortType(connection[iConnOutput]) == ptype:
|
|
port_out_id = connection[iConnOutput]
|
|
port_out_name = self.findPortName(port_out_id)
|
|
|
|
port_in_id = connection[iConnInput]
|
|
port_in_name = self.findPortName(port_in_id)
|
|
|
|
tw_port_out = QTableWidgetItem("%i - %s" % (port_out_id, port_out_name))
|
|
tw_port_in = QTableWidgetItem("%i - %s" % (port_in_id, port_in_name))
|
|
|
|
self.tw_connections.insertRow(index)
|
|
self.tw_connections.setItem(index, 0, tw_port_out)
|
|
self.tw_connections.setItem(index, 1, tw_port_in)
|
|
index += 1
|
|
|
|
def findPortName(self, port_id):
|
|
for port in self.m_port_list:
|
|
if port[iPortId] == port_id:
|
|
return "%s:%s" % (self.findPortGroupName(port[iPortGroup]), port[iPortName])
|
|
return ""
|
|
|
|
def findPortType(self, port_id):
|
|
for port in self.m_port_list:
|
|
if port[iPortId] == port_id:
|
|
return port[iPortType]
|
|
return patchcanvas.PORT_TYPE_NULL
|
|
|
|
def findPortGroupName(self, group_id):
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
return group[iGroupName]
|
|
return ""
|
|
|
|
@pyqtSlot()
|
|
def slot_portTypeChanged(self):
|
|
if self.rb_audio_jack.isChecked():
|
|
ptype = patchcanvas.PORT_TYPE_AUDIO_JACK
|
|
elif self.rb_midi_jack.isChecked():
|
|
ptype = patchcanvas.PORT_TYPE_MIDI_JACK
|
|
elif self.rb_midi_a2j.isChecked():
|
|
ptype = patchcanvas.PORT_TYPE_MIDI_A2J
|
|
elif self.rb_midi_alsa.isChecked():
|
|
ptype = patchcanvas.PORT_TYPE_MIDI_ALSA
|
|
else:
|
|
print("CatarinaDisconnectPortstW::portTypeChanged() - Invalid port type")
|
|
return
|
|
|
|
self.showPorts(ptype)
|
|
|
|
@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.tw_connections.currentRow() >= 0:
|
|
self.ret_port_out_id = int(self.tw_connections.item(self.tw_connections.currentRow(), 0).text().split(" - ", 1)[0])
|
|
self.ret_port_in_id = int(self.tw_connections.item(self.tw_connections.currentRow(), 1).text().split(" - ", 1)[0])
|
|
|
|
def done(self, r):
|
|
QDialog.done(self, r)
|
|
self.close()
|
|
|
|
# ------------------------------------------------------------------------------------------------------------
|
|
# Main Window
|
|
|
|
class CatarinaMainW(AbstractCanvasJackClass):
|
|
def __init__(self, parent=None):
|
|
AbstractCanvasJackClass.__init__(self, "Catarina", ui_catarina.Ui_CatarinaMainW, parent)
|
|
|
|
self.loadSettings(True)
|
|
|
|
# -------------------------------------------------------------
|
|
# Set-up GUI
|
|
|
|
setIcons(self, ("canvas",))
|
|
|
|
self.ui.act_project_new.setIcon(getIcon("document-new"))
|
|
self.ui.act_project_open.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.b_project_new.setIcon(getIcon("document-new"))
|
|
self.ui.b_project_open.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_patchbay_add_group.setIcon(getIcon("list-add"))
|
|
self.ui.act_patchbay_remove_group.setIcon(getIcon("edit-delete"))
|
|
self.ui.act_patchbay_rename_group.setIcon(getIcon("edit-rename"))
|
|
self.ui.act_patchbay_add_port.setIcon(getIcon("list-add"))
|
|
self.ui.act_patchbay_remove_port.setIcon(getIcon("list-remove"))
|
|
self.ui.act_patchbay_rename_port.setIcon(getIcon("edit-rename"))
|
|
self.ui.act_patchbay_connect_ports.setIcon(getIcon("network-connect"))
|
|
self.ui.act_patchbay_disconnect_ports.setIcon(getIcon("network-disconnect"))
|
|
self.ui.b_group_add.setIcon(getIcon("list-add"))
|
|
self.ui.b_group_remove.setIcon(getIcon("edit-delete"))
|
|
self.ui.b_group_rename.setIcon(getIcon("edit-rename"))
|
|
self.ui.b_port_add.setIcon(getIcon("list-add"))
|
|
self.ui.b_port_remove.setIcon(getIcon("list-remove"))
|
|
self.ui.b_port_rename.setIcon(getIcon("edit-rename"))
|
|
self.ui.b_ports_connect.setIcon(getIcon("network-connect"))
|
|
self.ui.b_ports_disconnect.setIcon(getIcon("network-disconnect"))
|
|
|
|
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))
|
|
self.ui.graphicsView.setRenderHint(QPainter.TextAntialiasing, self.fSavedSettings["Canvas/TextAntialiasing"])
|
|
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"])
|
|
|
|
p_options = patchcanvas.options_t()
|
|
p_options.theme_name = self.fSavedSettings["Canvas/Theme"]
|
|
p_options.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
|
|
p_options.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
|
|
p_options.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
|
|
p_options.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
|
|
|
|
p_features = patchcanvas.features_t()
|
|
p_features.group_info = False
|
|
p_features.group_rename = True
|
|
p_features.port_info = True
|
|
p_features.port_rename = True
|
|
p_features.handle_group_pos = True
|
|
|
|
patchcanvas.setOptions(p_options)
|
|
patchcanvas.setFeatures(p_features)
|
|
patchcanvas.init("Catarina", self.scene, self.canvasCallback, DEBUG)
|
|
|
|
self.ui.act_project_new.triggered.connect(self.slot_projectNew)
|
|
self.ui.act_project_open.triggered.connect(self.slot_projectOpen)
|
|
self.ui.act_project_save.triggered.connect(self.slot_projectSave)
|
|
self.ui.act_project_save_as.triggered.connect(self.slot_projectSaveAs)
|
|
self.ui.b_project_new.clicked.connect(self.slot_projectNew)
|
|
self.ui.b_project_open.clicked.connect(self.slot_projectOpen)
|
|
self.ui.b_project_save.clicked.connect(self.slot_projectSave)
|
|
self.ui.b_project_save_as.clicked.connect(self.slot_projectSaveAs)
|
|
self.ui.act_patchbay_add_group.triggered.connect(self.slot_groupAdd)
|
|
self.ui.act_patchbay_remove_group.triggered.connect(self.slot_groupRemove)
|
|
self.ui.act_patchbay_rename_group.triggered.connect(self.slot_groupRename)
|
|
self.ui.act_patchbay_add_port.triggered.connect(self.slot_portAdd)
|
|
self.ui.act_patchbay_remove_port.triggered.connect(self.slot_portRemove)
|
|
self.ui.act_patchbay_rename_port.triggered.connect(self.slot_portRename)
|
|
self.ui.act_patchbay_connect_ports.triggered.connect(self.slot_connectPorts)
|
|
self.ui.act_patchbay_disconnect_ports.triggered.connect(self.slot_disconnectPorts)
|
|
self.ui.b_group_add.clicked.connect(self.slot_groupAdd)
|
|
self.ui.b_group_remove.clicked.connect(self.slot_groupRemove)
|
|
self.ui.b_group_rename.clicked.connect(self.slot_groupRename)
|
|
self.ui.b_port_add.clicked.connect(self.slot_portAdd)
|
|
self.ui.b_port_remove.clicked.connect(self.slot_portRemove)
|
|
self.ui.b_port_rename.clicked.connect(self.slot_portRename)
|
|
self.ui.b_ports_connect.clicked.connect(self.slot_connectPorts)
|
|
self.ui.b_ports_disconnect.clicked.connect(self.slot_disconnectPorts)
|
|
|
|
self.setCanvasConnections()
|
|
|
|
self.ui.act_settings_configure.triggered.connect(self.slot_configureCatarina)
|
|
|
|
self.ui.act_help_about.triggered.connect(self.slot_aboutCatarina)
|
|
self.ui.act_help_about_qt.triggered.connect(app.aboutQt)
|
|
|
|
self.SIGUSR1.connect(self.slot_projectSave)
|
|
|
|
# Dummy timer to keep events active
|
|
self.fUpdateTimer = self.startTimer(1000)
|
|
|
|
# Start Empty Project
|
|
self.slot_projectNew()
|
|
|
|
def canvasCallback(self, action, value1, value2, value_str):
|
|
if action == patchcanvas.ACTION_GROUP_INFO:
|
|
pass
|
|
|
|
elif action == patchcanvas.ACTION_GROUP_RENAME:
|
|
group_id = value1
|
|
new_group_name = value_str
|
|
|
|
for group in self.m_group_list:
|
|
if group[iGroupName] == new_group_name:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("There is already a group with this name"))
|
|
return
|
|
|
|
patchcanvas.renameGroup(group_id, new_group_name)
|
|
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
group[iGroupName] = new_group_name
|
|
break
|
|
|
|
elif action == patchcanvas.ACTION_GROUP_SPLIT:
|
|
group_id = value1
|
|
patchcanvas.splitGroup(group_id)
|
|
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
group[iGroupSplit] = True
|
|
break
|
|
|
|
elif action == patchcanvas.ACTION_GROUP_JOIN:
|
|
group_id = value1
|
|
patchcanvas.joinGroup(group_id)
|
|
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
group[iGroupSplit] = False
|
|
break
|
|
|
|
elif action == patchcanvas.ACTION_PORT_INFO:
|
|
port_id = value1
|
|
|
|
group_id = 0
|
|
group_name = ""
|
|
port_name = ""
|
|
port_mode = patchcanvas.PORT_MODE_NULL
|
|
port_type = patchcanvas.PORT_TYPE_NULL
|
|
|
|
for port in self.m_port_list:
|
|
if port[iPortId] == port_id:
|
|
group_id = port[iPortGroup]
|
|
port_name = port[iPortName]
|
|
port_mode = port[iPortMode]
|
|
port_type = port[iPortType]
|
|
break
|
|
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
group_name = group[iGroupName]
|
|
break
|
|
|
|
if port_mode == patchcanvas.PORT_MODE_INPUT:
|
|
mode_text = self.tr("Input")
|
|
elif port_mode == patchcanvas.PORT_MODE_OUTPUT:
|
|
mode_text = self.tr("Output")
|
|
else:
|
|
mode_text = self.tr("Unknown")
|
|
|
|
if port_type == patchcanvas.PORT_TYPE_AUDIO_JACK:
|
|
type_text = self.tr("JACK Audio")
|
|
elif port_type == patchcanvas.PORT_TYPE_MIDI_JACK:
|
|
type_text = self.tr("JACK MIDI")
|
|
elif port_type == patchcanvas.PORT_TYPE_MIDI_A2J:
|
|
type_text = self.tr("A2J MIDI")
|
|
elif port_type == patchcanvas.PORT_TYPE_MIDI_ALSA:
|
|
type_text = self.tr("ALSA MIDI")
|
|
else:
|
|
type_text = self.tr("Unknown")
|
|
|
|
port_full_name = group_name + ":" + port_name
|
|
|
|
info = self.tr(""
|
|
"<table>"
|
|
"<tr><td align='right'><b>Group Name:</b></td><td> %1</td></tr>"
|
|
"<tr><td align='right'><b>Group ID:</b></td><td> %2</td></tr>"
|
|
"<tr><td align='right'><b>Port Name:</b></td><td> %3</td></tr>"
|
|
"<tr><td align='right'><b>Port ID:</b></td><td> %4</i></td></tr>"
|
|
"<tr><td align='right'><b>Full Port Name:</b></td><td> %5</td></tr>"
|
|
"<tr><td colspan='2'> </td></tr>"
|
|
"<tr><td align='right'><b>Port Mode:</b></td><td> %6</td></tr>"
|
|
"<tr><td align='right'><b>Port Type:</b></td><td> %7</td></tr>"
|
|
"</table>"
|
|
).arg(group_name).arg(group_id).arg(port_name).arg(port_id).arg(port_full_name).arg(mode_text).arg(type_text)
|
|
|
|
QMessageBox.information(self, self.tr("Port Information"), info)
|
|
|
|
elif action == patchcanvas.ACTION_PORT_RENAME:
|
|
port_id = value1
|
|
new_port_name = value_str
|
|
patchcanvas.renamePort(port_id, new_port_name)
|
|
|
|
for port in self.m_port_list:
|
|
if port[iPortId] == port_id:
|
|
port[iPortName] = new_port_name
|
|
break
|
|
|
|
elif action == patchcanvas.ACTION_PORTS_CONNECT:
|
|
connection_id = self.m_last_connection_id
|
|
port_out_id = value1
|
|
port_in_id = value2
|
|
patchcanvas.connectPorts(connection_id, port_out_id, port_in_id)
|
|
|
|
conn_obj = [None, None, None]
|
|
conn_obj[iConnId] = connection_id
|
|
conn_obj[iConnOutput] = port_out_id
|
|
conn_obj[iConnInput] = port_in_id
|
|
|
|
self.m_connection_list.append(conn_obj)
|
|
self.m_last_connection_id += 1
|
|
|
|
elif action == patchcanvas.ACTION_PORTS_DISCONNECT:
|
|
connection_id = value1
|
|
patchcanvas.disconnectPorts(connection_id)
|
|
|
|
for connection in self.m_connection_list:
|
|
if connection[iConnId] == connection_id:
|
|
self.m_connection_list.remove(connection)
|
|
break
|
|
|
|
def initPorts(self):
|
|
for group in self.m_group_list:
|
|
patchcanvas.addGroup(group[iGroupId], group[iGroupName], patchcanvas.SPLIT_YES if (group[iGroupSplit]) else patchcanvas.SPLIT_NO, group[iGroupIcon])
|
|
|
|
for group_pos in self.m_group_list_pos:
|
|
patchcanvas.setGroupPosFull(group_pos[iGroupPosId], group_pos[iGroupPosX_o], group_pos[iGroupPosY_o], group_pos[iGroupPosX_i], group_pos[iGroupPosY_i])
|
|
|
|
for port in self.m_port_list:
|
|
patchcanvas.addPort(port[iPortGroup], port[iPortId], port[iPortName], port[iPortMode], port[iPortType])
|
|
|
|
for connection in self.m_connection_list:
|
|
patchcanvas.connectPorts(connection[iConnId], connection[iConnOutput], connection[iConnInput])
|
|
|
|
self.m_group_list_pos = []
|
|
patchcanvas.updateZValues()
|
|
|
|
def saveFile(self, path):
|
|
content = ("<?xml version='1.0' encoding='UTF-8'?>\n"
|
|
"<!DOCTYPE CATARINA>\n"
|
|
"<CATARINA VERSION='%s'>\n" % VERSION)
|
|
|
|
content += " <Groups>\n"
|
|
for i in range(len(self.m_group_list)):
|
|
group = self.m_group_list[i]
|
|
group_id = group[iGroupId]
|
|
group_name = group[iGroupName]
|
|
group_split = group[iGroupSplit]
|
|
group_icon = group[iGroupIcon]
|
|
group_pos_i = patchcanvas.getGroupPos(group_id, patchcanvas.PORT_MODE_INPUT)
|
|
group_pos_o = patchcanvas.getGroupPos(group_id, patchcanvas.PORT_MODE_OUTPUT)
|
|
content += " <g%i> <name>%s</name> <data>%i:%i:%i:%f:%f:%f:%f</data> </g%i>\n" % (i, group_name, group_id, group_split, group_icon, group_pos_o.x(), group_pos_o.y(), group_pos_i.x(), group_pos_i.y(), i)
|
|
content += " </Groups>\n"
|
|
|
|
content += " <Ports>\n"
|
|
for i in range(len(self.m_port_list)):
|
|
port = self.m_port_list[i]
|
|
content += " <p%i> <name>%s</name> <data>%i:%i:%i:%i</data> </p%i>\n" % (i, port[iPortName], port[iPortGroup], port[iPortId], port[iPortMode], port[iPortType], i)
|
|
content += " </Ports>\n"
|
|
|
|
content += " <Connections>\n"
|
|
for i in range(len(self.m_connection_list)):
|
|
connection = self.m_connection_list[i]
|
|
content += " <c%i>%i:%i:%i</c%i>\n" % (i, connection[iConnId], connection[iConnOutput], connection[iConnInput], i)
|
|
content += " </Connections>\n"
|
|
|
|
content += "</CATARINA>\n"
|
|
|
|
try:
|
|
fd = uopen(path, "w")
|
|
fd.write(content)
|
|
fd.close()
|
|
except:
|
|
QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to save file"))
|
|
|
|
def loadFile(self, path):
|
|
if not os.path.exists(path):
|
|
QMessageBox.critical(self, self.tr("Error"), self.tr("The file '%s' does not exist" % path))
|
|
self.m_save_path = None
|
|
return
|
|
|
|
try:
|
|
fd = uopen(path, "r")
|
|
readState = fd.read()
|
|
fd.close()
|
|
except:
|
|
QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to load file"))
|
|
self.m_save_path = None
|
|
return
|
|
|
|
self.m_save_path = path
|
|
self.m_group_list = []
|
|
self.m_group_list_pos = []
|
|
self.m_port_list = []
|
|
self.m_connection_list = []
|
|
self.m_last_group_id = 1
|
|
self.m_last_port_id = 1
|
|
self.m_last_connection_id = 1
|
|
|
|
xml = QDomDocument()
|
|
xml.setContent(readState.encode("utf-8"))
|
|
|
|
content = xml.documentElement()
|
|
if content.tagName() != "CATARINA":
|
|
QMessageBox.critical(self, self.tr("Error"), self.tr("Not a valid Catarina file"))
|
|
return
|
|
|
|
# Get values from XML - the big code
|
|
node = content.firstChild()
|
|
while not node.isNull():
|
|
if node.toElement().tagName() == "Groups":
|
|
group_name = ""
|
|
groups = node.toElement().firstChild()
|
|
while not groups.isNull():
|
|
group = groups.toElement().firstChild()
|
|
while not group.isNull():
|
|
tag = group.toElement().tagName()
|
|
text = group.toElement().text()
|
|
if tag == "name":
|
|
group_name = text
|
|
elif tag == "data":
|
|
group_data = text.split(":")
|
|
if len(group_data) == 7 and group_data[0].isdigit() and group_data[1].isdigit() and group_data[2].isdigit() and isNumber(group_data[3]) and isNumber(group_data[4]) and isNumber(group_data[5]) and isNumber(group_data[6]):
|
|
group_obj = [None, None, None, None]
|
|
group_obj[iGroupId] = int(group_data[0])
|
|
group_obj[iGroupName] = group_name
|
|
group_obj[iGroupSplit] = int(group_data[1])
|
|
group_obj[iGroupIcon] = int(group_data[2])
|
|
|
|
group_pos_obj = [None, None, None, None, None]
|
|
group_pos_obj[iGroupPosId] = int(group_data[0])
|
|
group_pos_obj[iGroupPosX_o] = float(group_data[3])
|
|
group_pos_obj[iGroupPosY_o] = float(group_data[4])
|
|
group_pos_obj[iGroupPosX_i] = float(group_data[5])
|
|
group_pos_obj[iGroupPosY_i] = float(group_data[6])
|
|
|
|
self.m_group_list.append(group_obj)
|
|
self.m_group_list_pos.append(group_pos_obj)
|
|
|
|
group_id = group_obj[iGroupId]
|
|
if group_id > self.m_last_group_id:
|
|
self.m_last_group_id = group_id + 1
|
|
group = group.nextSibling()
|
|
groups = groups.nextSibling()
|
|
|
|
elif node.toElement().tagName() == "Ports":
|
|
port_name = ""
|
|
ports = node.toElement().firstChild()
|
|
while not ports.isNull():
|
|
port = ports.toElement().firstChild()
|
|
while not port.isNull():
|
|
tag = port.toElement().tagName()
|
|
text = port.toElement().text()
|
|
if tag == "name":
|
|
port_name = text
|
|
elif tag == "data":
|
|
port_data = text.split(":")
|
|
if len(port_data) == 4 and port_data[0].isdigit() and port_data[1].isdigit() and port_data[2].isdigit() and port_data[3].isdigit():
|
|
new_port = [None, None, None, None, None]
|
|
new_port[iPortGroup] = int(port_data[0])
|
|
new_port[iPortId] = int(port_data[1])
|
|
new_port[iPortName] = port_name
|
|
new_port[iPortMode] = int(port_data[2])
|
|
new_port[iPortType] = int(port_data[3])
|
|
self.m_port_list.append(new_port)
|
|
|
|
if new_port[iPortId] > self.m_last_port_id:
|
|
self.m_last_port_id = new_port[iPortId] + 1
|
|
|
|
port = port.nextSibling()
|
|
ports = ports.nextSibling()
|
|
|
|
elif node.toElement().tagName() == "Connections":
|
|
conns = node.toElement().firstChild()
|
|
while not conns.isNull():
|
|
conn_data = conns.toElement().text().split(":")
|
|
if len(conn_data) == 3 and conn_data[0].isdigit() and conn_data[1].isdigit() and conn_data[2].isdigit():
|
|
conn_obj = [None, None, None]
|
|
conn_obj[iConnId] = int(conn_data[0])
|
|
conn_obj[iConnOutput] = int(conn_data[1])
|
|
conn_obj[iConnInput] = int(conn_data[2])
|
|
|
|
connection_id = conn_obj[iConnId]
|
|
self.m_connection_list.append(conn_obj)
|
|
|
|
if connection_id >= self.m_last_connection_id:
|
|
self.m_last_connection_id = connection_id + 1
|
|
|
|
conns = conns.nextSibling()
|
|
node = node.nextSibling()
|
|
|
|
self.m_last_group_id += 1
|
|
self.m_last_port_id += 1
|
|
self.m_last_connection_id += 1
|
|
|
|
patchcanvas.clear()
|
|
self.initPorts()
|
|
|
|
self.scene.zoom_fit()
|
|
self.scene.zoom_reset()
|
|
|
|
@pyqtSlot()
|
|
def slot_projectNew(self):
|
|
self.m_group_list = []
|
|
self.m_group_list_pos = []
|
|
self.m_port_list = []
|
|
self.m_connection_list = []
|
|
self.m_last_group_id = 1
|
|
self.m_last_port_id = 1
|
|
self.m_last_connection_id = 1
|
|
self.m_save_path = None
|
|
patchcanvas.clear()
|
|
|
|
@pyqtSlot()
|
|
def slot_projectOpen(self):
|
|
path, _ = QFileDialog.getOpenFileName(self, self.tr("Load State"), filter=self.tr("Catarina XML Document (*.xml)"))
|
|
if path:
|
|
self.loadFile(path)
|
|
|
|
@pyqtSlot()
|
|
def slot_projectSave(self):
|
|
if self.m_save_path:
|
|
self.saveFile(self.m_save_path)
|
|
else:
|
|
self.slot_projectSaveAs()
|
|
|
|
@pyqtSlot()
|
|
def slot_projectSaveAs(self):
|
|
path, _ = QFileDialog.getSaveFileName(self, self.tr("Save State"), filter=self.tr("Catarina XML Document (*.xml)"))
|
|
if path:
|
|
self.m_save_path = path
|
|
self.saveFile(path)
|
|
|
|
@pyqtSlot()
|
|
def slot_groupAdd(self):
|
|
dialog = CatarinaAddGroupW(self, self.m_group_list)
|
|
if dialog.exec_():
|
|
group_id = self.m_last_group_id
|
|
group_name = dialog.ret_group_name
|
|
group_split = dialog.ret_group_split
|
|
group_splitR = patchcanvas.SPLIT_YES if group_split else patchcanvas.SPLIT_NO
|
|
group_icon = patchcanvas.ICON_HARDWARE if group_split else patchcanvas.ICON_APPLICATION
|
|
patchcanvas.addGroup(group_id, group_name, group_splitR, group_icon)
|
|
|
|
group_obj = [None, None, None, None]
|
|
group_obj[iGroupId] = group_id
|
|
group_obj[iGroupName] = group_name
|
|
group_obj[iGroupSplit] = group_split
|
|
group_obj[iGroupIcon] = group_icon
|
|
|
|
self.m_group_list.append(group_obj)
|
|
self.m_last_group_id += 1
|
|
|
|
@pyqtSlot()
|
|
def slot_groupRemove(self):
|
|
if len(self.m_group_list) > 0:
|
|
dialog = CatarinaRemoveGroupW(self, self.m_group_list)
|
|
if dialog.exec_():
|
|
group_id = dialog.ret_group_id
|
|
|
|
# Remove port connections first
|
|
for port in self.m_port_list:
|
|
if port[iPortGroup] == group_id:
|
|
port_id = port[iPortId]
|
|
|
|
h = 0
|
|
for i in range(len(self.m_connection_list)):
|
|
connection = self.m_connection_list[i-h]
|
|
if connection[iConnOutput] == port_id or connection[iConnInput] == port_id:
|
|
patchcanvas.disconnectPorts(connection[iConnId])
|
|
self.m_connection_list.pop(i-h)
|
|
h += 1
|
|
|
|
# Remove ports
|
|
h = 0
|
|
for i in range(len(self.m_port_list)):
|
|
port = self.m_port_list[i-h]
|
|
if port[iPortGroup] == group_id:
|
|
port_id = port[iPortId]
|
|
|
|
patchcanvas.removePort(port[iPortId])
|
|
self.m_port_list.pop(i-h)
|
|
h += 1
|
|
|
|
# Now remove group
|
|
patchcanvas.removeGroup(group_id)
|
|
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
self.m_group_list.remove(group)
|
|
break
|
|
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Please add a Group first!"))
|
|
|
|
@pyqtSlot()
|
|
def slot_groupRename(self):
|
|
if len(self.m_group_list) > 0:
|
|
dialog = CatarinaRenameGroupW(self, self.m_group_list)
|
|
if dialog.exec_():
|
|
group_id = dialog.ret_group_id
|
|
new_group_name = dialog.ret_new_group_name
|
|
patchcanvas.renameGroup(group_id, new_group_name)
|
|
|
|
for group in self.m_group_list:
|
|
if group[iGroupId] == group_id:
|
|
group[iGroupName] = new_group_name
|
|
break
|
|
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Please add a Group first!"))
|
|
|
|
@pyqtSlot()
|
|
def slot_portAdd(self):
|
|
if len(self.m_group_list) > 0:
|
|
dialog = CatarinaAddPortW(self, self.m_group_list, self.m_last_port_id)
|
|
if dialog.exec_():
|
|
group_id = dialog.ret_group_id
|
|
port_name = dialog.ret_port_name
|
|
port_mode = dialog.ret_port_mode
|
|
port_type = dialog.ret_port_type
|
|
patchcanvas.addPort(group_id, self.m_last_port_id, port_name, port_mode, port_type)
|
|
|
|
new_port = [None, None, None, None, None]
|
|
new_port[iPortGroup] = group_id
|
|
new_port[iPortId] = self.m_last_port_id
|
|
new_port[iPortName] = port_name
|
|
new_port[iPortMode] = port_mode
|
|
new_port[iPortType] = port_type
|
|
|
|
self.m_port_list.append(new_port)
|
|
self.m_last_port_id += 1
|
|
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Please add a Group first!"))
|
|
|
|
@pyqtSlot()
|
|
def slot_portRemove(self):
|
|
if len(self.m_port_list) > 0:
|
|
dialog = CatarinaRemovePortW(self, self.m_group_list, self.m_port_list)
|
|
if dialog.exec_():
|
|
port_id = dialog.ret_port_id
|
|
|
|
h = 0
|
|
for i in range(len(self.m_connection_list)):
|
|
connection = self.m_connection_list[i-h]
|
|
if connection[iConnOutput] == port_id or connection[iConnInput] == port_id:
|
|
patchcanvas.disconnectPorts(connection[iConnId])
|
|
self.m_connection_list.pop(i-h)
|
|
h += 1
|
|
|
|
patchcanvas.removePort(port_id)
|
|
|
|
for port in self.m_port_list:
|
|
if port[iPortId] == port_id:
|
|
self.m_port_list.remove(port)
|
|
break
|
|
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Please add a Port first!"))
|
|
|
|
@pyqtSlot()
|
|
def slot_portRename(self):
|
|
if len(self.m_port_list) > 0:
|
|
dialog = CatarinaRenamePortW(self, self.m_group_list, self.m_port_list)
|
|
if dialog.exec_():
|
|
port_id = dialog.ret_port_id
|
|
new_port_name = dialog.ret_new_port_name
|
|
patchcanvas.renamePort(port_id, new_port_name)
|
|
|
|
for port in self.m_port_list:
|
|
if port[iPortId] == port_id:
|
|
port[iPortName] = new_port_name
|
|
break
|
|
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Please add a Port first!"))
|
|
|
|
@pyqtSlot()
|
|
def slot_connectPorts(self):
|
|
if len(self.m_port_list) > 0:
|
|
dialog = CatarinaConnectPortsW(self, self.m_group_list, self.m_port_list)
|
|
if dialog.exec_():
|
|
connection_id = self.m_last_connection_id
|
|
port_out_id = dialog.ret_port_out_id
|
|
port_in_id = dialog.ret_port_in_id
|
|
|
|
for connection in self.m_connection_list:
|
|
if connection[iConnOutput] == port_out_id and connection[iConnInput] == port_in_id:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Ports already connected!"))
|
|
return
|
|
|
|
patchcanvas.connectPorts(connection_id, port_out_id, port_in_id)
|
|
|
|
conn_obj = [None, None, None]
|
|
conn_obj[iConnId] = connection_id
|
|
conn_obj[iConnOutput] = port_out_id
|
|
conn_obj[iConnInput] = port_in_id
|
|
|
|
self.m_connection_list.append(conn_obj)
|
|
self.m_last_connection_id += 1
|
|
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Please add some Ports first!"))
|
|
|
|
@pyqtSlot()
|
|
def slot_disconnectPorts(self):
|
|
if len(self.m_connection_list) > 0:
|
|
dialog = CatarinaDisconnectPortsW(self, self.m_group_list, self.m_port_list, self.m_connection_list)
|
|
if dialog.exec_():
|
|
connection_id = -1
|
|
port_out_id = dialog.ret_port_out_id
|
|
port_in_id = dialog.ret_port_in_id
|
|
|
|
for connection in self.m_connection_list:
|
|
if connection[iConnOutput] == port_out_id and connection[iConnInput] == port_in_id:
|
|
connection_id = connection[iConnId]
|
|
self.m_connection_list.remove(connection)
|
|
break
|
|
|
|
patchcanvas.disconnectPorts(connection_id)
|
|
|
|
else:
|
|
QMessageBox.warning(self, self.tr("Warning"), self.tr("Please make some Connections first!"))
|
|
|
|
@pyqtSlot()
|
|
def slot_configureCatarina(self):
|
|
dialog = SettingsW(self, "catarina", hasGL)
|
|
if dialog.exec_():
|
|
self.loadSettings(False)
|
|
patchcanvas.clear()
|
|
|
|
p_options = patchcanvas.options_t()
|
|
p_options.theme_name = self.fSavedSettings["Canvas/Theme"]
|
|
p_options.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
|
|
p_options.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
|
|
p_options.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
|
|
p_options.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
|
|
|
|
patchcanvas.setOptions(p_options)
|
|
patchcanvas.init("Catarina", self.scene, self.canvasCallback, DEBUG)
|
|
|
|
self.initPorts()
|
|
|
|
@pyqtSlot()
|
|
def slot_aboutCatarina(self):
|
|
QMessageBox.about(self, self.tr("About Catarina"), self.tr("<h3>Catarina</h3>"
|
|
"<br>Version %s"
|
|
"<br>Catarina is a testing ground for the 'PatchCanvas' module.<br>"
|
|
"<br>Copyright (C) 2010-2022 falkTX") % VERSION)
|
|
|
|
def saveSettings(self):
|
|
settings = QSettings()
|
|
|
|
settings.setValue("Geometry", self.saveGeometry())
|
|
settings.setValue("ShowToolbar", self.ui.frame_toolbar.isVisible())
|
|
|
|
def loadSettings(self, geometry):
|
|
settings = QSettings()
|
|
|
|
if geometry:
|
|
self.restoreGeometry(settings.value("Geometry", b""))
|
|
|
|
showToolbar = settings.value("ShowToolbar", True, type=bool)
|
|
self.ui.act_settings_show_toolbar.setChecked(showToolbar)
|
|
self.ui.frame_toolbar.setVisible(showToolbar)
|
|
|
|
self.fSavedSettings = {
|
|
"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/TextAntialiasing": settings.value("Canvas/TextAntialiasing", True, type=bool),
|
|
"Canvas/HighQualityAntialiasing": settings.value("Canvas/HighQualityAntialiasing", False, type=bool)
|
|
}
|
|
|
|
def timerEvent(self, event):
|
|
if event.timerId() == self.fUpdateTimer:
|
|
self.update()
|
|
QMainWindow.timerEvent(self, event)
|
|
|
|
def closeEvent(self, event):
|
|
self.saveSettings()
|
|
patchcanvas.clear()
|
|
QMainWindow.closeEvent(self, event)
|
|
|
|
#--------------- main ------------------
|
|
if __name__ == '__main__':
|
|
# App initialization
|
|
app = QApplication(sys.argv)
|
|
app.setApplicationName("Catarina")
|
|
app.setApplicationVersion(VERSION)
|
|
app.setOrganizationName("Cadence")
|
|
app.setWindowIcon(QIcon(":/scalable/catarina.svg"))
|
|
setup_i18n()
|
|
|
|
# Show GUI
|
|
gui = CatarinaMainW()
|
|
|
|
# Set-up custom signal handling
|
|
setUpSignals(gui)
|
|
|
|
gui.show()
|
|
|
|
if len(app.arguments()) > 1:
|
|
if not app.arguments()[0].endswith("Python.exe"):
|
|
gui.loadFile(app.arguments()[1])
|
|
elif len(app.arguments()) > 2:
|
|
gui.loadFile(app.arguments()[2])
|
|
|
|
# App-Loop
|
|
sys.exit(app.exec_())
|