| ... |
... |
@@ -26,8 +26,6 @@ |
|
26
|
26
|
|
|
27
|
27
|
from gajim.common.preview import AudioSampleT
|
|
28
|
28
|
|
|
29
|
|
-from gajim.gtk.util import rgba_to_float
|
|
30
|
|
-
|
|
31
|
29
|
log = logging.getLogger('gajim.gtk.preview_audio_visualizer')
|
|
32
|
30
|
|
|
33
|
31
|
|
| ... |
... |
@@ -40,8 +38,6 @@ def __init__(self, |
|
40
|
38
|
|
|
41
|
39
|
Gtk.DrawingArea.__init__(self)
|
|
42
|
40
|
|
|
43
|
|
- self.set_name('AudioVisualizer')
|
|
44
|
|
- self._update_colors()
|
|
45
|
41
|
self._x_offset = x_offset
|
|
46
|
42
|
self._peak_width = 2 # in px
|
|
47
|
43
|
self._width = width
|
| ... |
... |
@@ -57,6 +53,9 @@ def __init__(self, |
|
57
|
53
|
self.connect('configure-event', self._on_drawingarea_changed)
|
|
58
|
54
|
self.connect('style-updated', self._on_style_updated)
|
|
59
|
55
|
|
|
|
56
|
+ self._style_context = self.get_style_context()
|
|
|
57
|
+ self._style_context.add_class('audiovisualizer')
|
|
|
58
|
+
|
|
60
|
59
|
self.set_size_request(self._width, self._height)
|
|
61
|
60
|
self._surface: Optional[cairo.ImageSurface] = None
|
|
62
|
61
|
self._setup_surface()
|
| ... |
... |
@@ -77,7 +76,7 @@ def draw_graph(self, position: float, seek_position: float = -1.0) -> None: |
|
77
|
76
|
|
|
78
|
77
|
self._position = position
|
|
79
|
78
|
self._seek_position = seek_position
|
|
80
|
|
-
|
|
|
79
|
+
|
|
81
|
80
|
self.queue_draw()
|
|
82
|
81
|
|
|
83
|
82
|
def _on_drawingarea_draw(self,
|
| ... |
... |
@@ -100,25 +99,8 @@ def _on_drawingarea_changed(self, |
|
100
|
99
|
def _on_style_updated(self,
|
|
101
|
100
|
_event: Gdk.EventConfigure
|
|
102
|
101
|
) -> None:
|
|
103
|
|
-
|
|
104
|
|
- self._update_colors()
|
|
105
|
102
|
self.queue_draw()
|
|
106
|
103
|
|
|
107
|
|
- def _update_colors(self) -> None:
|
|
108
|
|
- sc = self.get_style_context()
|
|
109
|
|
- self._progress_color = rgba_to_float(
|
|
110
|
|
- sc.get_color(Gtk.StateFlags.NORMAL)
|
|
111
|
|
- )
|
|
112
|
|
- self._default_color = rgba_to_float(
|
|
113
|
|
- sc.get_background_color(Gtk.StateFlags.NORMAL)
|
|
114
|
|
- )
|
|
115
|
|
- self._outline_color = rgba_to_float(
|
|
116
|
|
- sc.get_border_color(Gtk.StateFlags.NORMAL)
|
|
117
|
|
- )
|
|
118
|
|
- self._seek_color = rgba_to_float(
|
|
119
|
|
- sc.get_color(Gtk.StateFlags.SELECTED)
|
|
120
|
|
- )
|
|
121
|
|
-
|
|
122
|
104
|
def _setup_surface(self) -> None:
|
|
123
|
105
|
if self._surface:
|
|
124
|
106
|
self._surface.finish()
|
| ... |
... |
@@ -128,8 +110,10 @@ def _setup_surface(self) -> None: |
|
128
|
110
|
self._width,
|
|
129
|
111
|
self._height)
|
|
130
|
112
|
ctx: cairo.Context[cairo.ImageSurface] = cairo.Context(self._surface)
|
|
|
113
|
+ self._cairo_path = ctx.copy_path()
|
|
131
|
114
|
|
|
132
|
115
|
if self._num_samples != 0:
|
|
|
116
|
+ self._draw_rms_amplitudes(ctx)
|
|
133
|
117
|
self._draw_surface(ctx)
|
|
134
|
118
|
|
|
135
|
119
|
def _process_samples(self) -> None:
|
| ... |
... |
@@ -164,56 +148,41 @@ def _process_samples(self) -> None: |
|
164
|
148
|
else:
|
|
165
|
149
|
self._samples = samples
|
|
166
|
150
|
|
|
|
151
|
+ def _pixel_pos(self, pos: float) -> float:
|
|
|
152
|
+ return pos * self._width + self._x_offset
|
|
|
153
|
+
|
|
167
|
154
|
def _draw_surface(self, ctx: cairo.Context[cairo.ImageSurface]) -> None:
|
|
168
|
|
- # First draw the progress part from left
|
|
169
|
|
- end = min(round(self._position * self._num_samples), self._num_samples)
|
|
170
|
|
- self._draw_rms_amplitudes(ctx,
|
|
171
|
|
- start=0,
|
|
172
|
|
- end=end,
|
|
173
|
|
- color=self._progress_color
|
|
174
|
|
- )
|
|
|
155
|
+ ctx.append_path(self._cairo_path)
|
|
|
156
|
+ ctx.clip()
|
|
|
157
|
+
|
|
|
158
|
+ play_pos = self._pixel_pos(self._position)
|
|
|
159
|
+ start_pos = self._pixel_pos(0.0)
|
|
|
160
|
+ width_pos = play_pos - start_pos
|
|
|
161
|
+
|
|
|
162
|
+ # Default
|
|
|
163
|
+ self._style_context.set_state(Gtk.StateFlags.NORMAL)
|
|
|
164
|
+ Gtk.render_background(
|
|
|
165
|
+ self._style_context, ctx,
|
|
|
166
|
+ start_pos, 0, self._width, self._height)
|
|
175
|
167
|
|
|
|
168
|
+ # Progress
|
|
|
169
|
+ self._style_context.set_state(Gtk.StateFlags.CHECKED)
|
|
|
170
|
+ Gtk.render_background(self._style_context, ctx,
|
|
|
171
|
+ start_pos, 0, width_pos, self._height)
|
|
|
172
|
+
|
|
|
173
|
+ # Seek
|
|
176
|
174
|
if self._seek_position >= 0:
|
|
177
|
|
- # If state is PLAYING and the user seeks, determine whether the
|
|
178
|
|
- # seek position lies in the past, i.e. on the left side of current
|
|
179
|
|
- # position or in the future, i.e. on the right side.
|
|
180
|
|
- # Highlight the skipped area from seek
|
|
181
|
|
- # to the current position on the determined site.
|
|
182
|
|
- play_pos = min(round(
|
|
183
|
|
- self._position * self._num_samples), self._num_samples)
|
|
184
|
|
- seek_pos = min(round(
|
|
185
|
|
- self._seek_position * self._num_samples), self._num_samples)
|
|
186
|
|
- if play_pos > seek_pos:
|
|
187
|
|
- start = seek_pos
|
|
188
|
|
- end = play_pos
|
|
189
|
|
- else:
|
|
190
|
|
- start = play_pos
|
|
191
|
|
- end = seek_pos
|
|
192
|
|
-
|
|
193
|
|
- self._draw_rms_amplitudes(ctx,
|
|
194
|
|
- start=start,
|
|
195
|
|
- end=end,
|
|
196
|
|
- color=self._seek_color
|
|
197
|
|
- )
|
|
198
|
|
-
|
|
199
|
|
- # Draw the default amplitudes for the rest of the timeline
|
|
200
|
|
- play_pos = min(round(
|
|
201
|
|
- self._position * self._num_samples), self._num_samples)
|
|
202
|
|
- seek_pos = min(round(
|
|
203
|
|
- self._seek_position * self._num_samples), self._num_samples)
|
|
204
|
|
- start_default = max(play_pos, seek_pos)
|
|
205
|
|
-
|
|
206
|
|
- self._draw_rms_amplitudes(ctx,
|
|
207
|
|
- start=start_default,
|
|
208
|
|
- end=self._num_samples,
|
|
209
|
|
- color=self._default_color
|
|
210
|
|
- )
|
|
|
175
|
+ seek_pos = self._pixel_pos(self._seek_position)
|
|
|
176
|
+ start_seek = min(play_pos, seek_pos)
|
|
|
177
|
+ end_seek = max(play_pos, seek_pos)
|
|
|
178
|
+ width_seek = end_seek - start_seek
|
|
|
179
|
+
|
|
|
180
|
+ self._style_context.set_state(Gtk.StateFlags.SELECTED)
|
|
|
181
|
+ Gtk.render_background(self._style_context, ctx,
|
|
|
182
|
+ start_seek, 0, width_seek, self._height)
|
|
211
|
183
|
|
|
212
|
184
|
def _draw_rms_amplitudes(self,
|
|
213
|
|
- ctx: cairo.Context[cairo.ImageSurface],
|
|
214
|
|
- start: int,
|
|
215
|
|
- end: int,
|
|
216
|
|
- color: tuple[float, float, float]
|
|
|
185
|
+ ctx: cairo.Context[cairo.ImageSurface]
|
|
217
|
186
|
) -> None:
|
|
218
|
187
|
peak_width = self._peak_width
|
|
219
|
188
|
radius = 1 # radius of the arcs on top and bottom of the amplitudes
|
| ... |
... |
@@ -224,12 +193,12 @@ def _draw_rms_amplitudes(self, |
|
224
|
193
|
if self._is_LTR:
|
|
225
|
194
|
# determines the spacing between the amplitudes
|
|
226
|
195
|
x_shift = (self._width - 2 * peak_width) / self._num_samples
|
|
227
|
|
- x = self._x_offset + x_shift * (start + 1)
|
|
|
196
|
+ x = self._x_offset + x_shift
|
|
228
|
197
|
else:
|
|
229
|
198
|
x_shift = -(self._width - 2 * peak_width) / self._num_samples
|
|
230
|
|
- x = -x_shift * (self._num_samples - start) + self._x_offset
|
|
|
199
|
+ x = -x_shift * (self._num_samples) + self._x_offset
|
|
231
|
200
|
|
|
232
|
|
- for i in range(start, end):
|
|
|
201
|
+ for i in range(0, self._num_samples):
|
|
233
|
202
|
if self._is_LTR:
|
|
234
|
203
|
sample1 = self._samples[i][0]
|
|
235
|
204
|
sample2 = self._samples[i][1]
|
| ... |
... |
@@ -247,15 +216,10 @@ def _draw_rms_amplitudes(self, |
|
247
|
216
|
radius,
|
|
248
|
217
|
gap,
|
|
249
|
218
|
)
|
|
250
|
|
-
|
|
251
|
|
- ctx.set_source_rgb(*self._outline_color)
|
|
252
|
|
- ctx.stroke_preserve()
|
|
253
|
|
-
|
|
254
|
|
- ctx.set_source_rgb(*color)
|
|
255
|
|
- ctx.fill()
|
|
256
|
|
-
|
|
257
|
219
|
x += x_shift
|
|
258
|
220
|
|
|
|
221
|
+ self._cairo_path = ctx.copy_path()
|
|
|
222
|
+
|
|
259
|
223
|
def _draw_rounded_rec(self,
|
|
260
|
224
|
ctx: cairo.Context[cairo.ImageSurface],
|
|
261
|
225
|
x: float,
|
| ... |
... |
@@ -288,6 +252,7 @@ def _draw_rounded_rec(self, |
|
288
|
252
|
|
|
289
|
253
|
# Up
|
|
290
|
254
|
# A -- B -- C
|
|
|
255
|
+ ctx.move_to(x, y + height1)
|
|
291
|
256
|
ctx.curve_to(x, y + height1,
|
|
292
|
257
|
x + m, y + height1 + radius,
|
|
293
|
258
|
x + width, y + height1)
|
| ... |
... |
@@ -297,6 +262,7 @@ def _draw_rounded_rec(self, |
|
297
|
262
|
ctx.line_to(x, y + gap_size)
|
|
298
|
263
|
# F -- A
|
|
299
|
264
|
ctx.line_to(x, y + height1)
|
|
|
265
|
+ ctx.close_path()
|
|
300
|
266
|
|
|
301
|
267
|
# Down
|
|
302
|
268
|
# C -- D
|
| ... |
... |
@@ -310,3 +276,4 @@ def _draw_rounded_rec(self, |
|
310
|
276
|
ctx.line_to(x, y - gap_size)
|
|
311
|
277
|
# A -- C
|
|
312
|
278
|
ctx.line_to(x + width, y - gap_size)
|
|
|
279
|
+ ctx.close_path() |