]> git.0d.be Git - jack_mixer.git/blob - meter.py
Don't force a redraw of the vumeter if appearance wouldn't change
[jack_mixer.git] / meter.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 cairo
22
23 class meter(gtk.DrawingArea):
24     def __init__(self, scale):
25         gtk.DrawingArea.__init__(self)
26
27         self.scale = scale
28
29         self.connect("expose-event", self.on_expose)
30         self.connect("size-request", self.on_size_request)
31         self.connect("size_allocate", self.on_size_allocate)
32
33         self.color_bg = gtk.gdk.Color(0,0,0)
34         self.color_value = None
35         self.color_mark = gtk.gdk.Color(int(65535 * 0.2), int(65535 * 0.2), int(65535 * 0.2))
36         self.width = 0
37         self.height = 0
38
39     def set_color(self, color):
40         self.color_value = color
41         self.invalidate_all()
42
43     def on_expose(self, widget, event):
44         cairo_ctx = widget.window.cairo_create()
45
46         # set a clip region for the expose event
47         cairo_ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
48         cairo_ctx.clip()
49
50         self.draw(cairo_ctx)
51
52         return False
53
54     def on_size_allocate(self, widget, allocation):
55         #print allocation.x, allocation.y, allocation.width, allocation.height
56         self.width = float(allocation.width)
57         self.height = float(allocation.height)
58         self.font_size = 10
59
60     def on_size_request(self, widget, requisition):
61         #print "size-request, %u x %u" % (requisition.width, requisition.height)
62         requisition.width = 20
63         return
64
65     def invalidate_all(self):
66         self.queue_draw_area(0, 0, int(self.width), int(self.height))
67
68     def draw_background(self, cairo_ctx):
69         cairo_ctx.set_source_color(self.color_bg)
70         cairo_ctx.rectangle(0, 0, self.width, self.height)
71         cairo_ctx.fill()
72
73         cairo_ctx.set_source_color(self.color_mark)
74         cairo_ctx.select_font_face("Fixed")
75         cairo_ctx.set_font_size(self.font_size)
76         glyph_width = self.font_size * 3 / 5 # avarage glyph ratio
77         for mark in self.scale.get_marks():
78             mark_position = int(self.height * (1 - mark.scale))
79             cairo_ctx.move_to(0, mark_position)
80             cairo_ctx.line_to(self.width, mark_position)
81             cairo_ctx.stroke()
82             x_correction = self.width / 2 - glyph_width * len(mark.text) / 2
83             cairo_ctx.move_to(x_correction, mark_position - 2)
84             cairo_ctx.show_text(mark.text)
85
86     def draw_value(self, cairo_ctx, value, x, width):
87         if self.color_value is not None:
88             cairo_ctx.set_source_color(self.color_value)
89         else:
90             height = self.allocation.height
91             gradient = cairo.LinearGradient(1, 1, width-1, height-1)
92             gradient.add_color_stop_rgb(0, 1, 0, 0)
93             gradient.add_color_stop_rgb(0.2, 1, 1, 0)
94             gradient.add_color_stop_rgb(1, 0, 1, 0)
95             cairo_ctx.set_source(gradient)
96         cairo_ctx.rectangle(x, self.height * (1 - value), width, self.height * value)
97         cairo_ctx.fill()
98
99     def set_scale(self, scale):
100         self.scale = scale
101         self.invalidate_all()
102
103 class mono(meter):
104     def __init__(self, scale):
105         meter.__init__(self, scale)
106         self.value = 0.0
107         self.raw_value = 0.0
108
109     def draw(self, cairo_ctx):
110         self.draw_background(cairo_ctx)
111         self.draw_value(cairo_ctx, self.value, self.width/4.0, self.width/2.0)
112
113     def set_value(self, value):
114         if value != self.raw_value:
115             self.raw_value = value
116             self.value = self.scale.db_to_scale(value)
117             self.invalidate_all()
118         if value == self.raw_value:
119             return
120         self.raw_value = value
121         old_vlaue = self.value
122         self.value = self.scale.db_to_scale(value)
123         if (abs(old_value-self.value) * self.height) > 1:
124             self.invalidate_all()
125
126 class stereo(meter):
127     def __init__(self, scale):
128         meter.__init__(self, scale)
129         self.left = 0.0
130         self.right = 0.0
131
132         self.raw_left = 0.0
133         self.raw_right = 0.0
134
135     def draw(self, cairo_ctx):
136         self.draw_background(cairo_ctx)
137         self.draw_value(cairo_ctx, self.left, self.width/5.0, self.width/5.0)
138         self.draw_value(cairo_ctx, self.right, self.width/5.0 * 3.0, self.width/5.0)
139
140     def set_values(self, left, right):
141         if left == self.raw_left and right == self.raw_right:
142             return
143         self.raw_left = left
144         self.raw_right = right
145         old_left = self.left
146         old_right = self.right
147         self.left = self.scale.db_to_scale(left)
148         self.right = self.scale.db_to_scale(right)
149         if (abs(old_left-self.left) * self.height) > 1 or (abs(old_right-self.right) * self.height) > 1:
150             self.invalidate_all()