Pass height/width to cairo.Surface.create_similar as integers
[jack_mixer.git] / meter.py
blob49d04455c51b7ee161b324693eee48b45c722cdb
1 #!/usr/bin/env python
3 # This file is part of jack_mixer
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
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.
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.
20 import gtk
21 import cairo
23 class meter(gtk.DrawingArea):
24 def __init__(self, scale):
25 gtk.DrawingArea.__init__(self)
27 self.scale = scale
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)
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 self.cache_surface = None
40 def set_color(self, color):
41 self.color_value = color
42 self.cache_surface = None
43 self.invalidate_all()
45 def on_expose(self, widget, event):
46 cairo_ctx = widget.window.cairo_create()
48 # set a clip region for the expose event
49 cairo_ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
50 cairo_ctx.clip()
52 self.draw(cairo_ctx)
54 return False
56 def on_size_allocate(self, widget, allocation):
57 #print allocation.x, allocation.y, allocation.width, allocation.height
58 self.width = float(allocation.width)
59 self.height = float(allocation.height)
60 self.font_size = 10
61 self.cache_surface = None
63 def on_size_request(self, widget, requisition):
64 #print "size-request, %u x %u" % (requisition.width, requisition.height)
65 requisition.width = 20
66 return
68 def invalidate_all(self):
69 self.queue_draw_area(0, 0, int(self.width), int(self.height))
71 def draw_background(self, cairo_ctx):
72 if not self.cache_surface:
73 self.cache_surface = cairo.Surface.create_similar(
74 cairo_ctx.get_target(),
75 cairo.CONTENT_COLOR,
76 int(self.width),
77 int(self.height))
78 cache_cairo_ctx = cairo.Context(self.cache_surface)
80 cache_cairo_ctx.set_source_rgba(0, 0, 0, 0)
81 cache_cairo_ctx.rectangle(0, 0, self.width, self.height)
82 cache_cairo_ctx.fill()
84 cache_cairo_ctx.set_source_rgba(0.2, 0.2, 0.2, 1)
85 cache_cairo_ctx.select_font_face("Fixed")
86 cache_cairo_ctx.set_font_size(self.font_size)
87 glyph_width = self.font_size * 3 / 5 # avarage glyph ratio
88 for mark in self.scale.get_marks():
89 mark_position = int(self.height * (1 - mark.scale))
90 cache_cairo_ctx.move_to(0, mark_position)
91 cache_cairo_ctx.line_to(self.width, mark_position)
92 cache_cairo_ctx.stroke()
93 x_correction = self.width / 2 - glyph_width * len(mark.text) / 2
94 cache_cairo_ctx.move_to(x_correction, mark_position - 2)
95 cache_cairo_ctx.show_text(mark.text)
96 cairo_ctx.set_source_surface(self.cache_surface, 0, 0)
97 cairo_ctx.paint()
99 def draw_value(self, cairo_ctx, value, x, width):
100 if self.color_value is not None:
101 cairo_ctx.set_source_color(self.color_value)
102 else:
103 height = self.allocation.height
104 gradient = cairo.LinearGradient(1, 1, width-1, height-1)
105 gradient.add_color_stop_rgb(0, 1, 0, 0)
106 gradient.add_color_stop_rgb(0.2, 1, 1, 0)
107 gradient.add_color_stop_rgb(1, 0, 1, 0)
108 cairo_ctx.set_source(gradient)
109 cairo_ctx.rectangle(x, self.height * (1 - value), width, self.height * value)
110 cairo_ctx.fill()
112 def set_scale(self, scale):
113 self.scale = scale
114 self.cache_surface = None
115 self.invalidate_all()
117 class mono(meter):
118 def __init__(self, scale):
119 meter.__init__(self, scale)
120 self.value = 0.0
121 self.raw_value = 0.0
123 def draw(self, cairo_ctx):
124 self.draw_background(cairo_ctx)
125 self.draw_value(cairo_ctx, self.value, self.width/4.0, self.width/2.0)
127 def set_value(self, value):
128 if value != self.raw_value:
129 self.raw_value = value
130 self.value = self.scale.db_to_scale(value)
131 self.invalidate_all()
132 if value == self.raw_value:
133 return
134 self.raw_value = value
135 old_value = self.value
136 self.value = self.scale.db_to_scale(value)
137 if (abs(old_value-self.value) * self.height) > 1:
138 self.invalidate_all()
140 class stereo(meter):
141 def __init__(self, scale):
142 meter.__init__(self, scale)
143 self.left = 0.0
144 self.right = 0.0
146 self.raw_left = 0.0
147 self.raw_right = 0.0
149 def draw(self, cairo_ctx):
150 self.draw_background(cairo_ctx)
151 self.draw_value(cairo_ctx, self.left, self.width/5.0, self.width/5.0)
152 self.draw_value(cairo_ctx, self.right, self.width/5.0 * 3.0, self.width/5.0)
154 def set_values(self, left, right):
155 if left == self.raw_left and right == self.raw_right:
156 return
157 self.raw_left = left
158 self.raw_right = right
159 old_left = self.left
160 old_right = self.right
161 self.left = self.scale.db_to_scale(left)
162 self.right = self.scale.db_to_scale(right)
163 if (abs(old_left-self.left) * self.height) > 1 or (abs(old_right-self.right) * self.height) > 1:
164 self.invalidate_all()