Minor code re-ordering for clarity
[jack_mixer.git] / meter.py
blobc56bd6e8875c40aafc61947191422d8924f14187
1 # This file is part of jack_mixer
3 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
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
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.
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.
18 import logging
20 import cairo
21 from gi.repository import Gtk
22 from gi.repository import Gdk
25 log = logging.getLogger(__name__)
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
43 self.widen()
45 self.connect("draw", self.draw)
46 self.connect("size-allocate", self.on_size_allocate)
48 def narrow(self):
49 return self.widen(False)
51 def widen(self, flag=True):
52 self.set_size_request(
53 self.preferred_width if flag else self.min_width, self.preferred_height
56 def set_color(self, color):
57 self.color_value = color
58 self.cache_surface = None
59 self.invalidate_all()
61 def on_expose(self, widget, event):
62 cairo_ctx = widget.window.cairo_create()
63 # set a clip region for the expose event
64 cairo_ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
65 cairo_ctx.clip()
67 self.draw(cairo_ctx)
69 return False
71 def on_size_allocate(self, widget, allocation):
72 self.width = float(allocation.width)
73 self.height = float(allocation.height)
74 self.font_size = 10
75 self.cache_surface = None
77 def invalidate_all(self):
78 self.queue_draw_area(0, 0, int(self.width), int(self.height))
80 def draw_background(self, cairo_ctx):
81 if not self.cache_surface:
82 self.cache_surface = cairo.Surface.create_similar(
83 cairo_ctx.get_target(), cairo.CONTENT_COLOR, int(self.width), int(self.height)
85 cache_cairo_ctx = cairo.Context(self.cache_surface)
87 cache_cairo_ctx.set_source_rgba(0, 0, 0, 0)
88 cache_cairo_ctx.rectangle(0, 0, self.width, self.height)
89 cache_cairo_ctx.fill()
91 cache_cairo_ctx.set_source_rgba(0.2, 0.2, 0.2, 1)
92 cache_cairo_ctx.select_font_face("Fixed")
93 cache_cairo_ctx.set_font_size(self.font_size)
94 glyph_width = self.font_size * 3 / 5 # avarage glyph ratio
96 for mark in self.scale.get_marks():
97 mark_position = int(self.height * (1 - mark.scale))
98 cache_cairo_ctx.move_to(0, mark_position)
99 cache_cairo_ctx.line_to(self.width, mark_position)
100 cache_cairo_ctx.stroke()
101 x_correction = self.width / 2 - glyph_width * len(mark.text) / 2
102 cache_cairo_ctx.move_to(x_correction, mark_position - 2)
103 cache_cairo_ctx.show_text(mark.text)
105 cairo_ctx.set_source_surface(self.cache_surface, 0, 0)
106 cairo_ctx.paint()
108 def draw_value(self, cairo_ctx, value, x, width):
109 if self.color_value is not None:
110 cairo_ctx.set_source_rgb(
111 self.color_value.red / 65535.0,
112 self.color_value.green / 65535.0,
113 self.color_value.blue / 65535.0,
115 else:
116 height = self.height
117 gradient = cairo.LinearGradient(1, 1, width - 1, height - 1)
119 if self.scale.scale_id == "K20":
120 gradient.add_color_stop_rgb(0, 1, 0, 0)
121 gradient.add_color_stop_rgb(0.38, 1, 1, 0)
122 gradient.add_color_stop_rgb(0.5, 0, 1, 0)
123 gradient.add_color_stop_rgb(1, 0, 0, 1)
124 elif self.scale.scale_id == "K14":
125 gradient.add_color_stop_rgb(0, 1, 0, 0)
126 gradient.add_color_stop_rgb(1 - self.scale.db_to_scale(-14), 1, 1, 0)
127 gradient.add_color_stop_rgb(1 - self.scale.db_to_scale(-24), 0, 1, 0)
128 gradient.add_color_stop_rgb(1, 0, 0, 1)
129 else:
130 gradient.add_color_stop_rgb(0, 1, 0, 0)
131 gradient.add_color_stop_rgb(0.2, 1, 1, 0)
132 gradient.add_color_stop_rgb(1, 0, 1, 0)
134 cairo_ctx.set_source(gradient)
136 cairo_ctx.rectangle(x, self.height * (1 - value), width, self.height * value)
137 cairo_ctx.fill()
139 def draw_peak(self, cairo_ctx, value, x, width):
140 cairo_ctx.set_source_rgb(1, 1, 1)
141 cairo_ctx.rectangle(x, self.height * (1 - value), width, 2.5)
142 cairo_ctx.fill()
144 def set_scale(self, scale):
145 self.scale = scale
146 self.cache_surface = None
147 self.invalidate_all()
150 class MonoMeterWidget(MeterWidget):
151 def __init__(self, scale):
152 super().__init__(scale)
153 self.value = 0.0
154 self.pk = 0.0
155 self.raw_value = 0.0
156 self.raw_pk = 0.0
158 def draw(self, widget, cairo_ctx):
159 self.draw_background(cairo_ctx)
160 self.draw_value(cairo_ctx, self.value, self.width / 4.0, self.width / 2.0)
161 self.draw_peak(cairo_ctx, self.pk, self.width / 4.0, self.width / 2.0)
163 def set_values(self, pk, value):
164 if value == self.raw_value and pk == self.raw_pk:
165 return
167 self.raw_value = value
168 self.raw_pk = pk
169 old_value = self.value
170 old_pk = self.pk
171 self.value = self.scale.db_to_scale(value)
172 self.pk = self.scale.db_to_scale(pk)
174 if (abs(old_value - self.value) * self.height) > 0.01 or (
175 abs(old_pk - self.pk) * self.height
176 ) > 0.01:
177 self.invalidate_all()
180 class StereoMeterWidget(MeterWidget):
181 def __init__(self, scale):
182 super().__init__(scale)
183 self.pk_left = 0.0
184 self.pk_right = 0.0
186 self.left = 0.0
187 self.right = 0.0
189 self.raw_left_pk = 0.0
190 self.raw_right_pk = 0.0
192 self.raw_left = 0.0
193 self.raw_right = 0.0
195 def draw(self, widget, cairo_ctx):
196 self.draw_background(cairo_ctx)
197 self.draw_value(cairo_ctx, self.left, self.width / 5.0, self.width / 5.0)
198 self.draw_value(cairo_ctx, self.right, self.width / 5.0 * 3.0, self.width / 5.0)
199 self.draw_peak(cairo_ctx, self.pk_left, self.width / 5.0, self.width / 5.0)
200 self.draw_peak(cairo_ctx, self.pk_right, self.width / 5.0 * 3.0, self.width / 5.0)
202 def set_values(self, pk_l, pk_r, left, right):
203 if (
204 left == self.raw_left
205 and right == self.raw_right
206 and pk_l == self.raw_left_pk
207 and pk_r == self.raw_right_pk
209 return
211 self.raw_left = left
212 self.raw_right = right
213 self.raw_left_pk = pk_l
214 self.raw_right_pk = pk_r
215 old_left = self.left
216 old_right = self.right
217 old_pk_left = self.pk_left
218 old_pk_right = self.pk_right
219 self.left = self.scale.db_to_scale(left)
220 self.right = self.scale.db_to_scale(right)
221 self.pk_left = self.scale.db_to_scale(pk_l)
222 self.pk_right = self.scale.db_to_scale(pk_r)
224 if (
225 (abs(old_left - self.left) * self.height) > 0.01
226 or (abs(old_right - self.right) * self.height) > 0.01
227 or (abs(old_pk_left - self.pk_left) * self.height) > 0.01
228 or (abs(old_pk_right - self.pk_right) * self.height) > 0.01
230 self.invalidate_all()