Browse Source

Initial port of catarina and patchcanvas

tags/v0.9.0
falkTX 13 years ago
parent
commit
c33a2f9f90
4 changed files with 1095 additions and 0 deletions
  1. +398
    -0
      src/catarina.py
  2. +493
    -0
      src/patchcanvas.py
  3. +167
    -0
      src/patchcanvas_theme.py
  4. +37
    -0
      src/shared.py

+ 398
- 0
src/catarina.py View File

@@ -0,0 +1,398 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# PatchCanvas test application
# Copyright (C) 2012 Filipe Coelho <falktx@gmail.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 PyQt4.QtCore import pyqtSlot, Qt, QSettings
from PyQt4.QtGui import QApplication, QDialog, QDialogButtonBox, QPainter, QMainWindow

# Imports (Custom Stuff)
import patchcanvas
import ui_catarina, icons_rc
import ui_catarina_addgroup, ui_catarina_removegroup, ui_catarina_renamegroup
import ui_catarina_addport, ui_catarina_removeport, ui_catarina_renameport
import ui_catarina_connectports, ui_catarina_disconnectports
from shared import *

try:
from PyQt4.QtOpenGL import QGLWidget
hasGL = True
except:
hasGL = False

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.connect(self, SIGNAL("accepted()"), SLOT("slot_setReturn()"))
self.connect(self.le_group_name, SIGNAL("textChanged(QString)"), SLOT("slot_checkText(QString)"))

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()

# 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)

i = 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(i)
self.tw_group_list.setItem(i, 0, twi_group_id)
self.tw_group_list.setItem(i, 1, twi_group_name)
self.tw_group_list.setItem(i, 2, twi_group_split)
i += 1

self.connect(self, SIGNAL("accepted()"), SLOT("slot_setReturn()"))
self.connect(self.tw_group_list, SIGNAL("cellDoubleClicked(int, int)"), SLOT("accept()"))
self.connect(self.tw_group_list, SIGNAL("currentCellChanged(int, int, int, int)"), SLOT("slot_checkCell(int)"))

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):
self.ret_group_id = int(self.tw_group_list.item(self.tw_group_list.currentRow(), 0).text())

# 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)

for group in group_list:
self.cb_group_to_rename.addItem("%i - %s" % (group[iGroupId], group[iGroupName]))

self.connect(self, SIGNAL("accepted()"), SLOT("slot_setReturn()"))
self.connect(self.cb_group_to_rename, SIGNAL("currentIndexChanged(int)"), SLOT("slot_checkItem()"))
self.connect(self.le_new_group_name, SIGNAL("textChanged(QString)"), SLOT("slot_checkText(QString)"))

self.ret_group_id = -1
self.ret_new_group_name = ""

@pyqtSlot()
def slot_checkItem(self, index):
self.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)
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()

# Main Window
class CatarinaMainW(QMainWindow, ui_catarina.Ui_CatarinaMainW):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.setupUi(self)

self.settings = QSettings("Cadence", "Catarina")
self.loadSettings()

self.act_project_new.setIcon(getIcon("document-new"))
self.act_project_open.setIcon(getIcon("document-open"))
self.act_project_save.setIcon(getIcon("document-save"))
self.act_project_save_as.setIcon(getIcon("document-save-as"))
self.b_project_new.setIcon(getIcon("document-new"))
self.b_project_open.setIcon(getIcon("document-open"))
self.b_project_save.setIcon(getIcon("document-save"))
self.b_project_save_as.setIcon(getIcon("document-save-as"))

self.act_patchbay_add_group.setIcon(getIcon("list-add"))
self.act_patchbay_remove_group.setIcon(getIcon("edit-delete"))
self.act_patchbay_rename_group.setIcon(getIcon("edit-rename"))
self.act_patchbay_add_port.setIcon(getIcon("list-add"))
self.act_patchbay_remove_port.setIcon(getIcon("list-remove"))
self.act_patchbay_rename_port.setIcon(getIcon("edit-rename"))
self.act_patchbay_connect_ports.setIcon(getIcon("network-connect"))
self.act_patchbay_disconnect_ports.setIcon(getIcon("network-disconnect"))
self.b_group_add.setIcon(getIcon("list-add"))
self.b_group_remove.setIcon(getIcon("edit-delete"))
self.b_group_rename.setIcon(getIcon("edit-rename"))
self.b_port_add.setIcon(getIcon("list-add"))
self.b_port_remove.setIcon(getIcon("list-remove"))
self.b_port_rename.setIcon(getIcon("edit-rename"))
self.b_ports_connect.setIcon(getIcon("network-connect"))
self.b_ports_disconnect.setIcon(getIcon("network-disconnect"))

setIcons(self, ("canvas",))

self.scene = patchcanvas.PatchScene(self, self.graphicsView)
self.graphicsView.setScene(self.scene)
self.graphicsView.setRenderHint(QPainter.Antialiasing, bool(self.m_savedSettings["Canvas/Antialiasing"] == Qt.Checked))
self.graphicsView.setRenderHint(QPainter.TextAntialiasing, self.m_savedSettings["Canvas/TextAntialiasing"])
if (self.m_savedSettings["Canvas/UseOpenGL"] and hasGL):
self.graphicsView.setViewport(QGLWidget(self.graphicsView))
self.graphicsView.setRenderHint(QPainter.HighQualityAntialiasing, self.m_savedSettings["Canvas/HighQualityAntialiasing"])

p_options = patchcanvas.options_t()
p_options.theme_name = self.m_savedSettings["Canvas/Theme"]
p_options.bezier_lines = self.m_savedSettings["Canvas/BezierLines"]
p_options.antialiasing = self.m_savedSettings["Canvas/Antialiasing"]
p_options.auto_hide_groups = self.m_savedSettings["Canvas/AutoHideGroups"]
p_options.fancy_eyecandy = self.m_savedSettings["Canvas/FancyEyeCandy"]

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 = False

patchcanvas.set_options(p_options)
patchcanvas.set_features(p_features)
patchcanvas.init(self.scene, self.canvasCallback, DEBUG)

self.connect(self.act_project_new, SIGNAL("triggered()"), SLOT("slot_projectNew()"))
#self.connect(self.act_project_open, SIGNAL("triggered()"), SLOT("slot_projectOpen()"))
#self.connect(self.act_project_save, SIGNAL("triggered()"), SLOT("slot_projectSave()"))
#self.connect(self.act_project_save_as, SIGNAL("triggered()"), SLOT("slot_projectSaveAs()"))
self.connect(self.b_project_new, SIGNAL("clicked()"), SLOT("slot_projectNew()"))
#self.connect(self.b_project_open, SIGNAL("clicked()"), SLOT("slot_projectOpen()"))
#self.connect(self.b_project_save, SIGNAL("clicked()"), SLOT("slot_projectSave()"))
#self.connect(self.b_project_save_as, SIGNAL("clicked()"), SLOT("slot_projectSaveAs()"))
self.connect(self.act_patchbay_add_group, SIGNAL("triggered()"), SLOT("slot_groupAdd()"))
self.connect(self.act_patchbay_remove_group, SIGNAL("triggered()"), SLOT("slot_groupRemove()"))
self.connect(self.act_patchbay_rename_group, SIGNAL("triggered()"), SLOT("slot_groupRename()"))
#self.connect(self.act_patchbay_add_port, SIGNAL("triggered()"),SLOT("slot_portAdd()"))
#self.connect(self.act_patchbay_remove_port, SIGNAL("triggered()"), SLOT("slot_portRemove()"))
#self.connect(self.act_patchbay_rename_port, SIGNAL("triggered()"), SLOT("slot_portRename()"))
#self.connect(self.act_patchbay_connect_ports, SIGNAL("triggered()"), SLOT("slot_connectPorts()"))
#self.connect(self.act_patchbay_disconnect_ports, SIGNAL("triggered()"), SLOT("slot_disconnectPorts()"))
self.connect(self.b_group_add, SIGNAL("clicked()"), SLOT("slot_groupAdd()"))
self.connect(self.b_group_remove, SIGNAL("clicked()"), SLOT("slot_groupRemove()"))
self.connect(self.b_group_rename, SIGNAL("clicked()"), SLOT("slot_groupRename()"))
#self.connect(self.b_port_add, SIGNAL("clicked()"), SLOT("slot_portAdd()"))
#self.connect(self.b_port_remove, SIGNAL("clicked()"), SLOT("slot_portRemove()"))
#self.connect(self.b_port_rename, SIGNAL("clicked()"), SLOT("slot_portRename()"))
#self.connect(self.b_ports_connect, SIGNAL("clicked()"), SLOT("slot_connectPorts()"))
#self.connect(self.b_ports_disconnect, SIGNAL("clicked()"), SLOT("slot_disconnectPorts()"))

#setCanvasConnections(self)

#self.connect(self.act_settings_configure, SIGNAL("triggered()"), self.configureCatarina)

self.connect(self.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCatarina()"))
self.connect(self.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))

#self.connect(self, SIGNAL("SIGUSR1()"), SLOT("slot_projectSave()"))

# Dummy timer to keep events active
self.m_updateTimer = self.startTimer(500)

# Start Empty Project
self.slot_projectNew()

def canvasCallback(self, action, value1, value2, value_str):
print(action, value1, value2, value_str)

@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_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_icon = patchcanvas.ICON_HARDWARE if (group_split) else patchcanvas.ICON_APPLICATION
patchcanvas.addGroup(group_id, group_name, group_split, 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):
dialog = CatarinaRemoveGroupW(self, self.m_group_list)
if (dialog.exec_()):
group_id = dialog.ret_group_id

#for port in self.m_port_list:
#if (group_id == port[iPortGroup]):
#port_id = port[iPortId]

#h = 0
#for j in range(len(self.connection_list)):
#if (self.connection_list[j-h][iConnOutput] == port_id or self.connection_list[j-h][iConnInput] == port_id):
#patchcanvas.disconnectPorts(self.connection_list[j-h][iConnId])
#self.connection_list.pop(j-h)
#h += 1

#h = 0
#for i in range(len(self.port_list)):
#if (self.port_list[i-h][iPortGroup] == group_id):
#port_id = self.port_list[i-h][iPortId]
#patchcanvas.removePort(port_id)
#self.port_list.pop(i-h)
#h += 1

#patchcanvas.removeGroup(group_id)

#for i in range(len(self.group_list)):
#if (self.group_list[i][iGroupId] == group_id):
#self.group_list.pop(i)
#break

@pyqtSlot()
def slot_groupRename(self):
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

@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-2012 falkTX") % (VERSION))

def saveSettings(self):
self.settings.setValue("Geometry", self.saveGeometry())
self.settings.setValue("ShowToolbar", self.frame_toolbar.isVisible())

def loadSettings(self):
self.restoreGeometry(self.settings.value("Geometry", ""))

show_toolbar = self.settings.value("ShowToolbar", True, type=bool)
self.act_settings_show_toolbar.setChecked(show_toolbar)
self.frame_toolbar.setVisible(show_toolbar)

self.m_savedSettings = {
"Canvas/Theme": self.settings.value("Canvas/Theme", patchcanvas.getThemeName(patchcanvas.getDefaultTheme), type=str),
"Canvas/BezierLines": self.settings.value("Canvas/BezierLines", True, type=bool),
"Canvas/AutoHideGroups": self.settings.value("Canvas/AutoHideGroups", False, type=bool),
"Canvas/FancyEyeCandy": self.settings.value("Canvas/FancyEyeCandy", False, type=bool),
"Canvas/UseOpenGL": self.settings.value("Canvas/UseOpenGL", False, type=bool),
"Canvas/Antialiasing": self.settings.value("Canvas/Antialiasing", Qt.PartiallyChecked, type=int),
"Canvas/TextAntialiasing": self.settings.value("Canvas/TextAntialiasing", True, type=bool),
"Canvas/HighQualityAntialiasing": self.settings.value("Canvas/HighQualityAntialiasing", False, type=bool)
}

def timerEvent(self, event):
if (event.timerId() == self.m_updateTimer):
self.update()
QMainWindow.timerEvent(self, event)

def closeEvent(self, event):
self.saveSettings()
QMainWindow.closeEvent(self, event)

#--------------- main ------------------
if __name__ == '__main__':

# App initialization
app = QApplication(sys.argv)
app.setApplicationName("Catarina")
app.setApplicationVersion(VERSION)
app.setOrganizationName("falkTX")
app.setWindowIcon(QIcon(":/scalable/catarina.svg"))

# Show GUI
gui = CatarinaMainW()

# Set-up custom signal handling
set_up_signals(gui)

#if (app.arguments().count() > 1):
#gui.save_path = QStringStr(app.arguments()[1])
#gui.prepareToloadFile()

gui.show()

# App-Loop
sys.exit(app.exec_())

+ 493
- 0
src/patchcanvas.py View File

@@ -0,0 +1,493 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Patchbay Canvas engine using QGraphicsView/Scene
# Copyright (C) 2012 Filipe Coelho <falktx@gmail.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 PyQt4.QtCore import pyqtSlot, qDebug, qCritical, qFatal, Qt, QObject, SIGNAL, SLOT
from PyQt4.QtCore import QPointF, QRectF, QSettings
from PyQt4.QtGui import QGraphicsScene, QGraphicsItem

# Imports (Theme)
from patchcanvas_theme import *

PATCHCANVAS_ORGANISATION_NAME = "Cadence"

# ------------------------------------------------------------------------------
# patchcanvas-api.h

# Port Mode
PORT_MODE_NULL = 0
PORT_MODE_INPUT = 1
PORT_MODE_OUTPUT = 2

# Port Type
PORT_TYPE_NULL = 0
PORT_TYPE_AUDIO_JACK = 1
PORT_TYPE_MIDI_JACK = 2
PORT_TYPE_MIDI_A2J = 3
PORT_TYPE_MIDI_ALSA = 4

# Callback Action
ACTION_GROUP_INFO = 0 # group_id, N, N
ACTION_GROUP_RENAME = 1 # group_id, N, new_name
ACTION_GROUP_SPLIT = 2 # group_id, N, N
ACTION_GROUP_JOIN = 3 # group_id, N, N
ACTION_PORT_INFO = 4 # port_id, N, N
ACTION_PORT_RENAME = 5 # port_id, N, new_name
ACTION_PORTS_CONNECT = 6 # out_id, in_id, N
ACTION_PORTS_DISCONNECT = 7 # conn_id, N, N

# Icon
ICON_HARDWARE = 0
ICON_APPLICATION = 1
ICON_LADISH_ROOM = 2

# Split Option
SPLIT_UNDEF = 0
SPLIT_NO = 1
SPLIT_YES = 2

# Canvas options
class options_t(object):
__slots__ = [
'theme_name',
'bezier_lines',
'antialiasing',
'auto_hide_groups',
'fancy_eyecandy'
]

# Canvas features
class features_t(object):
__slots__ = [
'group_info',
'group_rename',
'port_info',
'port_rename',
'handle_group_pos'
]

# ------------------------------------------------------------------------------
# patchcanvas.h

# object types
CanvasBoxType = QGraphicsItem.UserType + 1
CanvasIconType = QGraphicsItem.UserType + 2
CanvasPortType = QGraphicsItem.UserType + 3
CanvasLineType = QGraphicsItem.UserType + 4
CanvasBezierLineType = QGraphicsItem.UserType + 5
CanvasLineMovType = QGraphicsItem.UserType + 6
CanvasBezierLineMovType = QGraphicsItem.UserType + 7

# object lists
class group_dict_t(object):
__slots__ = [
'group_id',
'group_name',
'split',
'icon',
'widgets'
]

class port_dict_t(object):
__slots__ = [
'group_id',
'port_id',
'port_name',
'port_mode',
'port_type',
'widget'
]

class connection_dict_t(object):
__slots__ = [
'connection_id',
'port_in_id',
'port_out_id',
'widget'
]

# Main Canvas object
class Canvas(object):
__slots__ = [
'scene',
'callback',
'debug',
'last_z_value',
'last_group_id',
'last_connection_id',
'initial_pos',
'group_list',
'port_list',
'connection_list',
'postponed_groups',
'qobject',
'settings',
'theme',
'size_rect',
'initiated'
]

# ------------------------------------------------------------------------------
# patchcanvas.cpp

class CanvasObject(QObject):
def __init__(self, parent):
QObject.__init__(self, parent)

@pyqtSlot()
def CanvasPostponedGroups(self):
CanvasPostponedGroups()

@pyqtSlot()
def PortContextMenuDisconnect(self):
connection_id_try = self.sender().data().toInt()
if (connection_id_try[1]):
CanvasCallback(ACTION_PORTS_DISCONNECT, connection_id_try[0], 0, "")

# Global objects
canvas = Canvas()
canvas.qobject = None
canvas.settings = None
canvas.theme = None
canvas.initiated = False

options = options_t()
options.theme_name = getThemeName(getDefaultTheme())
options.bezier_lines = True
options.antialiasing = Qt.PartiallyChecked
options.auto_hide_groups = True
options.fancy_eyecandy = False

features = features_t()
features.group_info = False
features.group_rename = True
features.port_info = False
features.port_rename = True
features.handle_group_pos = False

# Internal functions
def bool2str(check):
return "True" if check else "False"

# PatchCanvas API
def set_options(new_options):
if (canvas.initiated): return
options.theme_name = new_options.theme_name
options.bezier_lines = new_options.bezier_lines
options.antialiasing = new_options.antialiasing
options.auto_hide_groups = new_options.auto_hide_groups
options.fancy_eyecandy = new_options.fancy_eyecandy

def set_features(new_features):
if (canvas.initiated): return
features.group_info = new_features.group_info
features.group_rename = new_features.group_rename
features.port_info = new_features.port_info
features.port_rename = new_features.port_rename
features.handle_group_pos = new_features.handle_group_pos

def init(scene, callback, debug=False):
if (debug):
qDebug("PatchCanvas::init(%s, %s, %s)" % (scene, callback, bool2str(debug)))

if (canvas.initiated):
qCritical("PatchCanvas::init() - already initiated")
return

if (not callback):
qFatal("PatchCanvas::init() - fatal error: callback not set")
return

canvas.scene = scene
canvas.callback = callback
canvas.debug = debug

canvas.last_z_value = 0
canvas.last_group_id = 0
canvas.last_connection_id = 0
canvas.initial_pos = QPointF(0, 0)

canvas.group_list = []
canvas.port_list = []
canvas.connection_list = []
canvas.postponed_groups = []

if (not canvas.qobject): canvas.qobject = CanvasObject(None)
if (not canvas.settings): canvas.settings = QSettings(PATCHCANVAS_ORGANISATION_NAME, "PatchCanvas")

for i in range(Theme.THEME_MAX):
this_theme_name = getThemeName(i)
if (this_theme_name == options.theme_name):
canvas.theme = Theme(i)
break
else:
canvas.theme = Theme(getDefaultTheme())

canvas.size_rect = QRectF()

canvas.scene.rubberbandByTheme()
canvas.scene.setBackgroundBrush(canvas.theme.canvas_bg)

canvas.initiated = True

def clear():
if (canvas.debug):
qDebug("patchcanvas::clear()")

group_list_ids = []
port_list_ids = []
connection_list_ids = []

for i in range(len(canvas.group_list)):
group_list_ids.append(canvas.group_list[i].group_id)

for i in range(len(canvas.port_list)):
port_list_ids.append(canvas.port_list[i].port_id)

for i in range(len(canvas.connection_list)):
connection_list_ids.append(canvas.connection_list[i].connection_id)

for idx in connection_list_ids:
disconnectPorts(idx)

for idx in port_list_ids:
removePort(tmp_port_list[i])

for idx in group_list_ids:
removeGroup(idx)

canvas.last_z_value = 0
canvas.last_group_id = 0
canvas.last_connection_id = 0

canvas.group_list = []
canvas.port_list = []
canvas.connection_list = []
canvas.postponed_groups = []

canvas.initiated = False

def setInitialPos(x, y):
if (canvas.debug):
qDebug("patchcanvas::setInitialPos(%i, %i)" % (x, y))

canvas.initial_pos.setX(x)
canvas.initial_pos.setY(y)

def setCanvasSize(x, y, width, height):
if (canvas.debug):
qDebug("patchcanvas::setCanvasSize(%i, %i, %i, %i)" % (x, y, width, height))

canvas.size_rect.setX(x)
canvas.size_rect.setY(y)
canvas.size_rect.setWidth(width)
canvas.size_rect.setHeight(height)

# ------------------------------------------------------------------------------
# patchscene.cpp

class PatchScene(QGraphicsScene):
def __init__(self, parent, view):
QGraphicsScene.__init__(self, parent)

self.m_ctrl_down = False
self.m_mouse_down_init = False
self.m_mouse_rubberband = False

self.m_rubberband = self.addRect(QRectF(0, 0, 0, 0))
self.m_rubberband.setZValue(-1)
self.m_rubberband.hide()
self.m_rubberband_selection = False
self.m_rubberband_orig_point = QPointF(0, 0)

self.m_view = view
if (not self.m_view):
qFatal("PatchCanvas::PatchScene() - Invalid view")

def fixScaleFactor(self):
scale = self.m_view.transform().m11()
if (scale > 3.0):
self.m_view.resetTransform()
self.m_view.scale(3.0, 3.0)
elif (scale < 0.2):
self.m_view.resetTransform()
self.m_view.scale(0.2, 0.2)
self.emit(SIGNAL("scaleChanged(double)"), self.m_view.transform().m11())

def rubberbandByTheme(self):
self.m_rubberband.setPen(canvas.theme.rubberband_pen)
self.m_rubberband.setBrush(canvas.theme.rubberband_brush)

def zoom_fit(self):
min_x = min_y = max_x = max_y = None
items_list = self.items()

if (len(items_list) > 0):
for i in range(len(items_list)):
if (items_list[i].isVisible() and items_list[i].type() == CanvasBoxType):
pos = items_list[i].scenePos()
rect = items_list[i].boundingRect()

if (min_x == None):
min_x = pos.x()
elif (pos.x() < min_x):
min_x = pos.x()

if (min_y == None):
min_y = pos.y()
elif (pos.y() < min_y):
min_y = pos.y()

if (max_x == None):
max_x = pos.x()+rect.width()
elif (pos.x()+rect.width() > max_x):
max_x = pos.x()+rect.width()

if (max_y == None):
max_y = pos.y()+rect.height()
elif (pos.y()+rect.height() > max_y):
max_y = pos.y()+rect.height()

self.m_view.fitInView(min_x, min_y, abs(max_x-min_x), abs(max_y-min_y), Qt.KeepAspectRatio)
self.fixScaleFactor()

def zoom_in(self):
if (self.m_view.transform().m11() < 3.0):
self.m_view.scale(1.2, 1.2)
self.emit(SIGNAL("scaleChanged(double)"), self.m_view.transform().m11())

def zoom_out(self):
if (self.m_view.transform().m11() > 0.2):
self.m_view.scale(0.8, 0.8)
self.emit(SIGNAL("scaleChanged(double)"), self.m_view.transform().m11())

def zoom_reset(self):
self.m_view.resetTransform()
self.emit(SIGNAL("scaleChanged(double)"), 1.0)

def keyPressEvent(self, event):
if (not self.m_view):
event.reject()

if (event.key() == Qt.Key_Control):
self.m_ctrl_down = True

if (event.key() == Qt.Key_Home):
self.zoom_fit()
event.accept()

elif (self.m_ctrl_down):
if (event.key() == Qt.Key_Plus):
self.zoom_in()
event.accept()
elif (event.key() == Qt.Key_Minus):
self.zoom_out()
event.accept()
elif (event.key() == Qt.Key_1):
self.zoom_reset()
event.accept()
else:
QGraphicsScene.keyPressEvent(self, event)

else:
QGraphicsScene.keyPressEvent(self, event)

def keyReleaseEvent(self, event):
if (event.key() == Qt.Key_Control):
self.m_ctrl_down = False
QGraphicsScene.keyReleaseEvent(self, event)

def mousePressEvent(self, event):
if (event.button() == Qt.LeftButton):
self.m_mouse_down_init = True
else:
self.m_mouse_down_init = False
self.m_mouse_rubberband = False
QGraphicsScene.mousePressEvent(self, event)

def mouseMoveEvent(self, event):
if (self.m_mouse_down_init):
self.m_mouse_rubberband = (len(self.selectedItems()) == 0)
self.m_mouse_down_init = False

if (self.m_mouse_rubberband):
if (self.m_rubberband_selection == False):
self.m_rubberband.show()
self.m_rubberband_selection = True
self.m_rubberband_orig_point = event.scenePos()

pos = event.scenePos()

if (pos.x() > self.m_rubberband_orig_point.x()):
x = self.m_rubberband_orig_point.x()
else:
x = pos.x()

if (pos.y() > self.m_rubberband_orig_point.y()):
y = self.m_rubberband_orig_point.y()
else:
y = pos.y()

self.m_rubberband.setRect(x, y, abs(pos.x()-self.m_rubberband_orig_point.x()), abs(pos.y()-self.m_rubberband_orig_point.y()))

event.accept()

else:
QGraphicsScene.mouseMoveEvent(self, event)

def mouseReleaseEvent(self, event):
if (self.m_rubberband_selection):
items_list = self.items()
if (len(items_list) > 0):
for item in items_list:
if (item.isVisible() and item.type() == CanvasBoxType):
item_rect = item.sceneBoundingRect()
item_top_left = QPointF(item_rect.x(), item_rect.y())
item_bottom_right = QPointF(item_rect.x()+item_rect.width(), item_rect.y()+item_rect.height())

if (self.m_rubberband.contains(item_top_left) and self.m_rubberband.contains(item_bottom_right)):
item.setSelected(True)

self.m_rubberband.hide()
self.m_rubberband.setRect(0, 0, 0, 0)
self.m_rubberband_selection = False

else:
items_list = self.selectedItems()
for item in items_list:
if (item.isVisible() and item.type() == CanvasBoxType):
item.checkItemPos()
self.emit(SIGNAL("sceneGroupMoved(int, int, QPointF)"), item.getGroupId(), item.getSplittedMode(), item.scenePos())

self.m_mouse_down_init = False
self.m_mouse_rubberband = False
QGraphicsScene.mouseReleaseEvent(self, event)

def wheelEvent(self, event):
if (not self.m_view):
event.reject()

if (self.m_ctrl_down):
factor = 1.41 ** (event.delta()/240.0)
self.m_view.scale(factor, factor)

self.fixScaleFactor()
event.accept()

else:
QGraphicsScene.wheelEvent(self, event)

+ 167
- 0
src/patchcanvas_theme.py View File

@@ -0,0 +1,167 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Patchbay Canvas Themes
# Copyright (C) 2012 Filipe Coelho <falktx@gmail.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

from PyQt4.QtCore import Qt
from PyQt4.QtGui import QColor, QFont, QPen

class Theme(object):

# enum PortType
THEME_PORT_SQUARE = 0
THEME_PORT_POLYGON = 1

# enum List
THEME_MODERN_DARK = 0
THEME_CLASSIC_DARK = 1
THEME_MAX = 2

def __init__(self, idx):
super(Theme, self).__init__()

if (idx == self.THEME_MODERN_DARK):
# Name this theme
self.m_name = "Modern Dark"

# Canvas
self.canvas_bg = QColor(0,0,0)

# Boxes
self.box_pen = QPen(QColor(76,77,78), 1, Qt.SolidLine)
self.box_pen_sel = QPen(QColor(206,207,208), 1, Qt.DashLine)
self.box_bg_1 = QColor(32,34,35)
self.box_bg_2 = QColor(43,47,48)
self.box_shadow = QColor(89,89,89,180)

self.box_text = QPen(QColor(240,240,240), 0)
self.box_font_name = "Deja Vu Sans"
self.box_font_size = 8
self.box_font_state = QFont.Bold

# Ports
self.port_audio_jack_pen = QPen(QColor(63,90,126), 1)
self.port_audio_jack_pen_sel = QPen(QColor(63+30,90+30,126+30), 1)
self.port_midi_jack_pen = QPen(QColor(159,44,42), 1)
self.port_midi_jack_pen_sel = QPen(QColor(159+30,44+30,42+30), 1)
self.port_midi_a2j_pen = QPen(QColor(137,76,43), 1)
self.port_midi_a2j_pen_sel = QPen(QColor(137+30,76+30,43+30), 1)
self.port_midi_alsa_pen = QPen(QColor(93,141,46), 1)
self.port_midi_alsa_pen_sel = QPen(QColor(93+30,141+30,46+30), 1)

self.port_audio_jack_bg = QColor(35,61,99)
self.port_audio_jack_bg_sel = QColor(35+50,61+50,99+50)
self.port_midi_jack_bg = QColor(120,15,16)
self.port_midi_jack_bg_sel = QColor(120+50,15+50,16+50)
self.port_midi_a2j_bg = QColor(101,47,16)
self.port_midi_a2j_bg_sel = QColor(101+50,47+50,16+50)
self.port_midi_alsa_bg = QColor(64,112,18)
self.port_midi_alsa_bg_sel = QColor(64+50,112+50,18+50)

self.port_text = QPen(QColor(250,250,250), 0)
self.port_font_name = "Deja Vu Sans"
self.port_font_size = 8
self.port_font_state = QFont.Normal
self.port_mode = self.THEME_PORT_POLYGON

# Lines
self.line_audio_jack = QColor(63,90,126)
self.line_audio_jack_sel = QColor(63+90,90+90,126+90)
self.line_audio_jack_glow = QColor(100,100,200)
self.line_midi_jack = QColor(159,44,42)
self.line_midi_jack_sel = QColor(159+90,44+90,42+90)
self.line_midi_jack_glow = QColor(200,100,100)
self.line_midi_a2j = QColor(137,76,43)
self.line_midi_a2j_sel = QColor(137+90,76+90,43+90)
self.line_midi_a2j_glow = QColor(166,133,133)
self.line_midi_alsa = QColor(93,141,46)
self.line_midi_alsa_sel = QColor(93+90,141+90,46+90)
self.line_midi_alsa_glow = QColor(100,200,100)

self.rubberband_pen = QPen(QColor(206,207,208), 1, Qt.SolidLine)
self.rubberband_brush = QColor(76,77,78,100)

elif (idx == self.THEME_CLASSIC_DARK):
# Name this theme
self.m_name = "Classic Dark"

# Canvas
self.canvas_bg = QColor(0,0,0)

# Boxes
self.box_pen = QPen(QColor(147-70,151-70,143-70), 2, Qt.SolidLine)
self.box_pen_sel = QPen(QColor(147,151,143), 2, Qt.DashLine)
self.box_bg_1 = QColor(30,34,36)
self.box_bg_2 = QColor(30,34,36)
self.box_shadow = QColor(89,89,89,180)

self.box_text = QPen(QColor(255,255,255), 0)
self.box_font_name = "Sans"
self.box_font_size = 9
self.box_font_state = QFont.Normal

# Ports
self.port_audio_jack_pen = QPen(QColor(35,61,99), 0)
self.port_audio_jack_pen_sel = QPen(QColor(255,0,0), 0)
self.port_midi_jack_pen = QPen(QColor(120,15,16), 0)
self.port_midi_jack_pen_sel = QPen(QColor(255,0,0), 0)
self.port_midi_a2j_pen = QPen(QColor(101,47,17), 0)
self.port_midi_a2j_pen_sel = QPen(QColor(255,0,0), 0)
self.port_midi_alsa_pen = QPen(QColor(63,112,19), 0)
self.port_midi_alsa_pen_sel = QPen(QColor(255,0,0), 0)

self.port_audio_jack_bg = QColor(35,61,99)
self.port_audio_jack_bg_sel = QColor(255,0,0)
self.port_midi_jack_bg = QColor(120,15,16)
self.port_midi_jack_bg_sel = QColor(255,0,0)
self.port_midi_a2j_bg = QColor(101,47,17)
self.port_midi_a2j_bg_sel = QColor(255,0,0)
self.port_midi_alsa_bg = QColor(63,112,19)
self.port_midi_alsa_bg_sel = QColor(255,0,0)

self.port_text = QPen(QColor(250,250,250), 0)
self.port_font_name = "Sans"
self.port_font_size = 8
self.port_font_state = QFont.Normal
self.port_mode = self.THEME_PORT_SQUARE

# Lines
self.line_audio_jack = QColor(53,78,116)
self.line_audio_jack_sel = QColor(255,0,0)
self.line_audio_jack_glow = QColor(255,0,0)
self.line_midi_jack = QColor(139,32,32)
self.line_midi_jack_sel = QColor(255,0,0)
self.line_midi_jack_glow = QColor(255,0,0)
self.line_midi_a2j = QColor(120,65,33)
self.line_midi_a2j_sel = QColor(255,0,0)
self.line_midi_a2j_glow = QColor(255,0,0)
self.line_midi_alsa = QColor(81,130,36)
self.line_midi_alsa_sel = QColor(255,0,0)
self.line_midi_alsa_glow = QColor(255,0,0)

self.rubberband_pen = QPen(QColor(147,151,143), 2, Qt.SolidLine)
self.rubberband_brush = QColor(35,61,99,100)

def getDefaultTheme():
return Theme.THEME_MODERN_DARK

def getThemeName(idx):
if (idx == Theme.THEME_MODERN_DARK):
return "Modern Dark"
elif (idx == Theme.THEME_CLASSIC_DARK):
return "Classic Dark"
else:
return ""

+ 37
- 0
src/shared.py View File

@@ -210,3 +210,40 @@ def showWindow(self):
self.showMaximized()
else:
self.showNormal()

# Shared Icons
def setIcons(self, modes):
if ("canvas" in modes):
self.act_canvas_arrange.setIcon(getIcon("view-sort-ascending"))
self.act_canvas_refresh.setIcon(getIcon("view-refresh"))
self.act_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best"))
self.act_canvas_zoom_in.setIcon(getIcon("zoom-in"))
self.act_canvas_zoom_out.setIcon(getIcon("zoom-out"))
self.act_canvas_zoom_100.setIcon(getIcon("zoom-original"))
self.act_canvas_print.setIcon(getIcon("document-print"))
self.b_canvas_zoom_fit.setIcon(getIcon("zoom-fit-best"))
self.b_canvas_zoom_in.setIcon(getIcon("zoom-in"))
self.b_canvas_zoom_out.setIcon(getIcon("zoom-out"))
self.b_canvas_zoom_100.setIcon(getIcon("zoom-original"))

if ("jack" in modes):
self.act_jack_clear_xruns.setIcon(getIcon("edit-clear"))
self.act_jack_configure.setIcon(getIcon("configure"))
self.act_jack_render.setIcon(getIcon("media-record"))
self.b_jack_clear_xruns.setIcon(getIcon("edit-clear"))
self.b_jack_configure.setIcon(getIcon("configure"))
self.b_jack_render.setIcon(getIcon("media-record"))

if ("transport" in modes):
self.act_transport_play.setIcon(getIcon("media-playback-start"))
self.act_transport_stop.setIcon(getIcon("media-playback-stop"))
self.act_transport_backwards.setIcon(getIcon("media-seek-backward"))
self.act_transport_forwards.setIcon(getIcon("media-seek-forward"))
self.b_transport_play.setIcon(getIcon("media-playback-start"))
self.b_transport_stop.setIcon(getIcon("media-playback-stop"))
self.b_transport_backwards.setIcon(getIcon("media-seek-backward"))
self.b_transport_forwards.setIcon(getIcon("media-seek-forward"))

if ("misc" in modes):
self.act_quit.setIcon(getIcon("application-exit"))
self.act_configure.setIcon(getIcon("configure"))

Loading…
Cancel
Save