1
/* gtkwaveview.c: Gtk+ widget for displaying data
3
* This library is free software; you can redistribute it and/or
4
* modify it under the terms of the GNU Library General Public
5
* License as published by the Free Software Foundation; either
6
* version 2 of the License, or (at your option) any later version.
8
* This library is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
* Library General Public License for more details.
13
* You should have received a copy of the GNU Library General Public
14
* License along with this library; if not, write to the
15
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16
* Boston, MA 02111-1307, USA.
19
/* Amplitude zoom, selection, and marker code by
20
* Ben De Rydt <ben.de.rydt@pandora.be>
22
* Documentation for the selection resize algorithm is in
23
* docs/drag_algorithm.txt
27
#include "util/glame_hruler.h"
28
#include "gtkwaveview.h"
29
#include "gtkeditablewavebuffer.h"
34
/* Stuff for new ruler.
37
static gchar *time_metric_translate(gdouble value)
42
minutes = ((gint) (value / 60.0));
43
seconds = value - (((gint)value) / 60) * 60;
45
return g_strdup_printf ("%02d:%02.3f", minutes, seconds);
48
static const GlameRulerMetric time_metric = {
49
"Time Metric", "time", 1.0,
50
24, (gdouble[24]){ 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0,
51
5.0, 15.0, 30.0, 45.0, 60.0, 90.0, 120.0,
52
180.0, 240.0, 360.0, 480.0, 720.0, 960.0,
53
1440.0, 1920.0, 2880.0, 3840.0 },
54
5, (gint[5]){ 1, 5, 10, 30, 60 },
58
static gchar *frame_metric_translate (gdouble value)
60
return g_strdup_printf ("%li", (long) value);
63
static const GlameRulerMetric frame_metric = {
64
"Frame Metric", "frames", 1.0,
65
20, (gdouble[20]){ 1, 5, 10, 50, 100, 500, 1000, 2500, 5000, 10000,
66
50000, 100000, 500000, 1000000, 5000000,
67
10000000, 50000000, 100000000, 5000000, 1000000000 },
68
5, (gint[5]){ 1, 5, 10, 50, 100 },
69
frame_metric_translate
75
static void gtk_wave_view_class_init (GtkWaveViewClass *klass);
76
static void gtk_wave_view_init (GtkWaveView *waveview);
79
static GtkVBoxClass *parent_class;
83
Info on units used in this widget:
85
There are three major units:
86
* Frame units (frame_pos)
87
Used by select_left, select_right and for keeping track of
88
precise data locations. Also used by the scrollbar.
90
* Pel x units relative to left side of window (win_pel_pos)
91
Given to us by Gdk for motion events. Used by us to tell
92
Gdk where to draw stuff.
94
* Pel x units relative to start of data stream (ext_pel_pos)
95
Used by the cache to keep track of recently calculated
98
Mathematical representation of how to convert between unit forms:
100
pel x units relative to start of data stream * zoom
102
Where zoom >= 1.0. zoom is in units of samples per pixel
104
There is a need to convert back and forth between the units,
105
however, you must be careful to round exactly the same way,
106
regardless of which direction you want to convert. Rounding
107
errors occur when converting floating point #s to integers.
108
That happens a lot in this code. Or when performing integer
109
divison (not used much here). If you don't watch how you
110
round, subtle one-off problems will develop. Be careful!
115
gtk_wave_view_get_type (void)
117
static GtkType waveview_type = 0;
121
static const GtkTypeInfo waveview_info =
124
sizeof (GtkWaveView),
125
sizeof (GtkWaveViewClass),
126
(GtkClassInitFunc) gtk_wave_view_class_init,
127
(GtkObjectInitFunc) gtk_wave_view_init,
128
/* reserved_1 */ NULL,
129
/* reserved_2 */ NULL,
130
(GtkClassInitFunc) NULL,
133
waveview_type = gtk_type_unique (GTK_TYPE_VBOX, &waveview_info);
136
return waveview_type;
141
gtk_wave_view_new (void)
143
GtkWaveView *waveview;
145
waveview = gtk_type_new (GTK_TYPE_WAVEFORM);
146
waveview->drawing = 0;
147
waveview->destroyed = 0;
149
return GTK_WIDGET (waveview);
154
gtk_wave_view_real_destroy (GtkObject *obj)
156
GtkWaveView *waveview = GTK_WAVE_VIEW (obj);
158
/* Dont allow destroying, if we have pending drawing events. */
159
if (waveview->drawing) {
160
DPRINTF("NOT destroying.\n");
161
waveview->destroyed = 1;
165
if (waveview->wavebuffer != NULL)
166
gtk_wave_view_set_buffer (waveview, NULL);
168
gdk_cursor_destroy (waveview->drag_cursor);
169
gdk_cursor_destroy (waveview->normal_cursor);
171
if (waveview->marker_gc != NULL)
172
gdk_gc_unref (waveview->marker_gc);
174
GTK_OBJECT_CLASS (parent_class)->destroy (obj);
179
gtk_wave_view_class_init (GtkWaveViewClass *klass)
181
GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
183
parent_class = gtk_type_class (gtk_vbox_get_type ());
184
object_class->destroy = gtk_wave_view_real_destroy;
188
/* Unit conversion functions */
191
calc_scrn_y (gint32 top, gint32 height, gint16 mag, gdouble ampl_zoom)
195
pos = (guint32) (top + (height * 0.5) + \
196
(height * mag * ampl_zoom) / 65535.0);
198
pos = MIN (MAX (pos, top), top + height - 1);
205
calc_win_pel_pos (GtkWaveView *waveview, gint32 frame_pos)
207
return ((gint32) (frame_pos / waveview->zoom)) - ((gint32) (GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom));
212
calc_ext_pel_pos (GtkWaveView *waveview, gint32 frame_pos)
214
return (gint32) (frame_pos / waveview->zoom);
219
calc_win_pel_ext (GtkWaveView *waveview, gint32 ext_pel_pos)
221
return ext_pel_pos - ((gint32)(GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom));
225
calc_ext_pel_win (GtkWaveView *waveview, gint32 win_pel_pos)
227
return win_pel_pos + ((gint32)(GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom));
232
calc_frame_pos_ext (GtkWaveView *waveview, gint32 ext_pel_pos)
234
return (gint32) (ext_pel_pos * waveview->zoom);
239
calc_frame_pos_win (GtkWaveView *waveview, gint32 win_pel_pos)
241
return (((gint32) GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom) + win_pel_pos) * waveview->zoom;
245
/* Cache functions */
247
static void gtk_wave_view_cache_free (GtkWaveView *waveview);
248
static void gtk_wave_view_cache_create (GtkWaveView *waveview);
249
static void gtk_wave_view_cache_add (GtkWaveView *waveview, guint32 x, gint16 *min, gint16 *max);
250
static gint gtk_wave_view_cache_paint (GtkWaveView *waveview, gint32 offset, gint32 x);
251
static void gtk_wave_view_cache_invalidate (GtkWaveView *waveview);
252
static void gtk_wave_view_cache_invalidate_range (GtkWaveView *waveview, gint32 start, gint32 length);
256
gtk_wave_view_cache_free (GtkWaveView *waveview)
260
for (i = 0; i < waveview->n_channels; i++)
262
g_free (waveview->channels [i].cache);
263
waveview->channels [i].cache = NULL;
266
g_free (waveview->cache_tag);
267
waveview->cache_tag = NULL;
272
gtk_wave_view_cache_create (GtkWaveView *waveview)
276
if (waveview->wavebuffer == NULL)
279
waveview->cache_tag = g_new (gint32, waveview->cache_size);
281
for (i = 0; i < waveview->n_channels; i++)
282
waveview->channels[i].cache = g_new (GtkWaveViewCacheEntry, waveview->cache_size);
284
gtk_wave_view_cache_invalidate (waveview);
289
gtk_wave_view_cache_add (GtkWaveView *waveview, guint32 x, gint16 *min, gint16 *max)
291
guint32 i, size, offset;
292
GtkWaveViewCacheEntry *e;
294
size = waveview->cache_size;
297
/* Mmmm... direct mapped cache. */
298
waveview->cache_tag [offset] = x;
300
for (i = 0; i < waveview->n_channels; i++)
302
e = &waveview->channels [i].cache [offset];
306
min [i] = max [i] = 0;
312
gtk_wave_view_cache_paint (GtkWaveView *waveview, gint32 offset, gint32 x)
315
guint32 size, cache_offset;
317
if (waveview->wavebuffer == NULL)
320
size = waveview->cache_size;
321
cache_offset = (offset + x) % size;
323
/* Is this x coordinate cached? */
324
if (waveview->cache_tag [cache_offset] == offset + x)
329
l_pos = calc_win_pel_pos (waveview, waveview->select_left);
330
r_pos = calc_win_pel_pos (waveview, waveview->select_right);
332
for (i = 0; i < waveview->n_channels; i++)
334
GtkWaveViewCacheEntry *e;
338
/* Retrieve cache entry for this channel. */
339
e = &waveview->channels [i].cache [cache_offset];
340
top = waveview->channels [i].top;
341
height = waveview->channels [i].height;
343
/* Calc y coordinates. */
344
min = calc_scrn_y (top, height, e->min, waveview->ampl_zoom);
345
max = calc_scrn_y (top, height, e->max, waveview->ampl_zoom);
347
/* Draw black line if not selected, white otherwise. */
348
if (((1 << i) & waveview->select_channels) && x >= l_pos && x <= r_pos && waveview->select_left <= waveview->select_right)
349
gc = waveview->area->style->fg_gc [GTK_STATE_SELECTED];
351
gc = waveview->area->style->fg_gc [GTK_STATE_ACTIVE];
353
gdk_draw_line (waveview->area->window, gc, x, min, x, max);
364
gtk_wave_view_cache_invalidate (GtkWaveView *waveview)
368
if (waveview->wavebuffer == NULL)
371
for (i = 0; i < waveview->cache_size; i++)
372
waveview->cache_tag [i] = -1;
377
gtk_wave_view_cache_invalidate_range (GtkWaveView *waveview, gint32 start, gint32 length)
381
if (waveview->wavebuffer == NULL)
384
for (i = 0; i < waveview->cache_size; i++)
385
if (waveview->cache_tag [i] >= start &&
386
waveview->cache_tag [i] <= start + length)
387
waveview->cache_tag [i] = -1;
391
/* Update ruler and scrollbar units. */
393
gtk_wave_view_update_units (GtkWaveView *waveview)
396
gdouble length, rate;
400
adj = GTK_ADJUSTMENT (waveview->adjust);
402
if (waveview->wavebuffer == NULL)
407
gtk_adjustment_changed (adj);
408
glame_ruler_set_range (GLAME_RULER(waveview->hruler), 0.0, 0.0, 0.0, 20.0);
412
length = (gdouble) gtk_wave_buffer_get_length (waveview->wavebuffer);
413
rate = (gdouble) gtk_wave_buffer_get_rate (waveview->wavebuffer);
414
width = GTK_WIDGET (waveview)->allocation.width;
416
/* Set scrollbar in pixel units. */
419
adj->step_increment = waveview->zoom * 32.0;
420
//adj->upper += adj->step_increment; /* why? gtk bug? */
421
adj->page_size = width * waveview->zoom;
422
adj->page_increment = adj->page_size;
424
if (adj->value > adj->upper - adj->page_size)
426
adj->value = adj->upper - adj->page_size;
427
if (adj->value < 0.0)
431
gtk_adjustment_changed (adj);
433
/* This is a bit convoluted, but I want to round the units properly.
434
First I convert the sample position to a pel position, and then
435
convert it back into a sample position. */
437
j = -calc_win_pel_pos (waveview, 0);
438
glame_ruler_set_range (GLAME_RULER(waveview->hruler),
439
calc_frame_pos_ext (waveview, j) / rate,
440
calc_frame_pos_ext (waveview, j + width) / rate,
443
glame_ruler_set_range (GLAME_RULER(waveview->hruler),
444
calc_frame_pos_ext (waveview, j),
445
calc_frame_pos_ext (waveview, j + width),
450
/* The crusty stuff to redraw all the channels of a waveview. */
452
gtk_wave_view_redraw_wave (GtkWaveView *waveview)
454
GWavefileType datatype;
455
guint32 n_samples, n_channels;
456
guint32 i, j, width, start_x, offset;
457
gint16 max_val, min_val;
459
if (waveview->wavebuffer == NULL)
462
if (waveview->invalidate)
464
waveview->invalidate = FALSE;
465
gtk_wave_view_cache_invalidate_range (waveview,
466
calc_ext_pel_pos (waveview, waveview->invalidate_start),
467
calc_ext_pel_pos (waveview, waveview->invalidate_stop));
472
offset = -calc_win_pel_pos (waveview, 0);
473
waveview->drawn_offset = offset;
474
width = waveview->expose_width;
475
start_x = MAX(0, calc_win_pel_ext(waveview, waveview->expose_x));
477
/* First, paint all cached x coords. */
478
/* Keep a range min_val -> max_val that contains all uncached x coords. */
479
for (i = start_x; i < start_x + width; i++)
480
if (gtk_wave_view_cache_paint (waveview, offset, i) == 0) {
482
min_val = max_val = i;
489
gint16 max [waveview->n_channels], min [waveview->n_channels];
490
guint32 sample_offset, last_sample_offset, pos, size;
491
guint32 accum, count, delta;
496
/* Now here comes the fun part, if some x coordinates weren't cached, */
497
/* we gotta do a lot of calculations to figure out their values. */
498
n_channels = waveview->n_channels;
500
datatype = gtk_wave_buffer_get_datatype (waveview->wavebuffer);
502
#define REDRAW_BUFFER 8192
503
/* Allocate some temp space. */
504
data = g_malloc (g_wavefile_type_width (datatype) * n_channels * REDRAW_BUFFER);
506
/* Allocate more temp space if the data source datatype is not s16.
507
We then have to convert it to s16 data for cache use. */
508
if (datatype != G_WAVEFILE_TYPE_S16)
509
data16 = g_new (gint16, n_channels * REDRAW_BUFFER);
511
data16 = (gint16*) data;
513
/* Approximate sample # range we need to recalc for the cache. */
514
sample_offset = calc_frame_pos_win (waveview, min_val);
515
last_sample_offset = calc_frame_pos_win (waveview, max_val + 1);
517
n_samples = gtk_wave_buffer_get_length (waveview->wavebuffer);
519
/* Perform clipping. */
520
if (sample_offset >= n_samples)
522
if (last_sample_offset >= n_samples)
523
last_sample_offset = n_samples - 1;
525
for (j = 0; j < waveview->n_channels; j++)
529
accum = 1073741824U; /* 2147483648 / 2, round to nearest unit */
531
delta = (guint32) (2147483648.0 / waveview->zoom);
532
while (pos <= last_sample_offset)
534
size = MIN (REDRAW_BUFFER, last_sample_offset - pos + 1);
536
/* If by any chance we got destroyed, bail out. */
537
if (waveview->destroyed) {
538
DPRINTF("Whoops - coalesced with destroy event :)\n");
542
/* Read data chunk. */
543
gtk_wave_buffer_get_samples (waveview->wavebuffer, pos, size, 0xffffffff, data);
545
/* Convert data to s16 if it's not already in that format. */
546
if (datatype != G_WAVEFILE_TYPE_S16)
547
g_wavefile_type_convert (waveview->n_channels, size, G_WAVEFILE_TYPE_S16, data16, datatype, data);
550
for (i = 0; i < size; i++)
552
/* For each sample of a track, keep min and max values. */
553
for (j = 0; j < n_channels; j++)
555
gint16 val = data16[pos16++];
557
if (val < min[j]) min[j] = val;
558
if (val > max[j]) max[j] = val;
561
/* Do Bresenham's algorithm */
564
if (accum >= 2147483648U)
566
accum -= 2147483648U;
568
gtk_wave_view_cache_add (waveview, offset + min_val + count, min, max);
569
gtk_wave_view_cache_paint (waveview, offset, min_val + count);
575
/* Be nice to the user. */
576
if (gtk_events_pending()) {
577
/* Handle all pending events => stall redrawing. */
578
while (gtk_events_pending())
579
gtk_main_iteration();
581
/* Correcting the exposed region, bail out
582
* - only if expose event arrived (else redraw error) */
583
if (waveview->expose_count > 0) {
584
long notdone_x, notdone_width;
585
notdone_x = calc_ext_pel_pos(waveview, pos + size) - 1;
586
notdone_width = calc_ext_pel_pos(waveview, last_sample_offset - (pos + size) + 1) + 1;
587
if (notdone_x < waveview->expose_x) {
588
waveview->expose_width += waveview->expose_x - notdone_x;
589
waveview->expose_x = notdone_x;
591
if (notdone_x + notdone_width > waveview->expose_x + waveview->expose_width)
592
waveview->expose_width = notdone_x + notdone_width - waveview->expose_x;
597
/* Increment position in data source. */
601
if (data16 != (void*) data)
609
/* Fill rectangle (x1, y) -> (x2, y + height - 1), clip if necessary. */
611
fill_rect (GdkWindow *win, GdkGC *gc, gint32 win_width, gint32 x1, gint32 x2, gint32 y, gint32 height)
613
/* Clipping and stuff.. */
614
if (x1 > x2 || x2 < 0 || x1 >= win_width) return;
617
if (x2 >= win_width) x2 = win_width - 1;
619
gdk_draw_rectangle (win, gc, TRUE, x1, y, x2 - x1 + 1, height);
623
draw_marker_from_frame_pos (GtkWaveView *waveview, gint32 frame)
627
win_pos = calc_win_pel_pos (waveview, frame);
628
if (win_pos >= 0 && win_pos < waveview->area->allocation.width)
631
for (i = 0; i < waveview->n_channels; i++)
635
top = waveview->channels[i].top;
636
height = waveview->channels[i].height;
638
gdk_draw_line (waveview->area->window, waveview->marker_gc,
639
win_pos, top, win_pos, top + height - 1);
646
gtk_wave_view_draw_marker (GtkWaveView *waveview)
648
if (waveview->marker < 0)
650
if (!GTK_WIDGET_REALIZED (waveview->area))
652
draw_marker_from_frame_pos (waveview, waveview->marker);
656
/* Redraw the region between two window x coordinates inclusive. */
658
gtk_wave_view_redraw_area (GtkWaveView *waveview, gint32 x1, gint32 x2)
660
/* Reverse x1 and x2, if backwards. */
664
t = x1; x1 = x2; x2 = t;
667
/* Perform clipping. */
669
if (x1 >= waveview->area->allocation.width) return;
673
if (x2 >= waveview->area->allocation.width)
674
x2 = waveview->area->allocation.width - 1;
676
/* Query a redraw of the area. */
677
gtk_widget_queue_draw_area (GTK_WIDGET (waveview->area),
678
x1, 0, x2 - x1 + 1, waveview->area->allocation.height);
682
/* Redraw the range between two *sample* #s, inclusive. */
684
gtk_wave_view_redraw_sample_area (GtkWaveView *waveview, gint32 pos1, gint32 pos2)
688
x1 = calc_win_pel_pos (waveview, pos1);
689
x2 = calc_win_pel_pos (waveview, pos2);
691
gtk_wave_view_redraw_area (waveview, x1, x2);
696
on_area_realize (GtkWidget *widget, gpointer userdata)
698
GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
700
if (waveview->marker_gc == NULL)
702
waveview->marker_gc = gdk_gc_new (waveview->area->window);
703
gdk_gc_copy (waveview->marker_gc, waveview->area->style->white_gc);
704
gdk_gc_set_function (waveview->marker_gc, GDK_XOR);
706
gdk_gc_set_exposures(waveview->area->style->bg_gc [GTK_STATE_NORMAL],TRUE);
710
/* Paint selection areas then call a function to paint the wave data. */
712
on_area_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer userdata)
714
GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
715
static gint16 horiz_lines [] = { -24576, -16384, -8192, 0, 8191, 16383, 24575, -999 };
716
GdkGC *sel_bg_gc, *unsel_bg_gc;
717
GdkRectangle frame_area;
718
gint expose_x, expose_width;
720
/* Accumulate expose events. */
721
expose_x = calc_ext_pel_win(waveview, event->area.x);
722
expose_width = event->area.width;
724
if (waveview->expose_count == 0) {
725
waveview->expose_x = expose_x;
726
waveview->expose_width = expose_width;
728
if (expose_x < waveview->expose_x) {
729
waveview->expose_width += waveview->expose_x - expose_x;
730
waveview->expose_x = expose_x;
732
if (expose_x + expose_width > waveview->expose_x + waveview->expose_width)
733
waveview->expose_width = expose_x + expose_width - waveview->expose_x;
736
waveview->expose_count++;
738
if (event->count > 0 || waveview->drawing)
741
waveview->drawing = 1;
743
/* Done accumulating sequential expose events, now process them. */
744
waveview->expose_count = 0;
746
sel_bg_gc = widget->style->bg_gc [GTK_STATE_SELECTED];
747
// unsel_bg_gc = widget->style->white_gc;
748
unsel_bg_gc = widget->style->bg_gc [GTK_STATE_NORMAL];
749
if (waveview->wavebuffer != NULL && !waveview->destroyed)
753
guint32 top, height, width;
757
exp_win_x = calc_win_pel_ext(waveview, waveview->expose_x);
758
frame_area.x = MAX(0, exp_win_x);
759
frame_area.width = MIN(waveview->expose_width + MIN(0, exp_win_x), widget->allocation.width);
761
frame_area.height = widget->allocation.height;
764
gtk_wave_view_draw_marker (waveview);
766
/* Set clipping to expose region. */
767
gdk_gc_set_clip_rectangle (widget->style->fg_gc [GTK_STATE_NORMAL], &frame_area);
768
gdk_gc_set_clip_rectangle (widget->style->fg_gc [GTK_STATE_SELECTED], &frame_area);
769
gdk_gc_set_clip_rectangle (widget->style->bg_gc [GTK_STATE_NORMAL], &frame_area);
770
gdk_gc_set_clip_rectangle (widget->style->bg_gc [GTK_STATE_SELECTED], &frame_area);
771
gdk_gc_set_clip_rectangle (widget->style->dark_gc [GTK_STATE_NORMAL], &frame_area);
772
gdk_gc_set_clip_rectangle (widget->style->mid_gc [GTK_STATE_NORMAL], &frame_area);
773
gdk_gc_set_clip_rectangle (widget->style->black_gc, &frame_area);
774
gdk_gc_set_clip_rectangle (waveview->marker_gc, &frame_area);
776
n_channels = gtk_wave_buffer_get_num_channels (waveview->wavebuffer);
777
width = widget->allocation.width;
778
window = widget->window;
780
/* Draw seperator bars. */
781
for (i = 1; i < n_channels; i++)
783
j = waveview->channels[i].top;
784
gdk_draw_line (window, waveview->area->style->mid_gc [GTK_STATE_NORMAL], 0, j - 3, width, j - 3);
785
gdk_draw_line (window, waveview->area->style->dark_gc [GTK_STATE_NORMAL], 0, j - 2, width, j - 2);
786
gdk_draw_line (window, waveview->area->style->black_gc, 0, j - 1, width, j - 1);
789
for (i = 0; i < n_channels; i++)
791
top = waveview->channels [i].top;
792
height = waveview->channels [i].height;
794
/* Draw filled regions. */
795
if (waveview->select_right < waveview->select_left ||
796
!(waveview->select_channels & (1 << i)))
798
fill_rect (window, unsel_bg_gc, width, 0, width - 1, top, height);
804
l_pos = calc_win_pel_pos (waveview, waveview->select_left);
805
r_pos = calc_win_pel_pos (waveview, waveview->select_right);
807
fill_rect (window, unsel_bg_gc, width, 0, l_pos - 1, top, height);
808
fill_rect (window, sel_bg_gc, width, l_pos, r_pos, top, height);
809
fill_rect (window, unsel_bg_gc, width, r_pos + 1, width - 1, top, height);
812
/* Draw horizontal lines. */
813
for (j = 0; horiz_lines [j] != -999; j++)
815
k = calc_scrn_y (top, height, horiz_lines [j],
816
waveview->ampl_zoom);
817
gdk_draw_line (window, waveview->area->style->dark_gc [GTK_STATE_NORMAL], 0, k, width, k);
820
/* Basically, this is just a fast, convoluted version of:
821
j = (x * 50) + offset; where x is an integer selected such that
822
j is a modulus of 50 in the range of: [0,50) */
824
/* calc_win_pel_pos returns <= 0 */
825
j = 49 - ((49 - calc_win_pel_pos (waveview, 0)) % 50);
827
/* Draw vertical lines. */
828
for (; j < width; j += 50)
829
gdk_draw_line (window, waveview->area->style->dark_gc [GTK_STATE_NORMAL], j, top, j, top + height - 1);
832
/* Reset clipping. */
833
gdk_gc_set_clip_mask (widget->style->fg_gc [GTK_STATE_NORMAL], NULL);
834
gdk_gc_set_clip_mask (widget->style->fg_gc [GTK_STATE_SELECTED], NULL);
835
gdk_gc_set_clip_mask (widget->style->bg_gc [GTK_STATE_NORMAL], NULL);
836
gdk_gc_set_clip_mask (widget->style->bg_gc [GTK_STATE_SELECTED], NULL);
837
gdk_gc_set_clip_mask (widget->style->dark_gc [GTK_STATE_NORMAL], NULL);
838
gdk_gc_set_clip_mask (widget->style->mid_gc [GTK_STATE_NORMAL], NULL);
839
gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
840
gdk_gc_set_clip_mask (waveview->marker_gc, NULL);
842
/* Paint all channels of the waveview. */
843
gtk_wave_view_redraw_wave (waveview);
844
if (waveview->destroyed) {
845
DPRINTF("Doing real, delayed destroy.\n");
846
waveview->drawing = 0;
847
gtk_object_destroy(GTK_OBJECT(waveview));
852
gtk_wave_view_draw_marker (waveview);
856
if (waveview->expose_count != 0)
858
waveview->drawing = 0;
862
/* Calculate the top and bottom window y coordinates for each channel. */
864
gtk_wave_view_calc_channel_locs (GtkWaveView *waveview)
866
guint32 i, n_channels, height;
870
if (waveview->wavebuffer == NULL)
873
n_channels = gtk_wave_buffer_get_num_channels (GTK_WAVE_BUFFER (waveview->wavebuffer));
874
height = waveview->area->allocation.height - (n_channels - 1) * 3;
878
for (i = 0; i < n_channels; i++)
880
waveview->channels[i].top = top;
882
waveview->channels[i].height = accum / n_channels;
885
top += waveview->channels[i].height + 3;
890
/* Update ruler and repaint screen on resize event. */
892
gtk_wave_view_resize_event (GtkWidget *widget, gpointer data)
894
GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
896
gtk_wave_view_calc_channel_locs (waveview);
897
gtk_wave_view_update_units (waveview);
902
gtk_wave_view_scroll (GtkWidget *widget, gpointer data)
904
GtkWaveView *waveview = GTK_WAVE_VIEW (data);
905
guint32 offset, width, height;
908
offset = -calc_win_pel_pos (waveview, 0);
910
width = waveview->area->allocation.width;
911
height = waveview->area->allocation.height;
913
gtk_wave_view_update_units (waveview);
915
if (!GTK_WIDGET_REALIZED (waveview->area))
918
if (offset > waveview->drawn_offset)
920
/* Find out how many pixels we moved. */
921
shift = offset - waveview->drawn_offset;
923
/* Copy and redraw as needed. */
925
gtk_widget_queue_draw (GTK_WIDGET (waveview->area));
928
gdk_window_copy_area (waveview->area->window, waveview->area->style->bg_gc [GTK_STATE_NORMAL], 0, 0, waveview->area->window, shift, 0, width - shift, height);
929
gtk_wave_view_redraw_area (waveview, width - 1, width - shift);
934
/* Find out how many pixels we moved. */
935
shift = waveview->drawn_offset - offset;
937
/* Copy and redraw as needed. */
939
gtk_widget_queue_draw (GTK_WIDGET (waveview->area));
942
gdk_window_copy_area (waveview->area->window, waveview->area->style->bg_gc [GTK_STATE_NORMAL], shift, 0, waveview->area->window, 0, 0, width - shift, height);
943
gtk_wave_view_redraw_area (waveview, 0, shift);
948
/* The meaning of the different flags. */
949
#define FLAG_DRAGGING_MARKER (1)
950
#define FLAG_DRAGGING_SELECTION (1 << 1)
951
#define FLAG_DID_MOVE (1 << 2)
952
#define FLAG_CURSOR_SET (1 << 3)
954
#define FLAGS_CLEAR(flags) do { (flags) = 0; } while(0)
955
#define FLAGS_IS_CLEAR(flags) ( (flags) == 0)
956
#define FLAG_SET(flags, flag) do { (flags) |= (flag); } while(0)
957
#define FLAG_UNSET(flags, flag) do { (flags) &= (~(flag)); } while(0)
958
#define FLAG_IS_SET(flags, flag) ((flags) & (flag))
960
/* Given an 2 frame positions, update selection and repaint as needed.
961
Selection is between x1 and x2, but x1 is not necessary <= x2.
964
gtk_wave_view_update_selection (GtkWaveView *waveview, gint32 x1, gint32 x2)
968
len = gtk_wave_buffer_get_length (waveview->wavebuffer);
969
/* Cannot do a selection if empty. */
973
/* sanity checking: before, because both params can be out of range */
974
if (x1 >= len) x1 = len - 1;
975
if (x2 >= len) x2 = len - 1;
985
/* new selection doesn't overlap with old selection */
986
if ((x1 < waveview->select_left && x2 < waveview->select_left) ||
987
(x1 > waveview->select_right && x2 > waveview->select_right))
989
t = waveview->select_left;
990
t2 = waveview->select_right;
991
waveview->select_left = x1;
992
waveview->select_right = x2;
993
gtk_wave_view_redraw_sample_area (waveview, t, t2);
994
gtk_wave_view_redraw_sample_area (waveview, x1, x2);
998
/* new_selection is overlapping with old_selection */
999
if (x1 < waveview->select_left)
1001
t = waveview->select_left;
1002
waveview->select_left = x1;
1003
gtk_wave_view_redraw_sample_area (waveview, x1, t - 1);
1005
if (x1 > waveview->select_left)
1007
t = waveview->select_left;
1008
waveview->select_left = x1;
1009
gtk_wave_view_redraw_sample_area (waveview, t, x1 - 1);
1011
if (x2 < waveview->select_right)
1013
t = waveview->select_right;
1014
waveview->select_right = x2;
1015
gtk_wave_view_redraw_sample_area(waveview, x2 + 1, t);
1017
if (x2 > waveview->select_right)
1019
t = waveview->select_right;
1020
waveview->select_right = x2;
1021
gtk_wave_view_redraw_sample_area(waveview, t + 1, x2);
1026
#define NEAR_SENSIVITY 3
1030
is_near_marker (GtkWaveView *waveview, gint32 x)
1032
if (waveview->marker < 0)
1037
win = calc_win_pel_pos(waveview, waveview->marker);
1038
return (x >= win - NEAR_SENSIVITY) &&
1039
(x <= win + NEAR_SENSIVITY);
1045
is_near_left_selection (GtkWaveView *waveview, gint32 x)
1047
if (waveview->select_right < waveview->select_left)
1052
win = calc_win_pel_pos(waveview, waveview->select_left);
1053
return (x >= win - NEAR_SENSIVITY) &&
1054
(x <= win + NEAR_SENSIVITY);
1060
is_near_right_selection (GtkWaveView *waveview, gint32 x)
1062
if (waveview->select_right < waveview->select_left)
1067
win = calc_win_pel_pos (waveview, waveview->select_right);
1068
return (x >= win - NEAR_SENSIVITY) &&
1069
(x <= win + NEAR_SENSIVITY);
1075
area_set_drag_cursor (GtkWaveView *waveview)
1077
if (!FLAG_IS_SET (waveview->drag_flags, FLAG_CURSOR_SET))
1079
gdk_window_set_cursor (waveview->area->window, waveview->drag_cursor);
1080
FLAG_SET (waveview->drag_flags, FLAG_CURSOR_SET);
1086
area_restore_normal_cursor (GtkWaveView *waveview)
1088
if (FLAG_IS_SET (waveview->drag_flags, FLAG_CURSOR_SET))
1090
gdk_window_set_cursor (waveview->area->window, waveview->normal_cursor);
1091
FLAG_UNSET (waveview->drag_flags, FLAG_CURSOR_SET);
1097
gtk_wave_view_button_press_event (GtkWidget *widget,
1098
GdkEventButton *event,
1101
GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
1104
if (waveview->wavebuffer == NULL)
1107
if (event->button != 1)
1110
gtk_grab_add (widget);
1112
frame = calc_frame_pos_win (waveview, event->x);
1113
FLAGS_CLEAR (waveview->drag_flags);
1114
if (is_near_marker (waveview, event->x) &&
1115
!FLAG_IS_SET (event->state, GDK_CONTROL_MASK))
1117
FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER);
1119
else if (is_near_right_selection (waveview, event->x))
1121
FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION);
1122
waveview->drag_start_point = waveview->select_left;
1124
else if (is_near_left_selection (waveview, event->x))
1126
FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION);
1127
waveview->drag_start_point = waveview->select_right;
1131
FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION);
1132
if (FLAG_IS_SET (event->state, GDK_SHIFT_MASK) &&
1133
waveview->marker >= 0)
1135
waveview->drag_start_point = waveview->marker;
1136
FLAG_SET (waveview->drag_flags, FLAG_DID_MOVE);
1137
gtk_wave_view_update_selection (waveview, waveview->drag_start_point,
1141
waveview->drag_start_point = frame;
1149
gtk_wave_view_button_release_event (GtkWidget *widget,
1153
GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
1156
gtk_grab_remove (widget);
1158
if (waveview->scroll_timeout != 0)
1160
gtk_timeout_remove (waveview->scroll_timeout);
1161
waveview->scroll_timeout = 0;
1164
if (event->type == GDK_BUTTON_RELEASE)
1167
GdkModifierType state;
1169
gdk_window_get_pointer (widget->window, &xint, &yint, &state);
1171
//x = ((GdkEventButton *)event)->x;
1176
GdkModifierType state;
1178
gdk_window_get_pointer (widget->window, &xint, &yint, &state);
1180
//x = ((GdkEventCrossing *)event)->x;
1183
/* dragging outside the border */
1184
if (x < 0 && GTK_ADJUSTMENT (waveview->adjust)->value >= 0.0)
1186
else if (x >= waveview->area->allocation.width)
1187
x = waveview->area->allocation.width /* - 1 no, round up this way */;
1189
frame = calc_frame_pos_win (waveview, x);
1192
if (waveview->wavebuffer && frame >= gtk_wave_buffer_get_length(waveview->wavebuffer))
1193
frame = gtk_wave_buffer_get_length(waveview->wavebuffer) - 1; /* correct for round up */
1195
if (FLAGS_IS_CLEAR (waveview->drag_flags))
1197
if (waveview->wavebuffer == NULL)
1199
FLAGS_CLEAR (waveview->drag_flags);
1202
if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER))
1204
gtk_wave_view_set_marker (waveview, frame);
1206
else if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION))
1208
if (FLAG_IS_SET (waveview->drag_flags, FLAG_DID_MOVE))
1210
gtk_wave_view_update_selection (waveview, waveview->drag_start_point,
1215
/* actually, it was a click */
1216
gtk_wave_view_set_marker (waveview, frame);
1219
area_restore_normal_cursor (waveview);
1220
FLAGS_CLEAR (waveview->drag_flags);
1225
motion_update (GtkWaveView *waveview, guint32 x)
1229
frame = calc_frame_pos_win (waveview, x);
1231
if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER))
1233
gtk_wave_view_set_marker (waveview, frame);
1234
area_set_drag_cursor (waveview);
1236
else if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION))
1238
FLAG_SET (waveview->drag_flags, FLAG_DID_MOVE);
1239
gtk_wave_view_update_selection (waveview, waveview->drag_start_point,
1241
area_set_drag_cursor (waveview);
1245
if (is_near_marker (waveview, x) ||
1246
is_near_left_selection (waveview, x) ||
1247
is_near_right_selection (waveview, x))
1249
area_set_drag_cursor (waveview);
1251
area_restore_normal_cursor (waveview);
1259
gtk_wave_view_scroll_notify (gpointer widget)
1261
GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
1262
GtkAdjustment *adjust = GTK_ADJUSTMENT (waveview->adjust);
1263
gint32 width, pos, frames;
1265
width = GTK_WIDGET (waveview)->allocation.width;
1266
pos = waveview->mouse_x;
1270
/* Scroll left (if possible). */
1272
frames = (gint32) (adjust->value - waveview->zoom * 32.0);
1273
frames = MAX (adjust->lower, frames);
1274
if (adjust->value > 0.0)
1277
else if (pos >= width)
1279
/* Scroll right (if possible). */
1280
frames = (gint32) (adjust->value + waveview->zoom * 32.0);
1281
frames = MIN (adjust->upper - adjust->page_size, frames);
1287
if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER))
1289
/* and now, something completely ugly ... A SHRUBBERY!
1290
* turn off the marker to reduce flicker while scrolling
1292
gtk_wave_view_set_marker (waveview, -1);
1293
gtk_adjustment_set_value (adjust, frames);
1294
/* motion update will turn the marker back on */
1295
motion_update (waveview, pos);
1299
gtk_adjustment_set_value (adjust, frames);
1300
motion_update (waveview, pos);
1308
gtk_wave_view_motion_notify_event (GtkWidget *widget,
1309
GdkEventMotion *event,
1312
GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
1315
if (waveview->wavebuffer == NULL)
1318
GTK_WIDGET_CLASS (GTK_OBJECT (waveview->hruler)->klass)->motion_notify_event (GTK_WIDGET (waveview->hruler), event);
1320
/* Get x coordinate on hint. */
1324
GdkModifierType state;
1326
gdk_window_get_pointer (widget->window, &xint, &yint, &state);
1332
motion_update (waveview, x);
1334
if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER) ||
1335
FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION))
1336
if (waveview->scroll_timeout == 0)
1337
waveview->scroll_timeout =
1338
gtk_timeout_add (50, gtk_wave_view_scroll_notify, waveview);
1340
waveview->mouse_x = x;
1346
gtk_wave_view_init (GtkWaveView *waveview)
1348
waveview->hruler = glame_hruler_new();
1349
glame_ruler_set_metric(GLAME_RULER(waveview->hruler),
1351
gtk_box_pack_start (GTK_BOX (waveview), waveview->hruler, FALSE, FALSE, 0);
1352
gtk_widget_show (waveview->hruler);
1354
waveview->area = gtk_drawing_area_new ();
1355
gtk_drawing_area_size (GTK_DRAWING_AREA (waveview->area), 150, 100);
1356
gtk_widget_show (waveview->area);
1357
gtk_box_pack_start (GTK_BOX (waveview), waveview->area, TRUE, TRUE, 0);
1358
gtk_widget_show (waveview->area);
1360
waveview->adjust = gtk_adjustment_new (0.0, 0.0, 10.0, 1.0, 1.0, 5.0);
1361
waveview->hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT (waveview->adjust));
1362
gtk_box_pack_start (GTK_BOX (waveview), waveview->hscroll, FALSE, FALSE, 0);
1363
gtk_widget_show (waveview->hscroll);
1365
gtk_signal_connect (GTK_OBJECT (waveview->adjust),
1366
"value_changed", gtk_wave_view_scroll,
1367
GTK_OBJECT (waveview));
1369
gtk_signal_connect (GTK_OBJECT (waveview),
1370
"size_allocate", gtk_wave_view_resize_event,
1371
GTK_OBJECT (waveview));
1373
gtk_signal_connect (GTK_OBJECT (waveview->area),
1374
"realize", on_area_realize,
1375
GTK_OBJECT (waveview));
1377
gtk_signal_connect (GTK_OBJECT (waveview->area),
1378
"expose_event", on_area_expose_event,
1379
GTK_OBJECT (waveview));
1381
gtk_signal_connect (GTK_OBJECT (waveview->area),
1382
"button_press_event", GTK_SIGNAL_FUNC (gtk_wave_view_button_press_event),
1383
GTK_OBJECT (waveview));
1385
gtk_signal_connect (GTK_OBJECT (waveview->area),
1386
"button_release_event", gtk_wave_view_button_release_event,
1387
GTK_OBJECT (waveview));
1389
gtk_signal_connect (GTK_OBJECT (waveview->area),
1390
"motion_notify_event", GTK_SIGNAL_FUNC (gtk_wave_view_motion_notify_event),
1391
GTK_OBJECT (waveview));
1393
gtk_widget_set_events (waveview->area, GDK_EXPOSURE_MASK |
1394
GDK_POINTER_MOTION_MASK |
1395
GDK_BUTTON_PRESS_MASK |
1396
GDK_BUTTON_RELEASE_MASK |
1397
GDK_BUTTON_MOTION_MASK |
1398
GDK_POINTER_MOTION_HINT_MASK |
1399
GDK_KEY_PRESS_MASK |
1400
GDK_KEY_RELEASE_MASK);
1402
waveview->wavebuffer = NULL;
1404
waveview->select_left = 0;
1405
waveview->select_right = -1;
1406
waveview->select_channels = 0xffffffff;
1408
waveview->drawn_offset = 0;
1409
waveview->drawing = 0;
1411
waveview->channels = NULL;
1412
waveview->n_channels = 0;
1413
waveview->cache_tag = NULL;
1414
waveview->invalidate = FALSE;
1416
waveview->zoom = 1.0;
1417
waveview->cache_size = 2048;
1418
waveview->ampl_zoom = 1.0;
1420
waveview->marker = -1;
1421
waveview->marker_scroll_stop = 0.0;
1422
waveview->marker_scroll_start = 0.0;
1424
waveview->drag_flags = 0;
1425
waveview->drag_start_point = -1;
1426
waveview->drag_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
1427
waveview->normal_cursor = gdk_cursor_new (GDK_LEFT_PTR);
1429
waveview->mouse_x = 0;
1430
waveview->scroll_timeout = 0;
1432
/* we can't initialize the gc here because the window's not realized yet */
1433
waveview->marker_gc = NULL;
1438
gtk_wave_view_set_amplitude_zoom (GtkWaveView *waveview, gdouble amplzoom)
1443
if (waveview->ampl_zoom != amplzoom)
1445
waveview->ampl_zoom = amplzoom;
1446
gtk_widget_queue_draw (GTK_WIDGET (waveview));
1452
gtk_wave_view_get_amplitude_zoom (GtkWaveView *waveview)
1454
return waveview->ampl_zoom;
1459
/* Verify selection is within the data bounds, otherwise fix it and
1460
repaint as necessary. */
1462
gtk_wave_view_check_selection (GtkWaveView *waveview)
1467
length = gtk_wave_buffer_get_length (waveview->wavebuffer);
1470
if (waveview->select_left >= length)
1473
waveview->select_left = length - 1;
1476
if (waveview->select_right >= length)
1479
waveview->select_right = length - 1;
1483
gtk_widget_queue_draw (waveview->area);
1489
gtk_wave_view_invalidate_range (GtkWaveView *waveview, guint32 start, guint32 length)
1491
if (!waveview->invalidate)
1493
waveview->invalidate = TRUE;
1494
waveview->invalidate_start = start;
1495
waveview->invalidate_stop = start + length - 1;
1499
waveview->invalidate_start = MIN (waveview->invalidate_start, start);
1500
waveview->invalidate_stop = MAX (waveview->invalidate_stop, start + length - 1);
1506
on_wave_buffer_modified (GtkWaveView *widget, GRange *range)
1508
GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
1510
if (waveview->wavebuffer == NULL)
1513
gtk_wave_view_invalidate_range (waveview, range->left, range->right - range->left + 1);
1514
gtk_wave_view_redraw_sample_area (waveview, range->left, range->right);
1519
on_wave_buffer_insert_data (GtkWidget *widget, GRange *range)
1521
GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
1524
width = range->right - range->left + 1;
1526
if (waveview->marker >= range->left)
1527
waveview->marker += width;
1529
if (waveview->select_right >= range->left)
1530
waveview->select_right += width;
1532
if (waveview->select_left >= range->left)
1533
waveview->select_left += width;
1535
gtk_wave_view_update_units (waveview);
1540
on_wave_buffer_delete_data (GtkWidget *widget, GRange *range)
1542
GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
1545
width = range->right - range->left + 1;
1547
if (waveview->marker > range->right)
1548
waveview->marker -= width;
1549
else if (waveview->marker >= range->left)
1550
waveview->marker = -1;
1552
if (waveview->select_left > range->right)
1553
waveview->select_left -= width;
1554
else if (waveview->select_right >= range->left)
1555
waveview->select_left = range->left;
1557
if (waveview->select_right > range->right)
1558
waveview->select_right -= width;
1559
else if (waveview->select_right >= range->left)
1560
waveview->select_right = range->left - 1;
1562
gtk_wave_view_update_units (waveview);
1567
gtk_wave_view_get_buffer (GtkWaveView *waveview)
1569
return waveview->wavebuffer;
1573
/* Select a new data stream, ref() it, invalidate cache, and update screen. */
1575
gtk_wave_view_set_buffer (GtkWaveView *waveview, GtkWaveBuffer *wavebuffer)
1577
if (waveview->wavebuffer == wavebuffer)
1580
gtk_wave_view_cache_free (waveview);
1581
g_free (waveview->channels);
1583
if (waveview->wavebuffer != NULL)
1585
if (GTK_IS_EDITABLE_WAVE_BUFFER (waveview->wavebuffer))
1587
gtk_signal_disconnect (GTK_OBJECT (waveview->wavebuffer),
1588
waveview->modified_connection);
1589
gtk_signal_disconnect (GTK_OBJECT (waveview->wavebuffer),
1590
waveview->insert_data_connection);
1591
gtk_signal_disconnect (GTK_OBJECT (waveview->wavebuffer),
1592
waveview->delete_data_connection);
1595
gtk_object_unref (GTK_OBJECT (waveview->wavebuffer));
1598
waveview->wavebuffer = wavebuffer;
1600
if (wavebuffer != NULL)
1602
gtk_object_ref (GTK_OBJECT (waveview->wavebuffer));
1603
gtk_object_sink (GTK_OBJECT (waveview->wavebuffer));
1605
if (GTK_IS_EDITABLE_WAVE_BUFFER (waveview->wavebuffer))
1607
waveview->modified_connection =
1608
gtk_signal_connect_object (GTK_OBJECT (waveview->wavebuffer),
1610
GTK_SIGNAL_FUNC (on_wave_buffer_modified),
1611
GTK_OBJECT (waveview));
1613
waveview->insert_data_connection =
1614
gtk_signal_connect_object (GTK_OBJECT (waveview->wavebuffer),
1616
GTK_SIGNAL_FUNC (on_wave_buffer_insert_data),
1617
GTK_OBJECT (waveview));
1619
waveview->delete_data_connection =
1620
gtk_signal_connect_object (GTK_OBJECT (waveview->wavebuffer),
1622
GTK_SIGNAL_FUNC (on_wave_buffer_delete_data),
1623
GTK_OBJECT (waveview));
1626
waveview->n_channels = gtk_wave_buffer_get_num_channels (waveview->wavebuffer);
1627
waveview->channels = g_new (GtkWaveViewChannelInfo, waveview->n_channels);
1629
waveview->select_left = 0;
1630
waveview->select_right = gtk_wave_buffer_get_length (waveview->wavebuffer) - 1;
1631
waveview->marker = 0;
1633
gtk_wave_view_cache_create (waveview);
1637
waveview->channels = NULL;
1638
waveview->cache_tag = NULL;
1639
waveview->n_channels = 0;
1640
waveview->marker = -1;
1643
gtk_widget_queue_draw (GTK_WAVE_VIEW (waveview)->area);
1644
gtk_wave_view_update_units (waveview);
1645
gtk_wave_view_calc_channel_locs (waveview);
1649
/* return < 0 means no further action necessary
1650
* return > 0 means further action necessary
1653
check_marker (GtkWaveView *waveview,
1656
gint32 *win_pos_new_marker)
1658
gint32 win_pos_old_marker;
1660
if (waveview->wavebuffer == NULL)
1663
if (!GTK_WIDGET_REALIZED (waveview->area))
1665
waveview->marker = *frame;
1672
* neat trick: because the marker is drawn with GDK_XOR
1673
* we can restore the original frame(s) by drawing it again.
1675
if (waveview->marker >= 0)
1676
gtk_wave_view_draw_marker (waveview);
1677
waveview->marker = -1;
1681
*length = gtk_wave_buffer_get_length (waveview->wavebuffer);
1682
if (*frame >= *length)
1685
win_pos_old_marker = calc_win_pel_pos (waveview, waveview->marker);
1686
*win_pos_new_marker = calc_win_pel_pos (waveview, *frame);
1688
if (*win_pos_new_marker == win_pos_old_marker)
1690
waveview->marker = *frame;
1699
gtk_wave_view_set_marker (GtkWaveView *waveview, gint32 frame)
1701
gint32 length, win_pos_new;
1703
if (check_marker (waveview, &frame, &length, &win_pos_new) > 0)
1705
draw_marker_from_frame_pos (waveview, frame);
1706
if (waveview->marker >= 0)
1707
draw_marker_from_frame_pos (waveview, waveview->marker);
1708
waveview->marker = frame;
1714
gtk_wave_view_set_marker_scrolling_boundaries (GtkWaveView *waveview,
1715
gdouble stop_threshold,
1716
gdouble start_offset)
1718
/* sanity checking on data */
1719
if (stop_threshold < 0.0 || stop_threshold > 1.0)
1721
/* scroll when arriving at the outermost visible frame */
1722
stop_threshold = 1.0;
1724
if (start_offset < 0.0 || start_offset > 1.0)
1726
/* set the new position at the first visible frame */
1729
if (start_offset + stop_threshold > 1.0)
1731
/* this will drive ya nuts!
1732
* Should have provided some decent parameters!
1734
start_offset = 1.0 - stop_threshold;
1736
waveview->marker_scroll_stop = stop_threshold;
1737
waveview->marker_scroll_start = start_offset;
1741
scroll_and_draw_marker (GtkWaveView *waveview,
1745
gdouble start_offset)
1747
GtkAdjustment *adj = GTK_ADJUSTMENT (waveview->adjust);
1748
gint32 frame_offset, max_offset;
1750
max_offset = wave_length - (win_width * waveview->zoom) - 1;
1751
max_offset = MAX (max_offset, 0);
1753
frame_offset = win_width * waveview->zoom * start_offset;
1754
frame_offset = frame - frame_offset;
1755
frame_offset = MAX (frame_offset, 0);
1756
frame_offset = MIN (frame_offset, max_offset);
1758
/* this will do the scrolling for us */
1759
gtk_adjustment_set_value (adj, frame_offset);
1761
/* remove the old marker, and draw the new one */
1762
draw_marker_from_frame_pos (waveview, waveview->marker);
1763
draw_marker_from_frame_pos (waveview, frame);
1765
gtk_wave_view_update_units (waveview);
1770
gtk_wave_view_set_marker_and_scroll (GtkWaveView *waveview,
1773
gint32 win_pos_new, width, length;
1776
if (check_marker (waveview, &frame, &length, &win_pos_new) < 0)
1778
/* no action necessary */
1779
/* WRONG! we might still need to scroll... return; */
1782
width = waveview->area->allocation.width;
1784
/* calculate the amount of scroll */
1785
if (win_pos_new < 0 ||
1786
(frame > waveview->marker &&
1787
win_pos_new > width * (1.0 - waveview->marker_scroll_stop)))
1789
/* we're moving to the right */
1790
scroll_and_draw_marker (waveview, frame, width, length,
1791
waveview->marker_scroll_start);
1793
else if (win_pos_new >= width ||
1794
(frame < waveview->marker &&
1795
win_pos_new < width * waveview->marker_scroll_stop))
1797
/* we're moving to the left */
1798
scroll_and_draw_marker (waveview, frame, width, length,
1799
1.0 - waveview->marker_scroll_start);
1803
/* redraw the marker */
1804
draw_marker_from_frame_pos (waveview, waveview->marker);
1805
draw_marker_from_frame_pos (waveview, frame);
1808
/* set the new marker */
1809
waveview->marker = frame;
1813
gint32 gtk_wave_view_get_marker (GtkWaveView *waveview)
1815
return waveview->marker;
1819
/* Return zoom factor. */
1821
gtk_wave_view_get_zoom (GtkWaveView *waveview)
1823
return waveview->zoom;
1827
/* Set zoom. zoom = # of samples per pixel, must be >= 1.0 */
1829
gtk_wave_view_set_zoom (GtkWaveView *waveview,
1835
if (waveview->area && waveview->wavebuffer) {
1839
if (GTK_WIDGET_REALIZED (waveview->area))
1840
length = GTK_WIDGET (waveview->area)->allocation.width;
1842
length = GTK_WIDGET (waveview->area)->requisition.width;
1843
max_zoom = (gdouble)gtk_wave_buffer_get_length(waveview->wavebuffer)/(gdouble)length;
1845
if (zoom > max_zoom)
1849
if (waveview->zoom != zoom)
1851
waveview->zoom = zoom;
1853
gtk_wave_view_cache_invalidate (waveview);
1854
gtk_wave_view_update_units (waveview);
1855
gtk_widget_queue_draw (GTK_WIDGET (waveview));
1860
/* Zoom whole screen. */
1862
gtk_wave_view_set_zoom_all (GtkWaveView *waveview)
1864
if (waveview->wavebuffer != NULL)
1868
if (GTK_WIDGET_REALIZED (waveview->area))
1869
length = GTK_WIDGET (waveview->area)->allocation.width;
1871
length = GTK_WIDGET (waveview->area)->requisition.width;
1873
gtk_wave_view_set_zoom (waveview, ((gdouble) gtk_wave_buffer_get_length (waveview->wavebuffer)) / length);
1878
/* Set zoom to selection (if there is one). */
1880
gtk_wave_view_set_zoom_selection (GtkWaveView *waveview)
1882
if (waveview->select_left <= waveview->select_right)
1885
GtkAdjustment *adj = GTK_ADJUSTMENT (waveview->adjust);
1887
zoom = ((gdouble) (waveview->select_right - waveview->select_left + 1)) / waveview->area->allocation.width;
1889
gtk_wave_view_set_zoom (waveview, zoom);
1891
if (adj->value != waveview->select_left)
1893
adj->value = waveview->select_left;
1894
gtk_wave_view_update_units (waveview);
1895
gtk_widget_queue_draw (waveview->area);
1901
/* Return selection. Length = 0 if nothing is selected. */
1903
gtk_wave_view_get_selection (GtkWaveView *waveview,
1907
*start = waveview->select_left;
1909
if (waveview->select_left <= waveview->select_right)
1910
*length = waveview->select_right - waveview->select_left + 1;
1916
/* Set selection and refresh screen. */
1918
gtk_wave_view_set_selection (GtkWaveView *waveview,
1922
waveview->select_left = start;
1923
waveview->select_right = start + length - 1;
1925
gtk_widget_queue_draw (waveview->area);
1930
gtk_wave_view_get_select_channels (GtkWaveView *waveview)
1932
return waveview->select_channels;
1937
gtk_wave_view_set_select_channels (GtkWaveView *waveview,
1940
waveview->select_channels = sel_mask;
1941
gtk_widget_queue_draw (waveview->area);
1946
gtk_wave_view_set_cache_size (GtkWaveView *waveview,
1952
if (waveview->cache_size != size)
1954
gtk_wave_view_cache_free (waveview);
1955
waveview->cache_size = size;
1956
gtk_wave_view_cache_create (waveview);
1957
gtk_wave_view_cache_invalidate (waveview);