]> git.0d.be Git - jack_mixer.git/blob - slider.py
Add possibility to have output channels mixing channels *prefader*
[jack_mixer.git] / slider.py
1 #!/usr/bin/env python
2 #
3 # This file is part of jack_mixer
4 #
5 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
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; version 2 of the License
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 import gtk
21 import gobject
22
23 class adjustment_dBFS(gtk.Adjustment):
24     def __init__(self, scale, default_db):
25         self.default_value = scale.db_to_scale(default_db)
26         self.db = default_db
27         self.scale = scale
28         gtk.Adjustment.__init__(self, self.default_value, 0.0, 1.0, 0.02)
29         self.connect("value-changed", self.on_value_changed)
30         self.disable_value_notify = False
31
32     def step_up(self):
33         self.set_value(self.get_value() + self.step_increment)
34
35     def step_down(self):
36         self.set_value(self.get_value() - self.step_increment)
37
38     def reset(self):
39         self.set_value(self.default_value)
40
41     def get_value_db(self):
42         return self.db
43
44     def set_value_db(self, db):
45         self.db = db
46         self.disable_value_notify = True
47         self.set_value(self.scale.db_to_scale(db))
48         self.disable_value_notify = False
49         self.emit("volume-changed")
50
51     def on_value_changed(self, adjustment):
52         if not self.disable_value_notify:
53             self.db = self.scale.scale_to_db(self.get_value())
54             self.emit("volume-changed")
55
56     def set_scale(self, scale):
57         self.scale = scale
58         self.disable_value_notify = True
59         self.set_value(self.scale.db_to_scale(self.db))
60         self.disable_value_notify = False
61
62 gobject.signal_new("volume-changed", adjustment_dBFS, gobject.SIGNAL_RUN_FIRST | gobject.SIGNAL_ACTION, gobject.TYPE_NONE, [])
63
64
65 class GtkSlider(gtk.VScale):
66     def __init__(self, adjustment):
67         gtk.VScale.__init__(self, adjustment)
68         self.set_draw_value(False)
69         self.set_inverted(True)
70
71         # HACK: we want the behaviour you get with the middle button, so we
72         # mangle the events. Clicking with other buttons moves the slider in
73         # step increments, clicking with the middle button moves the slider
74         # to the location of the click.
75         self.connect('button-press-event', self.button_press_event)
76         self.connect('button-release-event', self.button_release_event)
77
78     def button_press_event(self, widget, event):
79         event.button = 2
80         return False
81
82     def button_release_event(self, widget, event):
83         event.button = 2
84         return False
85
86
87 class CustomSliderWidget(gtk.DrawingArea):
88     def __init__(self, adjustment):
89         gtk.DrawingArea.__init__(self)
90
91         self.adjustment = adjustment
92
93         self.connect("expose-event", self.on_expose)
94         self.connect("size-request", self.on_size_request)
95         self.connect("size_allocate", self.on_size_allocate)
96         adjustment.connect("value-changed", self.on_value_changed)
97         self.connect("button-press-event", self.on_mouse)
98         self.connect("motion-notify-event", self.on_mouse)
99         self.set_events(gtk.gdk.BUTTON1_MOTION_MASK | gtk.gdk.BUTTON1_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK)
100
101     def on_mouse(self, widget, event):
102         if event.type == gtk.gdk.BUTTON_PRESS:
103             #print "mouse button %u pressed %u:%u" % (event.button, event.x, event.y)
104             if event.button == 1:
105                 if event.y >= self.slider_rail_up and event.y < self.slider_rail_up + self.slider_rail_height:
106                     self.adjustment.set_value(1 - float(event.y - self.slider_rail_up)/float(self.slider_rail_height))
107             elif event.button == 2:
108                 self.adjustment.reset()
109         elif event.type == gtk.gdk.MOTION_NOTIFY:
110             #print "mouse motion %u:%u" % (event.x, event.y)
111             if event.y < self.slider_rail_up:
112                 y = self.slider_rail_up
113             elif event.y > self.slider_rail_up + self.slider_rail_height:
114                 y = self.slider_rail_up + self.slider_rail_height
115             else:
116                 y = event.y
117             self.adjustment.set_value(1 - float(y - self.slider_rail_up)/float(self.slider_rail_height))
118
119         return False
120
121     def on_value_changed(self, adjustment):
122         self.invalidate_all()
123
124     def on_expose(self, widget, event):
125         cairo_ctx = widget.window.cairo_create()
126
127         # set a clip region for the expose event
128         cairo_ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
129         cairo_ctx.clip()
130
131         self.draw(cairo_ctx)
132
133         return False
134
135     def on_size_allocate(self, widget, allocation):
136         #print allocation.x, allocation.y, allocation.width, allocation.height
137         self.width = float(allocation.width)
138         self.height = float(allocation.height)
139         self.font_size = 10
140
141     def on_size_request(self, widget, requisition):
142         #print "size-request, %u x %u" % (requisition.width, requisition.height)
143         requisition.width = 20
144         return
145
146     def invalidate_all(self):
147         self.queue_draw_area(0, 0, int(self.width), int(self.height))
148
149     def draw(self, cairo_ctx):
150         if self.flags() & gtk.HAS_FOCUS:
151             state = gtk.STATE_PRELIGHT
152         else:
153             state = gtk.STATE_NORMAL
154
155         #cairo_ctx.rectangle(0, 0, self.width, self.height)
156         #cairo_ctx.set_source_color(self.style.bg[state])
157         #cairo_ctx.fill_preserve()
158         cairo_ctx.set_source_color(self.style.fg[state])
159         #cairo_ctx.stroke()
160
161         slider_knob_width = self.width * 3 / 4
162         slider_knob_height = self.width * 3 / 2
163         slider_knob_height -= slider_knob_height % 2
164         slider_knob_height += 1
165
166         slider_x = self.width/2
167
168         cairo_ctx.set_line_width(1)
169
170         # slider rail
171         cairo_ctx.set_source_color(self.style.dark[state])
172         self.slider_rail_up = slider_knob_height/2 + (self.width - slider_knob_width)/2
173         self.slider_rail_height = self.height - 2 * self.slider_rail_up
174         cairo_ctx.move_to(slider_x, self.slider_rail_up)
175         cairo_ctx.line_to(slider_x, self.slider_rail_height + self.slider_rail_up)
176         cairo_ctx.stroke()
177
178         # slider knob
179         slider_y = round(self.slider_rail_up + self.slider_rail_height * (1 - self.adjustment.get_value()))
180         cairo_ctx.rectangle(slider_x - float(slider_knob_width)/2,
181                             slider_y - slider_knob_height/2,
182                             float(slider_knob_width),
183                             slider_knob_height)
184         cairo_ctx.set_source_color(self.style.bg[state])
185         cairo_ctx.fill_preserve()
186         cairo_ctx.set_source_color(self.style.fg[state])
187         cairo_ctx.stroke()
188         # slider knob marks
189         cairo_ctx.set_source_color(self.style.fg[state])
190         for i in range(int(slider_knob_height/2))[8:]:
191             if i % 2 == 0:
192                 correction = 1.0 + (float(slider_knob_height)/2.0 - float(i)) / 10.0
193                 correction *= 2
194                 y = slider_y - i
195                 w = float(slider_knob_width)/2.0 - correction
196                 x1 = slider_x - w
197                 x2 = slider_x + w
198                 cairo_ctx.move_to(x1, y+0.5)
199                 cairo_ctx.line_to(x2, y+0.5)
200                 y = slider_y + i
201                 cairo_ctx.move_to(x1, y-0.5)
202                 cairo_ctx.line_to(x2, y-0.5)
203         cairo_ctx.set_line_width(1)
204         cairo_ctx.stroke()
205         # slider knob middle mark
206         cairo_ctx.move_to(slider_x - float(slider_knob_width)/2, slider_y)
207         cairo_ctx.line_to(slider_x + float(slider_knob_width)/2, slider_y)
208         cairo_ctx.set_line_width(2)
209         cairo_ctx.stroke()