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