]> 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
24
25 log = logging.getLogger(__name__)
26
27
28 class MeterWidget(Gtk.DrawingArea):
29     def __init__(self, scale):
30         log.debug("Creating MeterWidget for scale %s", scale)
31         super().__init__()
32         self.scale = scale
33         self.color_bg = Gdk.Color(0,0,0)
34         self.color_value = None
35         self.color_mark = 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
39         self.min_width = 15
40         self.preferred_width = 25
41         self.preferred_height = 200
42
43         self.widen()
44
45         self.connect("draw", self.draw)
46         self.connect("size-allocate", self.on_size_allocate)
47
48     def narrow(self):
49         return self.widen(False)
50
51     def widen(self, flag=True):
52         self.set_size_request(self.preferred_width if flag else self.min_width,
53                               self.preferred_height)
54
55     def set_color(self, color):
56         self.color_value = color
57         self.cache_surface = None
58         self.invalidate_all()
59
60     def on_expose(self, widget, event):
61         cairo_ctx = widget.window.cairo_create()
62         # set a clip region for the expose event
63         cairo_ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
64         cairo_ctx.clip()
65
66         self.draw(cairo_ctx)
67
68         return False
69
70     def on_size_allocate(self, widget, allocation):
71         self.width = float(allocation.width)
72         self.height = float(allocation.height)
73         self.font_size = 10
74         self.cache_surface = None
75
76     def invalidate_all(self):
77         self.queue_draw_area(0, 0, int(self.width), int(self.height))
78
79     def draw_background(self, cairo_ctx):
80         if not self.cache_surface:
81             self.cache_surface = cairo.Surface.create_similar(
82                             cairo_ctx.get_target(),
83                             cairo.CONTENT_COLOR,
84                             int(self.width),
85                             int(self.height))
86             cache_cairo_ctx = cairo.Context(self.cache_surface)
87
88             cache_cairo_ctx.set_source_rgba(0, 0, 0, 0)
89             cache_cairo_ctx.rectangle(0, 0, self.width, self.height)
90             cache_cairo_ctx.fill()
91
92             cache_cairo_ctx.set_source_rgba(0.2, 0.2, 0.2, 1)
93             cache_cairo_ctx.select_font_face("Fixed")
94             cache_cairo_ctx.set_font_size(self.font_size)
95             glyph_width = self.font_size * 3 / 5 # avarage glyph ratio
96
97             for mark in self.scale.get_marks():
98                 mark_position = int(self.height * (1 - mark.scale))
99                 cache_cairo_ctx.move_to(0, mark_position)
100                 cache_cairo_ctx.line_to(self.width, mark_position)
101                 cache_cairo_ctx.stroke()
102                 x_correction = self.width / 2 - glyph_width * len(mark.text) / 2
103                 cache_cairo_ctx.move_to(x_correction, mark_position - 2)
104                 cache_cairo_ctx.show_text(mark.text)
105
106         cairo_ctx.set_source_surface(self.cache_surface, 0, 0)
107         cairo_ctx.paint()
108
109     def draw_value(self, cairo_ctx, value, x, width):
110         if self.color_value is not None:
111             cairo_ctx.set_source_rgb(self.color_value.red/65535.,
112                     self.color_value.green/65535., self.color_value.blue/65535.)
113         else:
114             height = self.height
115             gradient = cairo.LinearGradient(1, 1, width-1, height-1)
116
117             if self.scale.scale_id == "K20":
118                 gradient.add_color_stop_rgb(0, 1, 0, 0)
119                 gradient.add_color_stop_rgb(0.38, 1, 1, 0)
120                 gradient.add_color_stop_rgb(0.5, 0, 1, 0)
121                 gradient.add_color_stop_rgb(1, 0, 0, 1)
122             elif self.scale.scale_id == "K14":
123                 gradient.add_color_stop_rgb(0, 1, 0, 0)
124                 gradient.add_color_stop_rgb(1-self.scale.db_to_scale(-14), 1, 1, 0)
125                 gradient.add_color_stop_rgb(1-self.scale.db_to_scale(-24), 0, 1, 0)
126                 gradient.add_color_stop_rgb(1, 0, 0, 1)
127             else:
128                 gradient.add_color_stop_rgb(0, 1, 0, 0)
129                 gradient.add_color_stop_rgb(0.2, 1, 1, 0)
130                 gradient.add_color_stop_rgb(1, 0, 1, 0)
131
132             cairo_ctx.set_source(gradient)
133
134         cairo_ctx.rectangle(x, self.height * (1 - value), width, self.height * value)
135         cairo_ctx.fill()
136
137     def draw_peak(self, cairo_ctx, value, x, width):
138         cairo_ctx.set_source_rgb(1, 1, 1)
139         cairo_ctx.rectangle(x, self.height * (1 - value), width, 2.5)
140         cairo_ctx.fill()
141
142     def set_scale(self, scale):
143         self.scale = scale
144         self.cache_surface = None
145         self.invalidate_all()
146
147
148 class MonoMeterWidget(MeterWidget):
149     def __init__(self, scale):
150         super().__init__(scale)
151         self.value = 0.0
152         self.pk = 0.0
153         self.raw_value = 0.0
154         self.raw_pk = 0.0
155
156     def draw(self, widget, cairo_ctx):
157         self.draw_background(cairo_ctx)
158         self.draw_value(cairo_ctx, self.value, self.width/4.0, self.width/2.0)
159         self.draw_peak(cairo_ctx, self.pk, self.width/4.0, self.width/2.0)
160
161     def set_values(self, pk, value):
162         if value == self.raw_value and pk == self.raw_pk:
163             return
164
165         self.raw_value = value
166         self.raw_pk = pk
167         old_value = self.value
168         old_pk = self.pk
169         self.value = self.scale.db_to_scale(value)
170         self.pk = self.scale.db_to_scale(pk)
171
172         if (abs(old_value-self.value) * self.height) > 0.01 or (abs(old_pk-self.pk) * self.height) > 0.01:
173             self.invalidate_all()
174
175
176 class StereoMeterWidget(MeterWidget):
177     def __init__(self, scale):
178         super().__init__(scale)
179         self.pk_left = 0.0
180         self.pk_right = 0.0
181
182         self.left = 0.0
183         self.right = 0.0
184
185         self.raw_left_pk = 0.0
186         self.raw_right_pk = 0.0
187
188         self.raw_left = 0.0
189         self.raw_right = 0.0
190
191     def draw(self, widget, cairo_ctx):
192         self.draw_background(cairo_ctx)
193         self.draw_value(cairo_ctx, self.left, self.width/5.0, self.width/5.0)
194         self.draw_value(cairo_ctx, self.right, self.width/5.0 * 3.0, self.width/5.0)
195         self.draw_peak(cairo_ctx, self.pk_left, self.width/5.0, self.width/5.0)
196         self.draw_peak(cairo_ctx, self.pk_right, self.width/5.0 * 3.0, self.width/5.0)
197
198     def set_values(self, pk_l, pk_r, left, right):
199         if left == self.raw_left and right == self.raw_right and pk_l == self.raw_left_pk and pk_r == self.raw_right_pk:
200             return
201
202         self.raw_left = left
203         self.raw_right = right
204         self.raw_left_pk = pk_l
205         self.raw_right_pk = pk_r
206         old_left = self.left
207         old_right = self.right
208         old_pk_left = self.pk_left
209         old_pk_right = self.pk_right
210         self.left = self.scale.db_to_scale(left)
211         self.right = self.scale.db_to_scale(right)
212         self.pk_left = self.scale.db_to_scale(pk_l)
213         self.pk_right = self.scale.db_to_scale(pk_r)
214
215         if (abs(old_left-self.left) * self.height) > 0.01 or (abs(old_right-self.right) * self.height) > 0.01 or (abs(old_pk_left-self.pk_left) * self.height) > 0.01 or (abs(old_pk_right-self.pk_right) * self.height) > 0.01:
216             self.invalidate_all()