1 |
# |
---|
2 |
# Copyright (C) 2009 by Arnold Krille |
---|
3 |
# |
---|
4 |
# This file is part of FFADO |
---|
5 |
# FFADO = Free Firewire (pro-)audio drivers for linux |
---|
6 |
# |
---|
7 |
# This program is free software: you can redistribute it and/or modify |
---|
8 |
# it under the terms of the GNU General Public License as published by |
---|
9 |
# the Free Software Foundation, either version 2 of the License, or |
---|
10 |
# (at your option) version 3 of the License. |
---|
11 |
# |
---|
12 |
# This program is distributed in the hope that it will be useful, |
---|
13 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 |
# GNU General Public License for more details. |
---|
16 |
# |
---|
17 |
# You should have received a copy of the GNU General Public License |
---|
18 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
19 |
# |
---|
20 |
|
---|
21 |
from PyQt4 import QtGui, QtCore, Qt |
---|
22 |
import dbus, math, numpy |
---|
23 |
|
---|
24 |
import logging |
---|
25 |
log = logging.getLogger("widgets") |
---|
26 |
|
---|
27 |
percentage = 0.3 |
---|
28 |
circlerect = QtCore.QRectF(-percentage/2, -percentage/2, percentage, percentage) |
---|
29 |
|
---|
30 |
class PannerSource(QtGui.QGraphicsEllipseItem): |
---|
31 |
def __init__(self, number, parent): |
---|
32 |
QtGui.QGraphicsEllipseItem.__init__(self) |
---|
33 |
self.setRect(circlerect) |
---|
34 |
|
---|
35 |
self.number = number |
---|
36 |
self.parent = parent |
---|
37 |
|
---|
38 |
self.setBrush(QtGui.QColor(255, 0, 0)) |
---|
39 |
self.setPen(QtGui.QPen(Qt.Qt.NoPen)) |
---|
40 |
|
---|
41 |
self.setFlags(QtGui.QGraphicsItem.ItemIsMovable | QtGui.QGraphicsItem.ItemIsFocusable) |
---|
42 |
|
---|
43 |
def focusInEvent(self, ev): |
---|
44 |
QtGui.QGraphicsEllipseItem.focusInEvent(self, ev) |
---|
45 |
|
---|
46 |
def itemChange(self, change, value): |
---|
47 |
if change == QtGui.QGraphicsItem.ItemPositionChange: |
---|
48 |
value = self.parent.nearestSink(value.toPointF()) |
---|
49 |
if change == QtGui.QGraphicsItem.ItemPositionHasChanged: |
---|
50 |
self.parent.sourcePositionChanged(self.number) |
---|
51 |
return QtGui.QGraphicsEllipseItem.itemChange(self, change, value) |
---|
52 |
|
---|
53 |
class N2MPanner(QtGui.QFrame): |
---|
54 |
def __init__(self, parent): |
---|
55 |
QtGui.QFrame.__init__(self, parent) |
---|
56 |
|
---|
57 |
layout = QtGui.QGridLayout(self) |
---|
58 |
self.setLayout(layout) |
---|
59 |
|
---|
60 |
self.view = QtGui.QGraphicsView(self) |
---|
61 |
layout.addWidget(self.view, 0, 0) |
---|
62 |
|
---|
63 |
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(-1, -1, 2, 2), self) |
---|
64 |
self.view.setScene(self.scene) |
---|
65 |
|
---|
66 |
self.scene.addEllipse( QtCore.QRectF(-1,-1,2,2), QtGui.QPen(self.palette().color(QtGui.QPalette.Window).darker() ) ).setZValue(-1) |
---|
67 |
|
---|
68 |
self.pen = QtGui.QPen(self.palette().color(QtGui.QPalette.Window).darker()) |
---|
69 |
#pen.setWidthF(0.01) |
---|
70 |
|
---|
71 |
self.sources = [] |
---|
72 |
self.sinks = [] |
---|
73 |
self.values = numpy.array(numpy.float) |
---|
74 |
#print self.values.flags |
---|
75 |
#print self.values |
---|
76 |
|
---|
77 |
#self.updateGeometry() |
---|
78 |
QtCore.QTimer.singleShot(10, self.resizeEvent) |
---|
79 |
|
---|
80 |
def setNumberOfSinks(self, sinknr): |
---|
81 |
#print "N2MPanner.setNumberOfSinks( %i )" % sinknr |
---|
82 |
while len(self.sinks) > sinknr: |
---|
83 |
self.sinks[-1].setParentItem(None) |
---|
84 |
del self.sinks[-1] |
---|
85 |
while len(self.sinks) < sinknr: |
---|
86 |
c = self.scene.addEllipse(circlerect, self.pen) |
---|
87 |
c.setZValue(1) |
---|
88 |
self.sinks.append(c) |
---|
89 |
#print "N2MPanner.setNumberOfSinks() new size %i" % len(self.sinks) |
---|
90 |
for i in range(sinknr): |
---|
91 |
degree = 2*math.pi/sinknr * i |
---|
92 |
self.sinks[i].setPos(math.cos(degree), math.sin(degree)) |
---|
93 |
self.update() |
---|
94 |
self.values.resize((len(self.sources), len(self.sinks))) |
---|
95 |
self.sourcePositionChanged(range(len(self.sources))) |
---|
96 |
|
---|
97 |
def setNumberOfSources(self, sourcenr): |
---|
98 |
#print "N2MPanner.setNumberOfSources( %i )" % sourcenr |
---|
99 |
while len(self.sources) > sourcenr: |
---|
100 |
self.sources[-1].setParentItem(None) |
---|
101 |
del self.sources[-1] |
---|
102 |
while len(self.sources) < sourcenr: |
---|
103 |
s = PannerSource(len(self.sources), self) |
---|
104 |
self.scene.addItem(s) |
---|
105 |
self.sources.append(s) |
---|
106 |
#print "N2MPanner.setNumberOfSources() new size %i" % len(self.sources) |
---|
107 |
self.values.resize((len(self.sources), len(self.sinks))) |
---|
108 |
self.sourcePositionChanged(range(len(self.sources))) |
---|
109 |
|
---|
110 |
def distance(self, p1, p2): |
---|
111 |
return math.sqrt( math.pow(p1.x()-p2.x(), 2) + math.pow(p1.y()-p2.y(), 2) ) |
---|
112 |
|
---|
113 |
def sourcePositionChanged(self, number): |
---|
114 |
if not isinstance(number, list): |
---|
115 |
number = [number] |
---|
116 |
#print "N2MPanner.sourcePositionChanged( %s )" % str(number) |
---|
117 |
for i in number: |
---|
118 |
for sink in self.sinks: |
---|
119 |
j = self.sinks.index(sink) |
---|
120 |
self.values[i,j] = self.distance(self.sources[i].pos(), sink.pos()) |
---|
121 |
#print " distance to sink(%g, %g) is %g" % (sink.x(), sink.y(), self.distance(self.sources[number].pos(), sink.pos())) |
---|
122 |
#print self.values |
---|
123 |
self.emit(QtCore.SIGNAL("valuesChanged")) |
---|
124 |
|
---|
125 |
def nearestSink(self, point): |
---|
126 |
for sink in self.sinks: |
---|
127 |
if sink.contains(sink.mapFromParent(point)): |
---|
128 |
return sink.pos() |
---|
129 |
return point |
---|
130 |
|
---|
131 |
def resizeEvent(self, event=None): |
---|
132 |
self.view.fitInView(QtCore.QRectF(-1.2, -1.2, 2.4, 2.4), Qt.Qt.KeepAspectRatio) |
---|
133 |
|
---|
134 |
|
---|
135 |
if __name__ == "__main__": |
---|
136 |
|
---|
137 |
import sys |
---|
138 |
|
---|
139 |
app = QtGui.QApplication(sys.argv) |
---|
140 |
|
---|
141 |
w = QtGui.QWidget(None) |
---|
142 |
l = QtGui.QVBoxLayout(w) |
---|
143 |
|
---|
144 |
s1 = QtGui.QSpinBox(w) |
---|
145 |
s1.setRange(1,10) |
---|
146 |
l.addWidget(s1) |
---|
147 |
|
---|
148 |
s2 = QtGui.QSpinBox(w) |
---|
149 |
s2.setRange(1,10) |
---|
150 |
l.addWidget(s2) |
---|
151 |
|
---|
152 |
p = N2MPanner(w) |
---|
153 |
p.setNumberOfSinks(1) |
---|
154 |
p.setNumberOfSources(1) |
---|
155 |
QtCore.QObject.connect(s1, QtCore.SIGNAL("valueChanged(int)"), p.setNumberOfSinks) |
---|
156 |
QtCore.QObject.connect(s2, QtCore.SIGNAL("valueChanged(int)"), p.setNumberOfSources) |
---|
157 |
l.addWidget(p) |
---|
158 |
|
---|
159 |
w.show() |
---|
160 |
|
---|
161 |
app.exec_() |
---|
162 |
|
---|
163 |
|
---|
164 |
# |
---|
165 |
# vim: et ts=4 sw=4 |
---|