]> git.0d.be Git - jack_mixer.git/blob - meter.py
Set version to 14 in preparation for next release
[jack_mixer.git] / meter.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 logging
19
20 import cairo
21 from gi.repository import Gtk
22 from gi.repository import Gdk
23 from gi.repository import GObject
24
25
26 log = logging.getLogger(__name__)
27
28
29 class MeterWidget(Gtk.DrawingArea):
30     def __init__(self, scale):
31         GObject.GObject.__init__(self)
32
33         self.scale = scale
34
35         self.connect("draw", self.draw)
36         #self.connect("size-request", self.on_size_request)
37         self.connect("size-allocate", self.on_size_allocate)
38
39         self.color_bg = Gdk.Color(0,0,0)
40         self.color_value = None
41         self.color_mark = Gdk.Color(int(65535 * 0.2), int(65535 * 0.2), int(65535 * 0.2))
42         self.width = 0
43         self.height = 0
44         self.cache_surface = None
45
46     def get_preferred_width(self):
47         log.debug('get_preferred_width called')
48         return 2
49
50     def get_preferred_height(self):
51         return 200
52
53     def set_color(self, color):
54         self.color_value = color
55         self.cache_surface = None
56         self.invalidate_all()
57
58     def on_expose(self, widget, event):
59         cairo_ctx = widget.window.cairo_create()
60
61         # set a clip region for the expose event
62         cairo_ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
63         cairo_ctx.clip()
64
65         self.draw(cairo_ctx)
66
67         return False
68
69     def on_size_allocate(self, widget, allocation):
70         self.width = float(allocation.width)
71         self.height = float(allocation.height)
72         self.font_size = 10
73         self.cache_surface = None
74
75     def on_size_request(self, widget, requisition):
76         log.debug("size-request, %u x %u", requisition.width, requisition.height)
77         requisition.width = 20
78         return
79
80     def invalidate_all(self):
81         self.queue_draw_area(0, 0, int(self.width), int(self.height))
82
83     def draw_background(self, cairo_ctx):
84         if not self.cache_surface:
85             self.cache_surface = cairo.Surface.create_similar(
86                             cairo_ctx.get_target(),
87                             cairo.CONTENT_COLOR,
88                             int(self.width),
89                             int(self.height))
90             cache_cairo_ctx = cairo.Context(self.cache_surface)
91
92             cache_cairo_ctx.set_source_rgba(0, 0, 0, 0)
93             cache_cairo_ctx.rectangle(0, 0, self.width, self.height)
94             cache_cairo_ctx.fill()
95
96             cache_cairo_ctx.set_source_rgba(0.2, 0.2, 0.2, 1)
97             cache_cairo_ctx.select_font_face("Fixed")
98             cache_cairo_ctx.set_font_size(self.font_size)
99             glyph_width = self.font_size * 3 / 5 # avarage glyph ratio
100             for mark in self.scale.get_marks():
101                 mark_position = int(self.height * (1 - mark.scale))
102                 cache_cairo_ctx.move_to(0, mark_position)
103                 cache_cairo_ctx.line_to(self.width, mark_position)
104                 cache_cairo_ctx.stroke()
105                 x_correction = self.width / 2 - glyph_width * len(mark.text) / 2
106                 cache_cairo_ctx.move_to(x_correction, mark_position - 2)
107                 cache_cairo_ctx.show_text(mark.text)
108         cairo_ctx.set_source_surface(self.cache_surface, 0, 0)
109         cairo_ctx.paint()
110
111     def draw_value(self, cairo_ctx, value, x, width):
112         if self.color_value is not None:
113             cairo_ctx.set_source_rgb(self.color_value.red/65535.,
114                     self.color_value.green/65535., self.color_value.blue/65535.)
115         else:
116             height = self.height
117             gradient = cairo.LinearGradient(1, 1, width-1, height-1)
118             gradient.add_color_stop_rgb(0, 1, 0, 0)
119             gradient.add_color_stop_rgb(0.2, 1, 1, 0)
120             gradient.add_color_stop_rgb(1, 0, 1, 0)
121             cairo_ctx.set_source(gradient)
122         cairo_ctx.rectangle(x, self.height * (1 - value), width, self.height * value)
123         cairo_ctx.fill()
124
125     def set_scale(self, scale):
126         self.scale = scale
127         self.cache_surface = None
128         self.invalidate_all()
129
130
131 class MonoMeterWidget(MeterWidget):
132     def __init__(self, scale):
133         MeterWidget.__init__(self, scale)
134         self.value = 0.0
135         self.raw_value = 0.0
136
137     def draw(self, widget, cairo_ctx):
138         self.draw_background(cairo_ctx)
139         self.draw_value(cairo_ctx, self.value, self.width/4.0, self.width/2.0)
140
141     def set_value(self, value):
142         if value != self.raw_value:
143             self.raw_value = value
144             self.value = self.scale.db_to_scale(value)
145             self.invalidate_all()
146         if value == self.raw_value:
147             return
148         self.raw_value = value
149         old_value = self.value
150         self.value = self.scale.db_to_scale(value)
151         if (abs(old_value-self.value) * self.height) > 1:
152             self.invalidate_all()
153
154
155 class StereoMeterWidget(MeterWidget):
156     def __init__(self, scale):
157         MeterWidget.__init__(self, scale)
158         self.left = 0.0
159         self.right = 0.0
160
161         self.raw_left = 0.0
162         self.raw_right = 0.0
163
164     def draw(self, widget, cairo_ctx):
165         self.draw_background(cairo_ctx)
166         self.draw_value(cairo_ctx, self.left, self.width/5.0, self.width/5.0)
167         self.draw_value(cairo_ctx, self.right, self.width/5.0 * 3.0, self.width/5.0)
168
169     def set_values(self, left, right):
170         if left == self.raw_left and right == self.raw_right:
171             return
172         self.raw_left = left
173         self.raw_right = right
174         old_left = self.left
175         old_right = self.right
176         self.left = self.scale.db_to_scale(left)
177         self.right = self.scale.db_to_scale(right)
178         if (abs(old_left-self.left) * self.height) > 0.01 or (abs(old_right-self.right) * self.height) > 0.01:
179             self.invalidate_all()