~ubuntu-branches/ubuntu/utopic/glame/utopic

« back to all changes in this revision

Viewing changes to src/gui/libgtkwaveform/gtkwaveview.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2002-04-09 17:14:12 UTC
  • Revision ID: james.westby@ubuntu.com-20020409171412-jzpnov7mbz2w6zsr
Tags: upstream-0.6.2
ImportĀ upstreamĀ versionĀ 0.6.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gtkwaveview.c: Gtk+ widget for displaying data
 
2
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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.
 
17
 */
 
18
 
 
19
/* Amplitude zoom, selection, and marker code by
 
20
 * Ben De Rydt <ben.de.rydt@pandora.be>
 
21
 *
 
22
 * Documentation for the selection resize algorithm is in
 
23
 * docs/drag_algorithm.txt
 
24
 */
 
25
 
 
26
#include <gtk/gtk.h>
 
27
#include "util/glame_hruler.h"
 
28
#include "gtkwaveview.h"
 
29
#include "gtkeditablewavebuffer.h"
 
30
#include "grange.h"
 
31
#include "util.h"
 
32
 
 
33
 
 
34
/* Stuff for new ruler.
 
35
 */
 
36
 
 
37
static gchar *time_metric_translate(gdouble value)
 
38
{
 
39
  gint minutes;
 
40
  gdouble seconds;
 
41
 
 
42
  minutes = ((gint) (value / 60.0));
 
43
  seconds = value - (((gint)value) / 60) * 60;
 
44
 
 
45
  return g_strdup_printf ("%02d:%02.3f", minutes, seconds);
 
46
}
 
47
 
 
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 },
 
55
  time_metric_translate
 
56
};
 
57
 
 
58
static gchar *frame_metric_translate (gdouble value)
 
59
{
 
60
  return g_strdup_printf ("%li", (long) value);
 
61
}
 
62
 
 
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
 
70
};
 
71
 
 
72
 
 
73
 
 
74
 
 
75
static void gtk_wave_view_class_init    (GtkWaveViewClass *klass);
 
76
static void gtk_wave_view_init          (GtkWaveView      *waveview);
 
77
 
 
78
 
 
79
static GtkVBoxClass *parent_class;
 
80
 
 
81
 
 
82
/*
 
83
   Info on units used in this widget:
 
84
 
 
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.
 
89
 
 
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.
 
93
 
 
94
    * Pel x units relative to start of data stream (ext_pel_pos)
 
95
        Used by the cache to keep track of recently calculated
 
96
        data.
 
97
 
 
98
   Mathematical representation of how to convert between unit forms:
 
99
     frame units =
 
100
       pel x units relative to start of data stream * zoom
 
101
 
 
102
   Where zoom >= 1.0.  zoom is in units of samples per pixel
 
103
 
 
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!
 
111
*/
 
112
 
 
113
 
 
114
GtkType
 
115
gtk_wave_view_get_type (void)
 
116
{
 
117
  static GtkType waveview_type = 0;
 
118
  
 
119
  if (!waveview_type)
 
120
    {
 
121
      static const GtkTypeInfo waveview_info =
 
122
      {
 
123
        "GtkWaveView",
 
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,
 
131
      };
 
132
      
 
133
      waveview_type = gtk_type_unique (GTK_TYPE_VBOX, &waveview_info);
 
134
    }
 
135
  
 
136
  return waveview_type;
 
137
}
 
138
 
 
139
 
 
140
GtkWidget *
 
141
gtk_wave_view_new (void)
 
142
{
 
143
  GtkWaveView *waveview;
 
144
  
 
145
  waveview = gtk_type_new (GTK_TYPE_WAVEFORM);
 
146
  waveview->drawing = 0;
 
147
  waveview->destroyed = 0;
 
148
 
 
149
  return GTK_WIDGET (waveview);
 
150
}
 
151
 
 
152
 
 
153
static void
 
154
gtk_wave_view_real_destroy (GtkObject *obj)
 
155
{
 
156
  GtkWaveView *waveview = GTK_WAVE_VIEW (obj);
 
157
 
 
158
  /* Dont allow destroying, if we have pending drawing events. */
 
159
  if (waveview->drawing) {
 
160
          DPRINTF("NOT destroying.\n");
 
161
          waveview->destroyed = 1;
 
162
          return;
 
163
  }
 
164
 
 
165
  if (waveview->wavebuffer != NULL)
 
166
    gtk_wave_view_set_buffer (waveview, NULL);
 
167
 
 
168
  gdk_cursor_destroy (waveview->drag_cursor);
 
169
  gdk_cursor_destroy (waveview->normal_cursor);
 
170
 
 
171
  if (waveview->marker_gc != NULL)
 
172
    gdk_gc_unref (waveview->marker_gc);
 
173
 
 
174
  GTK_OBJECT_CLASS (parent_class)->destroy (obj); 
 
175
}
 
176
 
 
177
 
 
178
static void
 
179
gtk_wave_view_class_init (GtkWaveViewClass *klass)
 
180
{
 
181
  GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
 
182
 
 
183
  parent_class = gtk_type_class (gtk_vbox_get_type ());
 
184
  object_class->destroy = gtk_wave_view_real_destroy;
 
185
}
 
186
 
 
187
 
 
188
/* Unit conversion functions */
 
189
 
 
190
static guint32
 
191
calc_scrn_y (gint32 top, gint32 height, gint16 mag, gdouble ampl_zoom)
 
192
{
 
193
  gint32 pos;
 
194
 
 
195
  pos = (guint32) (top + (height * 0.5) + \
 
196
                  (height * mag * ampl_zoom) / 65535.0);
 
197
 
 
198
  pos = MIN (MAX (pos, top), top + height - 1);
 
199
 
 
200
  return pos;
 
201
}
 
202
 
 
203
 
 
204
static gint32
 
205
calc_win_pel_pos (GtkWaveView *waveview, gint32 frame_pos)
 
206
{
 
207
  return ((gint32) (frame_pos / waveview->zoom)) - ((gint32) (GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom));
 
208
}
 
209
 
 
210
 
 
211
static gint32
 
212
calc_ext_pel_pos (GtkWaveView *waveview, gint32 frame_pos)
 
213
{
 
214
  return (gint32) (frame_pos / waveview->zoom);
 
215
}
 
216
 
 
217
 
 
218
static gint32
 
219
calc_win_pel_ext (GtkWaveView *waveview, gint32 ext_pel_pos)
 
220
{
 
221
  return ext_pel_pos - ((gint32)(GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom));
 
222
}
 
223
 
 
224
static gint32
 
225
calc_ext_pel_win (GtkWaveView *waveview, gint32 win_pel_pos)
 
226
{
 
227
  return win_pel_pos + ((gint32)(GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom));
 
228
}
 
229
 
 
230
 
 
231
static gint32
 
232
calc_frame_pos_ext (GtkWaveView *waveview, gint32 ext_pel_pos)
 
233
{
 
234
  return (gint32) (ext_pel_pos * waveview->zoom);
 
235
}
 
236
 
 
237
 
 
238
static gint32
 
239
calc_frame_pos_win (GtkWaveView *waveview, gint32 win_pel_pos)
 
240
{
 
241
        return (((gint32) GTK_ADJUSTMENT (waveview->adjust)->value / waveview->zoom) + win_pel_pos) * waveview->zoom;
 
242
}
 
243
 
 
244
 
 
245
/* Cache functions */
 
246
 
 
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);
 
253
 
 
254
 
 
255
static void
 
256
gtk_wave_view_cache_free (GtkWaveView *waveview)
 
257
{
 
258
  gint32 i;
 
259
 
 
260
  for (i = 0; i < waveview->n_channels; i++)
 
261
    {
 
262
      g_free (waveview->channels [i].cache);
 
263
      waveview->channels [i].cache = NULL;
 
264
    }
 
265
 
 
266
  g_free (waveview->cache_tag);
 
267
  waveview->cache_tag = NULL;
 
268
}
 
269
 
 
270
 
 
271
static void
 
272
gtk_wave_view_cache_create (GtkWaveView *waveview)
 
273
{
 
274
  gint32 i;
 
275
 
 
276
  if (waveview->wavebuffer == NULL)
 
277
    return;
 
278
 
 
279
  waveview->cache_tag = g_new (gint32, waveview->cache_size);
 
280
 
 
281
  for (i = 0; i < waveview->n_channels; i++)
 
282
    waveview->channels[i].cache = g_new (GtkWaveViewCacheEntry, waveview->cache_size);
 
283
 
 
284
  gtk_wave_view_cache_invalidate (waveview);
 
285
}
 
286
 
 
287
 
 
288
static void
 
289
gtk_wave_view_cache_add (GtkWaveView *waveview, guint32 x, gint16 *min, gint16 *max)
 
290
{
 
291
  guint32 i, size, offset;
 
292
  GtkWaveViewCacheEntry *e;
 
293
 
 
294
  size = waveview->cache_size;
 
295
  offset = x % size;
 
296
 
 
297
  /* Mmmm... direct mapped cache. */
 
298
  waveview->cache_tag [offset] = x;
 
299
  
 
300
  for (i = 0; i < waveview->n_channels; i++)
 
301
    {
 
302
      e = &waveview->channels [i].cache [offset];
 
303
      e->min = min [i];
 
304
      e->max = max [i];
 
305
 
 
306
      min [i] = max [i] = 0;
 
307
    }
 
308
}
 
309
 
 
310
 
 
311
static gint
 
312
gtk_wave_view_cache_paint (GtkWaveView *waveview, gint32 offset, gint32 x)
 
313
{
 
314
  GdkGC *gc;
 
315
  guint32 size, cache_offset;
 
316
 
 
317
  if (waveview->wavebuffer == NULL)
 
318
    return 0;
 
319
 
 
320
  size = waveview->cache_size;
 
321
  cache_offset = (offset + x) % size;
 
322
 
 
323
  /* Is this x coordinate cached? */
 
324
  if (waveview->cache_tag [cache_offset] == offset + x)
 
325
    {
 
326
      guint32 i;
 
327
      gint l_pos, r_pos;
 
328
 
 
329
      l_pos = calc_win_pel_pos (waveview, waveview->select_left);
 
330
      r_pos = calc_win_pel_pos (waveview, waveview->select_right);
 
331
 
 
332
      for (i = 0; i < waveview->n_channels; i++)
 
333
        {
 
334
          GtkWaveViewCacheEntry *e;
 
335
          gint32        min, max;
 
336
          guint32       top, height;
 
337
 
 
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;
 
342
 
 
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);
 
346
 
 
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];
 
350
          else
 
351
            gc = waveview->area->style->fg_gc [GTK_STATE_ACTIVE];
 
352
 
 
353
          gdk_draw_line (waveview->area->window, gc, x, min, x, max);
 
354
        }
 
355
 
 
356
      return 1;
 
357
    }
 
358
 
 
359
  return 0;
 
360
}
 
361
 
 
362
 
 
363
static void
 
364
gtk_wave_view_cache_invalidate (GtkWaveView *waveview)
 
365
{
 
366
  gint32 i;
 
367
 
 
368
  if (waveview->wavebuffer == NULL)
 
369
    return;
 
370
 
 
371
  for (i = 0; i < waveview->cache_size; i++)
 
372
    waveview->cache_tag [i] = -1;
 
373
}
 
374
 
 
375
 
 
376
static void
 
377
gtk_wave_view_cache_invalidate_range (GtkWaveView *waveview, gint32 start, gint32 length)
 
378
{
 
379
  gint32 i;
 
380
 
 
381
  if (waveview->wavebuffer == NULL)
 
382
    return;
 
383
 
 
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;
 
388
}
 
389
 
 
390
 
 
391
/* Update ruler and scrollbar units. */
 
392
static void
 
393
gtk_wave_view_update_units (GtkWaveView *waveview)
 
394
{
 
395
  GtkAdjustment *adj;
 
396
  gdouble length, rate;
 
397
  guint32 width;
 
398
  gint32 j;
 
399
 
 
400
  adj = GTK_ADJUSTMENT (waveview->adjust);
 
401
 
 
402
  if (waveview->wavebuffer == NULL)
 
403
    {
 
404
      adj->lower = 0.0;
 
405
      adj->upper = 0.0;
 
406
      adj->value = 0.0;
 
407
      gtk_adjustment_changed (adj);
 
408
      glame_ruler_set_range (GLAME_RULER(waveview->hruler), 0.0, 0.0, 0.0, 20.0);
 
409
      return;
 
410
    }
 
411
 
 
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;
 
415
 
 
416
  /* Set scrollbar in pixel units. */
 
417
  adj->lower = 0.0;
 
418
  adj->upper = length;
 
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;
 
423
 
 
424
  if (adj->value > adj->upper - adj->page_size)
 
425
    {
 
426
      adj->value = adj->upper - adj->page_size;
 
427
      if (adj->value < 0.0)
 
428
        adj->value = 0.0;
 
429
    }
 
430
 
 
431
  gtk_adjustment_changed (adj);
 
432
 
 
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. */
 
436
 
 
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,
 
441
                         0.0, 1000.0);
 
442
/* for frames
 
443
  glame_ruler_set_range (GLAME_RULER(waveview->hruler),
 
444
                         calc_frame_pos_ext (waveview, j),
 
445
                         calc_frame_pos_ext (waveview, j + width),
 
446
                         0.0, 1000.0); */
 
447
}
 
448
 
 
449
 
 
450
/* The crusty stuff to redraw all the channels of a waveview. */
 
451
static void
 
452
gtk_wave_view_redraw_wave (GtkWaveView *waveview)
 
453
{
 
454
  GWavefileType datatype;
 
455
  guint32   n_samples, n_channels;
 
456
  guint32   i, j, width, start_x, offset;
 
457
  gint16    max_val, min_val;
 
458
 
 
459
  if (waveview->wavebuffer == NULL)
 
460
    return;
 
461
 
 
462
  if (waveview->invalidate)
 
463
    {
 
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));
 
468
    }
 
469
 
 
470
  min_val = -1;
 
471
 
 
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));
 
476
 
 
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) {
 
481
      if (min_val == -1)
 
482
        min_val = max_val = i;
 
483
      else
 
484
        max_val = i;
 
485
    }
 
486
 
 
487
  if (min_val != -1)
 
488
    {
 
489
      gint16    max [waveview->n_channels], min [waveview->n_channels];
 
490
      guint32   sample_offset, last_sample_offset, pos, size;
 
491
      guint32   accum, count, delta;
 
492
      guint32   pos16;
 
493
      gpointer  data;
 
494
      gint16   *data16;
 
495
 
 
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;
 
499
 
 
500
      datatype = gtk_wave_buffer_get_datatype (waveview->wavebuffer);
 
501
 
 
502
#define REDRAW_BUFFER 8192
 
503
      /* Allocate some temp space. */
 
504
      data = g_malloc (g_wavefile_type_width (datatype) * n_channels * REDRAW_BUFFER);
 
505
 
 
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);
 
510
      else
 
511
        data16 = (gint16*) data;
 
512
 
 
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);
 
516
 
 
517
      n_samples = gtk_wave_buffer_get_length (waveview->wavebuffer);
 
518
 
 
519
      /* Perform clipping. */
 
520
      if (sample_offset >= n_samples)
 
521
        return;
 
522
      if (last_sample_offset >= n_samples)
 
523
        last_sample_offset = n_samples - 1;
 
524
 
 
525
      for (j = 0; j < waveview->n_channels; j++)
 
526
        min[j] = max[j] = 0;
 
527
 
 
528
      pos = sample_offset;
 
529
      accum = 1073741824U; /* 2147483648 / 2, round to nearest unit */
 
530
      count = 0;
 
531
      delta = (guint32) (2147483648.0 / waveview->zoom);
 
532
      while (pos <= last_sample_offset)
 
533
        {
 
534
          size = MIN (REDRAW_BUFFER, last_sample_offset - pos + 1);
 
535
 
 
536
          /* If by any chance we got destroyed, bail out. */
 
537
          if (waveview->destroyed) {
 
538
                  DPRINTF("Whoops - coalesced with destroy event :)\n");
 
539
                  return;
 
540
          }
 
541
 
 
542
          /* Read data chunk. */
 
543
          gtk_wave_buffer_get_samples (waveview->wavebuffer, pos, size, 0xffffffff, data);
 
544
 
 
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);
 
548
 
 
549
          pos16 = 0;
 
550
          for (i = 0; i < size; i++)
 
551
            {
 
552
              /* For each sample of a track, keep min and max values. */
 
553
              for (j = 0; j < n_channels; j++)
 
554
                {
 
555
                  gint16 val = data16[pos16++];
 
556
 
 
557
                  if (val < min[j]) min[j] = val;
 
558
                  if (val > max[j]) max[j] = val;
 
559
                }
 
560
 
 
561
              /* Do Bresenham's algorithm */
 
562
              accum += delta;
 
563
 
 
564
              if (accum >= 2147483648U)
 
565
                {
 
566
                  accum -= 2147483648U;
 
567
 
 
568
                  gtk_wave_view_cache_add (waveview, offset + min_val + count, min, max);
 
569
                  gtk_wave_view_cache_paint (waveview, offset, min_val + count);
 
570
 
 
571
                  count++;
 
572
                }
 
573
            }
 
574
 
 
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();
 
580
 
 
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;
 
590
                          }
 
591
                          if (notdone_x + notdone_width > waveview->expose_x + waveview->expose_width)
 
592
                                  waveview->expose_width = notdone_x + notdone_width - waveview->expose_x;
 
593
                          return;
 
594
                  }
 
595
          }
 
596
 
 
597
          /* Increment position in data source. */
 
598
          pos += size;
 
599
        }
 
600
 
 
601
      if (data16 != (void*) data)
 
602
        g_free (data16);
 
603
 
 
604
      g_free (data);
 
605
    }
 
606
}
 
607
 
 
608
 
 
609
/* Fill rectangle (x1, y) -> (x2, y + height - 1), clip if necessary. */
 
610
static void
 
611
fill_rect (GdkWindow *win, GdkGC *gc, gint32 win_width, gint32 x1, gint32 x2, gint32 y, gint32 height)
 
612
{
 
613
  /* Clipping and stuff.. */
 
614
  if (x1 > x2 || x2 < 0 || x1 >= win_width) return;
 
615
 
 
616
  if (x1 < 0) x1 = 0;
 
617
  if (x2 >= win_width) x2 = win_width - 1;
 
618
 
 
619
  gdk_draw_rectangle (win, gc, TRUE, x1, y, x2 - x1 + 1, height);
 
620
}
 
621
 
 
622
static void
 
623
draw_marker_from_frame_pos (GtkWaveView *waveview, gint32 frame)
 
624
{
 
625
  gint32 win_pos;
 
626
  
 
627
  win_pos = calc_win_pel_pos (waveview, frame);
 
628
  if (win_pos >= 0 && win_pos < waveview->area->allocation.width)
 
629
    {
 
630
      gint32 i;
 
631
      for (i = 0; i < waveview->n_channels; i++)
 
632
        {
 
633
          gint32 top, height;
 
634
 
 
635
          top = waveview->channels[i].top;
 
636
          height = waveview->channels[i].height;
 
637
 
 
638
          gdk_draw_line (waveview->area->window, waveview->marker_gc,
 
639
                         win_pos, top, win_pos, top + height - 1);
 
640
        }
 
641
    }
 
642
}
 
643
 
 
644
 
 
645
static void
 
646
gtk_wave_view_draw_marker (GtkWaveView *waveview)
 
647
{
 
648
  if (waveview->marker < 0)
 
649
    return;
 
650
  if (!GTK_WIDGET_REALIZED (waveview->area))
 
651
    return;
 
652
  draw_marker_from_frame_pos (waveview, waveview->marker);
 
653
}
 
654
 
 
655
 
 
656
/* Redraw the region between two window x coordinates inclusive. */
 
657
static void
 
658
gtk_wave_view_redraw_area (GtkWaveView *waveview, gint32 x1, gint32 x2)
 
659
{
 
660
  /* Reverse x1 and x2, if backwards. */
 
661
  if (x1 > x2)
 
662
    {
 
663
      guint32 t;
 
664
      t = x1; x1 = x2; x2 = t;
 
665
    }
 
666
 
 
667
  /* Perform clipping. */
 
668
  if (x2 < 0) return;
 
669
  if (x1 >= waveview->area->allocation.width) return;
 
670
 
 
671
  if (x1 < 0)
 
672
    x1 = 0;
 
673
  if (x2 >= waveview->area->allocation.width)
 
674
    x2 = waveview->area->allocation.width - 1;
 
675
 
 
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);
 
679
}
 
680
 
 
681
 
 
682
/* Redraw the range between two *sample* #s, inclusive. */
 
683
static void
 
684
gtk_wave_view_redraw_sample_area (GtkWaveView *waveview, gint32 pos1, gint32 pos2)
 
685
{
 
686
  gint32 x1, x2;
 
687
 
 
688
  x1 = calc_win_pel_pos (waveview, pos1);
 
689
  x2 = calc_win_pel_pos (waveview, pos2);
 
690
 
 
691
  gtk_wave_view_redraw_area (waveview, x1, x2);
 
692
}
 
693
 
 
694
 
 
695
static void
 
696
on_area_realize (GtkWidget *widget, gpointer userdata)
 
697
{
 
698
  GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
 
699
 
 
700
  if (waveview->marker_gc == NULL)
 
701
    {
 
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);
 
705
    }
 
706
  gdk_gc_set_exposures(waveview->area->style->bg_gc [GTK_STATE_NORMAL],TRUE);
 
707
}
 
708
 
 
709
 
 
710
/* Paint selection areas then call a function to paint the wave data. */
 
711
static void
 
712
on_area_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer userdata)
 
713
{
 
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;
 
719
 
 
720
  /* Accumulate expose events. */
 
721
  expose_x = calc_ext_pel_win(waveview, event->area.x);
 
722
  expose_width = event->area.width;
 
723
 
 
724
  if (waveview->expose_count == 0) {
 
725
          waveview->expose_x = expose_x;
 
726
          waveview->expose_width = expose_width;
 
727
  } else {
 
728
          if (expose_x < waveview->expose_x) {
 
729
                  waveview->expose_width += waveview->expose_x - expose_x;
 
730
                  waveview->expose_x = expose_x;
 
731
          }
 
732
          if (expose_x + expose_width > waveview->expose_x + waveview->expose_width)
 
733
                  waveview->expose_width = expose_x + expose_width - waveview->expose_x;
 
734
  }
 
735
 
 
736
  waveview->expose_count++;
 
737
 
 
738
  if (event->count > 0 || waveview->drawing)
 
739
    return;
 
740
 
 
741
  waveview->drawing = 1;
 
742
 again:
 
743
  /* Done accumulating sequential expose events, now process them. */
 
744
  waveview->expose_count = 0;
 
745
 
 
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)
 
750
    {
 
751
      gint32 i, j, k;
 
752
      guint32 n_channels;
 
753
      guint32 top, height, width;
 
754
      GdkWindow *window;
 
755
      long exp_win_x;
 
756
 
 
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);
 
760
      frame_area.y = 0;
 
761
      frame_area.height = widget->allocation.height;
 
762
 
 
763
      /* hide marker */
 
764
      gtk_wave_view_draw_marker (waveview);
 
765
 
 
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);
 
775
 
 
776
      n_channels = gtk_wave_buffer_get_num_channels (waveview->wavebuffer);
 
777
      width = widget->allocation.width;
 
778
      window = widget->window;
 
779
 
 
780
      /* Draw seperator bars. */
 
781
      for (i = 1; i < n_channels; i++)
 
782
        {
 
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);
 
787
        }
 
788
 
 
789
      for (i = 0; i < n_channels; i++)
 
790
        {
 
791
          top = waveview->channels [i].top;
 
792
          height = waveview->channels [i].height;
 
793
 
 
794
          /* Draw filled regions. */
 
795
          if (waveview->select_right < waveview->select_left ||
 
796
              !(waveview->select_channels & (1 << i)))
 
797
            {
 
798
              fill_rect (window, unsel_bg_gc, width, 0, width - 1, top, height);
 
799
            }
 
800
          else
 
801
            {
 
802
              gint32 l_pos, r_pos;
 
803
 
 
804
              l_pos = calc_win_pel_pos (waveview, waveview->select_left);
 
805
              r_pos = calc_win_pel_pos (waveview, waveview->select_right);
 
806
 
 
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);
 
810
            }
 
811
 
 
812
          /* Draw horizontal lines. */
 
813
          for (j = 0; horiz_lines [j] != -999; j++)
 
814
            {
 
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);
 
818
            }
 
819
          
 
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) */
 
823
 
 
824
          /* calc_win_pel_pos returns <= 0 */
 
825
          j = 49 - ((49 - calc_win_pel_pos (waveview, 0)) % 50);
 
826
 
 
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);
 
830
        }
 
831
 
 
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);
 
841
 
 
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));
 
848
              return;
 
849
      }
 
850
 
 
851
      /* show marker */
 
852
      gtk_wave_view_draw_marker (waveview);
 
853
 
 
854
    }
 
855
 
 
856
  if (waveview->expose_count != 0)
 
857
          goto again;
 
858
  waveview->drawing = 0;
 
859
}
 
860
 
 
861
 
 
862
/* Calculate the top and bottom window y coordinates for each channel. */
 
863
static void
 
864
gtk_wave_view_calc_channel_locs (GtkWaveView *waveview)
 
865
{
 
866
  guint32 i, n_channels, height;
 
867
  guint32 top;
 
868
  guint32 accum;
 
869
 
 
870
  if (waveview->wavebuffer == NULL)
 
871
    return;
 
872
 
 
873
  n_channels = gtk_wave_buffer_get_num_channels (GTK_WAVE_BUFFER (waveview->wavebuffer));
 
874
  height = waveview->area->allocation.height - (n_channels - 1) * 3;
 
875
 
 
876
  top = 0;
 
877
  accum = 0;
 
878
  for (i = 0; i < n_channels; i++)
 
879
    {
 
880
      waveview->channels[i].top = top;
 
881
      accum += height;
 
882
      waveview->channels[i].height = accum / n_channels;
 
883
      accum %= n_channels;
 
884
 
 
885
      top += waveview->channels[i].height + 3;
 
886
    }
 
887
}
 
888
 
 
889
 
 
890
/* Update ruler and repaint screen on resize event. */
 
891
static void
 
892
gtk_wave_view_resize_event (GtkWidget *widget, gpointer data)
 
893
{
 
894
  GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
 
895
 
 
896
  gtk_wave_view_calc_channel_locs (waveview);
 
897
  gtk_wave_view_update_units (waveview);
 
898
}
 
899
 
 
900
 
 
901
static void
 
902
gtk_wave_view_scroll (GtkWidget *widget, gpointer data)
 
903
{
 
904
  GtkWaveView *waveview = GTK_WAVE_VIEW (data);
 
905
  guint32 offset, width, height;
 
906
  guint32 shift;
 
907
 
 
908
  offset = -calc_win_pel_pos (waveview, 0);
 
909
 
 
910
  width = waveview->area->allocation.width;
 
911
  height = waveview->area->allocation.height;
 
912
 
 
913
  gtk_wave_view_update_units (waveview);
 
914
 
 
915
  if (!GTK_WIDGET_REALIZED (waveview->area))
 
916
    return;
 
917
 
 
918
  if (offset > waveview->drawn_offset)
 
919
    {
 
920
      /* Find out how many pixels we moved. */
 
921
      shift = offset - waveview->drawn_offset;
 
922
 
 
923
      /* Copy and redraw as needed. */
 
924
      if (shift >= width)
 
925
        gtk_widget_queue_draw (GTK_WIDGET (waveview->area));
 
926
      else
 
927
        {
 
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);
 
930
        }
 
931
    }
 
932
  else
 
933
    {
 
934
      /* Find out how many pixels we moved. */
 
935
      shift = waveview->drawn_offset - offset;
 
936
 
 
937
      /* Copy and redraw as needed. */
 
938
      if (shift >= width)
 
939
        gtk_widget_queue_draw (GTK_WIDGET (waveview->area));
 
940
      else
 
941
        {
 
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);
 
944
        }
 
945
    }
 
946
}
 
947
 
 
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)
 
953
 
 
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))
 
959
 
 
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.
 
962
 */
 
963
static void
 
964
gtk_wave_view_update_selection (GtkWaveView *waveview, gint32 x1, gint32 x2)
 
965
{
 
966
  gint32 len, t, t2;
 
967
 
 
968
  len = gtk_wave_buffer_get_length (waveview->wavebuffer);
 
969
  /* Cannot do a selection if empty. */
 
970
  if (len == 0)
 
971
    return;
 
972
 
 
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;
 
976
  if (x1 < 0) x1 = 0;
 
977
  if (x2 < 0) x2 = 0;
 
978
  if (x2 < x1)
 
979
    {
 
980
      t = x1;
 
981
      x1 = x2;
 
982
      x2 = t;
 
983
    }
 
984
 
 
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))
 
988
    {
 
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);
 
995
      return;
 
996
    }
 
997
 
 
998
  /* new_selection is overlapping with old_selection */
 
999
  if (x1 < waveview->select_left)
 
1000
    {
 
1001
      t = waveview->select_left;
 
1002
      waveview->select_left = x1;
 
1003
      gtk_wave_view_redraw_sample_area (waveview, x1, t - 1);
 
1004
    }
 
1005
  if (x1 > waveview->select_left)
 
1006
    {
 
1007
      t = waveview->select_left;
 
1008
      waveview->select_left = x1;
 
1009
      gtk_wave_view_redraw_sample_area (waveview, t, x1 - 1);
 
1010
    }
 
1011
  if (x2 < waveview->select_right)
 
1012
    {
 
1013
      t = waveview->select_right;
 
1014
      waveview->select_right = x2;
 
1015
      gtk_wave_view_redraw_sample_area(waveview, x2 + 1, t);
 
1016
    }
 
1017
  if (x2 > waveview->select_right)
 
1018
    {
 
1019
      t = waveview->select_right;
 
1020
      waveview->select_right = x2;
 
1021
      gtk_wave_view_redraw_sample_area(waveview, t + 1, x2);
 
1022
    }
 
1023
}
 
1024
 
 
1025
 
 
1026
#define NEAR_SENSIVITY   3
 
1027
 
 
1028
 
 
1029
static int
 
1030
is_near_marker (GtkWaveView *waveview, gint32 x)
 
1031
{
 
1032
  if (waveview->marker < 0) 
 
1033
    return 0;
 
1034
  else
 
1035
    {
 
1036
      gint32 win;
 
1037
      win = calc_win_pel_pos(waveview, waveview->marker);
 
1038
      return  (x >= win - NEAR_SENSIVITY) && 
 
1039
              (x <= win + NEAR_SENSIVITY);
 
1040
    }
 
1041
}
 
1042
 
 
1043
 
 
1044
static int
 
1045
is_near_left_selection (GtkWaveView *waveview, gint32 x)
 
1046
{
 
1047
  if (waveview->select_right < waveview->select_left) 
 
1048
    return 0;
 
1049
  else
 
1050
    {
 
1051
      gint32 win;
 
1052
      win = calc_win_pel_pos(waveview, waveview->select_left);
 
1053
      return  (x >= win - NEAR_SENSIVITY) && 
 
1054
              (x <= win + NEAR_SENSIVITY);
 
1055
    }
 
1056
}
 
1057
 
 
1058
 
 
1059
static int
 
1060
is_near_right_selection (GtkWaveView *waveview, gint32 x)
 
1061
{
 
1062
  if (waveview->select_right < waveview->select_left) 
 
1063
    return 0;
 
1064
  else
 
1065
    {
 
1066
      gint32 win;
 
1067
      win = calc_win_pel_pos (waveview, waveview->select_right);
 
1068
      return  (x >= win - NEAR_SENSIVITY) && 
 
1069
              (x <= win + NEAR_SENSIVITY);
 
1070
    }
 
1071
}
 
1072
 
 
1073
 
 
1074
static void
 
1075
area_set_drag_cursor (GtkWaveView *waveview)
 
1076
{
 
1077
  if (!FLAG_IS_SET (waveview->drag_flags, FLAG_CURSOR_SET))
 
1078
    {
 
1079
      gdk_window_set_cursor (waveview->area->window, waveview->drag_cursor);
 
1080
      FLAG_SET (waveview->drag_flags, FLAG_CURSOR_SET);
 
1081
    }
 
1082
}
 
1083
 
 
1084
 
 
1085
static void
 
1086
area_restore_normal_cursor (GtkWaveView *waveview)
 
1087
{
 
1088
  if (FLAG_IS_SET (waveview->drag_flags, FLAG_CURSOR_SET))
 
1089
    {
 
1090
      gdk_window_set_cursor (waveview->area->window, waveview->normal_cursor);
 
1091
      FLAG_UNSET (waveview->drag_flags, FLAG_CURSOR_SET);
 
1092
    }
 
1093
}
 
1094
 
 
1095
 
 
1096
static gint
 
1097
gtk_wave_view_button_press_event (GtkWidget *widget,
 
1098
                                  GdkEventButton *event,
 
1099
                                  gpointer userdata)
 
1100
{
 
1101
  GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
 
1102
  gint32 frame;
 
1103
 
 
1104
  if (waveview->wavebuffer == NULL)
 
1105
    return TRUE;
 
1106
 
 
1107
  if (event->button != 1)
 
1108
    return FALSE;
 
1109
 
 
1110
  gtk_grab_add (widget);
 
1111
 
 
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))
 
1116
    {
 
1117
      FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER);
 
1118
    }
 
1119
  else if (is_near_right_selection (waveview, event->x))
 
1120
    {
 
1121
      FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION);
 
1122
      waveview->drag_start_point = waveview->select_left;
 
1123
    }
 
1124
  else if (is_near_left_selection (waveview, event->x))
 
1125
    {
 
1126
      FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION);
 
1127
      waveview->drag_start_point = waveview->select_right;
 
1128
    }
 
1129
  else
 
1130
    {
 
1131
      FLAG_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION);
 
1132
      if (FLAG_IS_SET (event->state, GDK_SHIFT_MASK) &&
 
1133
          waveview->marker >= 0)
 
1134
        {
 
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,
 
1138
                                          frame);
 
1139
        }
 
1140
      else
 
1141
        waveview->drag_start_point = frame;
 
1142
    }
 
1143
 
 
1144
  return TRUE;
 
1145
}
 
1146
 
 
1147
 
 
1148
static void
 
1149
gtk_wave_view_button_release_event (GtkWidget *widget,
 
1150
                                    GdkEventAny *event,
 
1151
                                    gpointer userdata)
 
1152
{
 
1153
  GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
 
1154
  gint32 frame, x;
 
1155
 
 
1156
  gtk_grab_remove (widget);
 
1157
 
 
1158
  if (waveview->scroll_timeout != 0)
 
1159
    {
 
1160
      gtk_timeout_remove (waveview->scroll_timeout);
 
1161
      waveview->scroll_timeout = 0;
 
1162
    }
 
1163
 
 
1164
  if (event->type == GDK_BUTTON_RELEASE)
 
1165
    {
 
1166
      gint xint, yint;
 
1167
      GdkModifierType state;
 
1168
 
 
1169
      gdk_window_get_pointer (widget->window, &xint, &yint, &state);
 
1170
      x = xint;
 
1171
      //x = ((GdkEventButton *)event)->x;
 
1172
    }
 
1173
  else 
 
1174
    {
 
1175
      gint xint, yint;
 
1176
      GdkModifierType state;
 
1177
 
 
1178
      gdk_window_get_pointer (widget->window, &xint, &yint, &state);
 
1179
      x = xint;
 
1180
      //x = ((GdkEventCrossing *)event)->x;
 
1181
    }
 
1182
 
 
1183
  /* dragging outside the border */
 
1184
  if (x < 0 && GTK_ADJUSTMENT (waveview->adjust)->value >= 0.0)
 
1185
      x = 0;
 
1186
  else if (x >= waveview->area->allocation.width)
 
1187
      x = waveview->area->allocation.width /* - 1  no, round up this way */;
 
1188
 
 
1189
  frame = calc_frame_pos_win (waveview, x);
 
1190
  if (frame < 0)
 
1191
          frame = 0;
 
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 */
 
1194
 
 
1195
  if (FLAGS_IS_CLEAR (waveview->drag_flags))
 
1196
    return;
 
1197
  if (waveview->wavebuffer == NULL)
 
1198
    {
 
1199
      FLAGS_CLEAR (waveview->drag_flags);
 
1200
      return;
 
1201
    }
 
1202
  if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER))
 
1203
    {
 
1204
      gtk_wave_view_set_marker (waveview, frame);
 
1205
    }
 
1206
  else if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION))
 
1207
    {
 
1208
      if (FLAG_IS_SET (waveview->drag_flags, FLAG_DID_MOVE))
 
1209
        {
 
1210
          gtk_wave_view_update_selection (waveview, waveview->drag_start_point,
 
1211
                                         frame);
 
1212
        }
 
1213
      else
 
1214
        {
 
1215
          /* actually, it was a click */
 
1216
          gtk_wave_view_set_marker (waveview, frame);
 
1217
        }
 
1218
    }  
 
1219
  area_restore_normal_cursor (waveview);
 
1220
  FLAGS_CLEAR (waveview->drag_flags);
 
1221
}
 
1222
 
 
1223
 
 
1224
static gboolean
 
1225
motion_update (GtkWaveView *waveview, guint32 x)
 
1226
{
 
1227
  gint32 frame;
 
1228
 
 
1229
  frame = calc_frame_pos_win (waveview, x);
 
1230
 
 
1231
  if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER))
 
1232
    {
 
1233
      gtk_wave_view_set_marker (waveview, frame);
 
1234
      area_set_drag_cursor (waveview);
 
1235
    }
 
1236
  else if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_SELECTION))
 
1237
    {
 
1238
      FLAG_SET (waveview->drag_flags, FLAG_DID_MOVE);
 
1239
      gtk_wave_view_update_selection (waveview, waveview->drag_start_point,
 
1240
                                               frame);
 
1241
      area_set_drag_cursor (waveview);
 
1242
    }
 
1243
  else
 
1244
    {
 
1245
      if (is_near_marker (waveview, x) ||
 
1246
          is_near_left_selection (waveview, x) ||
 
1247
          is_near_right_selection (waveview, x))
 
1248
 
 
1249
        area_set_drag_cursor (waveview);
 
1250
      else
 
1251
        area_restore_normal_cursor (waveview);
 
1252
    }
 
1253
 
 
1254
  return TRUE;
 
1255
}
 
1256
 
 
1257
 
 
1258
static gboolean
 
1259
gtk_wave_view_scroll_notify (gpointer widget)
 
1260
{
 
1261
  GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
 
1262
  GtkAdjustment *adjust = GTK_ADJUSTMENT (waveview->adjust);
 
1263
  gint32 width, pos, frames;
 
1264
 
 
1265
  width = GTK_WIDGET (waveview)->allocation.width;
 
1266
  pos = waveview->mouse_x;
 
1267
 
 
1268
  if (pos < 0)
 
1269
    {
 
1270
      /* Scroll left (if possible). */
 
1271
 
 
1272
      frames = (gint32) (adjust->value - waveview->zoom * 32.0);
 
1273
      frames = MAX (adjust->lower, frames);
 
1274
      if (adjust->value > 0.0)
 
1275
        pos = 0;
 
1276
    }
 
1277
  else if (pos >= width)
 
1278
    {
 
1279
      /* Scroll right (if possible). */
 
1280
      frames = (gint32) (adjust->value + waveview->zoom * 32.0);
 
1281
      frames = MIN (adjust->upper - adjust->page_size, frames);
 
1282
      pos = width - 1;
 
1283
    }
 
1284
  else
 
1285
    return TRUE;
 
1286
 
 
1287
  if (FLAG_IS_SET (waveview->drag_flags, FLAG_DRAGGING_MARKER))
 
1288
    {
 
1289
      /* and now, something completely ugly ... A SHRUBBERY!
 
1290
       * turn off the marker to reduce flicker while scrolling
 
1291
       */
 
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);
 
1296
    }
 
1297
  else
 
1298
    {
 
1299
      gtk_adjustment_set_value (adjust, frames);
 
1300
      motion_update (waveview, pos);
 
1301
    }
 
1302
 
 
1303
  return TRUE;
 
1304
}
 
1305
 
 
1306
 
 
1307
static gint
 
1308
gtk_wave_view_motion_notify_event (GtkWidget *widget,
 
1309
                                   GdkEventMotion *event,
 
1310
                                   gpointer userdata)
 
1311
{
 
1312
  GtkWaveView *waveview = GTK_WAVE_VIEW (userdata);
 
1313
  gint32 x;
 
1314
 
 
1315
  if (waveview->wavebuffer == NULL)
 
1316
    return FALSE;
 
1317
 
 
1318
  GTK_WIDGET_CLASS (GTK_OBJECT (waveview->hruler)->klass)->motion_notify_event (GTK_WIDGET (waveview->hruler), event);
 
1319
 
 
1320
  /* Get x coordinate on hint. */
 
1321
  if (event->is_hint)
 
1322
    {
 
1323
      gint xint, yint;
 
1324
      GdkModifierType state;
 
1325
 
 
1326
      gdk_window_get_pointer (widget->window, &xint, &yint, &state);
 
1327
      x = xint;
 
1328
    }
 
1329
  else
 
1330
    x = event->x;
 
1331
 
 
1332
  motion_update (waveview, x);
 
1333
 
 
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);
 
1339
 
 
1340
  waveview->mouse_x = x;
 
1341
 
 
1342
  return TRUE;
 
1343
}
 
1344
 
 
1345
static void
 
1346
gtk_wave_view_init (GtkWaveView *waveview)
 
1347
{
 
1348
  waveview->hruler = glame_hruler_new();
 
1349
  glame_ruler_set_metric(GLAME_RULER(waveview->hruler),
 
1350
                         &time_metric);
 
1351
  gtk_box_pack_start (GTK_BOX (waveview), waveview->hruler, FALSE, FALSE, 0);
 
1352
  gtk_widget_show (waveview->hruler);
 
1353
 
 
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);
 
1359
 
 
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);
 
1364
 
 
1365
  gtk_signal_connect (GTK_OBJECT (waveview->adjust),
 
1366
                      "value_changed", gtk_wave_view_scroll,
 
1367
                      GTK_OBJECT (waveview));
 
1368
 
 
1369
  gtk_signal_connect (GTK_OBJECT (waveview),
 
1370
                      "size_allocate", gtk_wave_view_resize_event,
 
1371
                      GTK_OBJECT (waveview));
 
1372
 
 
1373
  gtk_signal_connect (GTK_OBJECT (waveview->area),
 
1374
                      "realize", on_area_realize,
 
1375
                      GTK_OBJECT (waveview));
 
1376
 
 
1377
  gtk_signal_connect (GTK_OBJECT (waveview->area),
 
1378
                      "expose_event", on_area_expose_event,
 
1379
                      GTK_OBJECT (waveview));
 
1380
 
 
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));
 
1384
 
 
1385
  gtk_signal_connect (GTK_OBJECT (waveview->area),
 
1386
                      "button_release_event", gtk_wave_view_button_release_event,
 
1387
                      GTK_OBJECT (waveview));
 
1388
 
 
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));
 
1392
 
 
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);
 
1401
 
 
1402
  waveview->wavebuffer = NULL;
 
1403
 
 
1404
  waveview->select_left = 0;
 
1405
  waveview->select_right = -1;
 
1406
  waveview->select_channels = 0xffffffff;
 
1407
 
 
1408
  waveview->drawn_offset = 0;
 
1409
  waveview->drawing = 0;
 
1410
 
 
1411
  waveview->channels = NULL;
 
1412
  waveview->n_channels = 0;
 
1413
  waveview->cache_tag = NULL;
 
1414
  waveview->invalidate = FALSE;
 
1415
 
 
1416
  waveview->zoom = 1.0;
 
1417
  waveview->cache_size = 2048;
 
1418
  waveview->ampl_zoom = 1.0;
 
1419
 
 
1420
  waveview->marker = -1;
 
1421
  waveview->marker_scroll_stop = 0.0;
 
1422
  waveview->marker_scroll_start = 0.0;
 
1423
 
 
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);
 
1428
 
 
1429
  waveview->mouse_x = 0;
 
1430
  waveview->scroll_timeout = 0;
 
1431
 
 
1432
  /* we can't initialize the gc here because the window's not realized yet */
 
1433
  waveview->marker_gc = NULL;
 
1434
}
 
1435
 
 
1436
 
 
1437
void
 
1438
gtk_wave_view_set_amplitude_zoom (GtkWaveView *waveview, gdouble amplzoom)
 
1439
{
 
1440
  if (amplzoom < 1.0)
 
1441
    amplzoom = 1.0;
 
1442
 
 
1443
  if (waveview->ampl_zoom != amplzoom)
 
1444
    {
 
1445
      waveview->ampl_zoom = amplzoom;
 
1446
      gtk_widget_queue_draw (GTK_WIDGET (waveview));
 
1447
    }
 
1448
}
 
1449
 
 
1450
 
 
1451
gdouble
 
1452
gtk_wave_view_get_amplitude_zoom (GtkWaveView *waveview)
 
1453
{
 
1454
  return waveview->ampl_zoom;
 
1455
}
 
1456
 
 
1457
 
 
1458
#if 0
 
1459
/* Verify selection is within the data bounds, otherwise fix it and
 
1460
   repaint as necessary. */
 
1461
static void
 
1462
gtk_wave_view_check_selection (GtkWaveView *waveview)
 
1463
{
 
1464
  gboolean modified;
 
1465
  gint32   length;
 
1466
 
 
1467
  length = gtk_wave_buffer_get_length (waveview->wavebuffer);
 
1468
 
 
1469
  modified = FALSE;
 
1470
  if (waveview->select_left >= length)
 
1471
    {
 
1472
      modified = TRUE;
 
1473
      waveview->select_left = length - 1;
 
1474
    }
 
1475
 
 
1476
  if (waveview->select_right >= length)
 
1477
    {
 
1478
      modified = TRUE;
 
1479
      waveview->select_right = length - 1;
 
1480
    }
 
1481
 
 
1482
  if (modified)
 
1483
    gtk_widget_queue_draw (waveview->area);
 
1484
}
 
1485
#endif
 
1486
 
 
1487
 
 
1488
static void
 
1489
gtk_wave_view_invalidate_range (GtkWaveView *waveview, guint32 start, guint32 length)
 
1490
{
 
1491
  if (!waveview->invalidate)
 
1492
    {
 
1493
      waveview->invalidate = TRUE;
 
1494
      waveview->invalidate_start = start;
 
1495
      waveview->invalidate_stop = start + length - 1;
 
1496
    }
 
1497
  else
 
1498
    {
 
1499
      waveview->invalidate_start = MIN (waveview->invalidate_start, start);
 
1500
      waveview->invalidate_stop = MAX (waveview->invalidate_stop, start + length - 1);
 
1501
    }
 
1502
}
 
1503
 
 
1504
 
 
1505
static void
 
1506
on_wave_buffer_modified (GtkWaveView *widget, GRange *range)
 
1507
{
 
1508
  GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
 
1509
 
 
1510
  if (waveview->wavebuffer == NULL)
 
1511
    return;
 
1512
 
 
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);
 
1515
}
 
1516
 
 
1517
 
 
1518
static void
 
1519
on_wave_buffer_insert_data (GtkWidget *widget, GRange *range)
 
1520
{
 
1521
  GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
 
1522
  gint32 width;
 
1523
 
 
1524
  width = range->right - range->left + 1;
 
1525
 
 
1526
  if (waveview->marker >= range->left)
 
1527
    waveview->marker += width;
 
1528
 
 
1529
  if (waveview->select_right >= range->left)
 
1530
    waveview->select_right += width;
 
1531
 
 
1532
  if (waveview->select_left >= range->left)
 
1533
    waveview->select_left += width;
 
1534
 
 
1535
  gtk_wave_view_update_units (waveview);
 
1536
}
 
1537
 
 
1538
 
 
1539
static void
 
1540
on_wave_buffer_delete_data (GtkWidget *widget, GRange *range)
 
1541
{
 
1542
  GtkWaveView *waveview = GTK_WAVE_VIEW (widget);
 
1543
  gint32 width;
 
1544
 
 
1545
  width = range->right - range->left + 1;
 
1546
 
 
1547
  if (waveview->marker > range->right)
 
1548
    waveview->marker -= width;
 
1549
  else if (waveview->marker >= range->left)
 
1550
    waveview->marker = -1;
 
1551
 
 
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;
 
1556
 
 
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;
 
1561
 
 
1562
  gtk_wave_view_update_units (waveview);
 
1563
}
 
1564
 
 
1565
 
 
1566
GtkWaveBuffer *
 
1567
gtk_wave_view_get_buffer (GtkWaveView *waveview)
 
1568
{
 
1569
  return waveview->wavebuffer;
 
1570
}
 
1571
 
 
1572
 
 
1573
/* Select a new data stream, ref() it, invalidate cache, and update screen. */
 
1574
void
 
1575
gtk_wave_view_set_buffer (GtkWaveView *waveview, GtkWaveBuffer *wavebuffer)
 
1576
{
 
1577
  if (waveview->wavebuffer == wavebuffer)
 
1578
    return;
 
1579
 
 
1580
  gtk_wave_view_cache_free (waveview);
 
1581
  g_free (waveview->channels);
 
1582
 
 
1583
  if (waveview->wavebuffer != NULL)
 
1584
    {
 
1585
      if (GTK_IS_EDITABLE_WAVE_BUFFER (waveview->wavebuffer))
 
1586
        {
 
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);
 
1593
        }
 
1594
 
 
1595
      gtk_object_unref (GTK_OBJECT (waveview->wavebuffer));
 
1596
    }
 
1597
 
 
1598
  waveview->wavebuffer = wavebuffer;
 
1599
 
 
1600
  if (wavebuffer != NULL)
 
1601
    {
 
1602
      gtk_object_ref (GTK_OBJECT (waveview->wavebuffer));
 
1603
      gtk_object_sink (GTK_OBJECT (waveview->wavebuffer));
 
1604
 
 
1605
      if (GTK_IS_EDITABLE_WAVE_BUFFER (waveview->wavebuffer))
 
1606
        {
 
1607
          waveview->modified_connection = 
 
1608
            gtk_signal_connect_object (GTK_OBJECT (waveview->wavebuffer),
 
1609
                                       "modified",
 
1610
                                       GTK_SIGNAL_FUNC (on_wave_buffer_modified),
 
1611
                                       GTK_OBJECT (waveview));
 
1612
 
 
1613
          waveview->insert_data_connection = 
 
1614
            gtk_signal_connect_object (GTK_OBJECT (waveview->wavebuffer),
 
1615
                                       "insert_data",
 
1616
                                       GTK_SIGNAL_FUNC (on_wave_buffer_insert_data),
 
1617
                                       GTK_OBJECT (waveview));
 
1618
 
 
1619
          waveview->delete_data_connection = 
 
1620
            gtk_signal_connect_object (GTK_OBJECT (waveview->wavebuffer),
 
1621
                                       "delete_data",
 
1622
                                       GTK_SIGNAL_FUNC (on_wave_buffer_delete_data),
 
1623
                                       GTK_OBJECT (waveview));
 
1624
        }
 
1625
 
 
1626
      waveview->n_channels = gtk_wave_buffer_get_num_channels (waveview->wavebuffer);
 
1627
      waveview->channels = g_new (GtkWaveViewChannelInfo, waveview->n_channels);
 
1628
 
 
1629
      waveview->select_left = 0;
 
1630
      waveview->select_right = gtk_wave_buffer_get_length (waveview->wavebuffer) - 1;
 
1631
      waveview->marker = 0;
 
1632
 
 
1633
      gtk_wave_view_cache_create (waveview);
 
1634
    }
 
1635
  else
 
1636
    {
 
1637
      waveview->channels = NULL;
 
1638
      waveview->cache_tag = NULL;
 
1639
      waveview->n_channels = 0;
 
1640
      waveview->marker = -1;
 
1641
    }
 
1642
 
 
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);
 
1646
}
 
1647
 
 
1648
 
 
1649
/* return < 0 means no further action necessary
 
1650
 * return > 0 means further action necessary
 
1651
 */
 
1652
static int
 
1653
check_marker (GtkWaveView *waveview, 
 
1654
              gint32 *frame, 
 
1655
              gint32 *length,
 
1656
              gint32 *win_pos_new_marker)
 
1657
{
 
1658
  gint32 win_pos_old_marker;
 
1659
 
 
1660
  if (waveview->wavebuffer == NULL)
 
1661
    return -1;
 
1662
  
 
1663
  if (!GTK_WIDGET_REALIZED (waveview->area))
 
1664
    {
 
1665
      waveview->marker = *frame;
 
1666
      return -1;
 
1667
    }
 
1668
 
 
1669
  if (*frame < 0)
 
1670
    {
 
1671
      /* removal:
 
1672
       * neat trick: because the marker is drawn with GDK_XOR
 
1673
       * we can restore the original frame(s) by drawing it again.
 
1674
       */
 
1675
      if (waveview->marker >= 0)
 
1676
        gtk_wave_view_draw_marker (waveview);
 
1677
      waveview->marker = -1;
 
1678
      return -1;
 
1679
    }
 
1680
  
 
1681
  *length = gtk_wave_buffer_get_length (waveview->wavebuffer);
 
1682
  if (*frame >= *length)
 
1683
      *frame = *length;
 
1684
 
 
1685
  win_pos_old_marker = calc_win_pel_pos (waveview, waveview->marker);
 
1686
  *win_pos_new_marker = calc_win_pel_pos (waveview, *frame);
 
1687
 
 
1688
  if (*win_pos_new_marker == win_pos_old_marker)
 
1689
    {
 
1690
      waveview->marker = *frame;
 
1691
      return -1;
 
1692
    }
 
1693
 
 
1694
  return 1;
 
1695
}
 
1696
 
 
1697
 
 
1698
void
 
1699
gtk_wave_view_set_marker (GtkWaveView *waveview, gint32 frame)
 
1700
{
 
1701
  gint32 length, win_pos_new;
 
1702
 
 
1703
  if (check_marker (waveview, &frame, &length, &win_pos_new) > 0)
 
1704
    {
 
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;
 
1709
    }
 
1710
}
 
1711
 
 
1712
 
 
1713
void
 
1714
gtk_wave_view_set_marker_scrolling_boundaries (GtkWaveView *waveview,
 
1715
                                               gdouble      stop_threshold,
 
1716
                                               gdouble      start_offset)
 
1717
{
 
1718
  /* sanity checking on data */
 
1719
  if (stop_threshold < 0.0 || stop_threshold > 1.0)
 
1720
    {
 
1721
      /* scroll when arriving at the outermost visible frame */
 
1722
      stop_threshold = 1.0;
 
1723
    }
 
1724
  if (start_offset < 0.0 || start_offset > 1.0)
 
1725
    {
 
1726
      /* set the new position at the first visible frame */
 
1727
      start_offset = 0.0;
 
1728
    }
 
1729
  if (start_offset + stop_threshold > 1.0)
 
1730
    {
 
1731
      /* this will drive ya nuts! 
 
1732
       * Should have provided some decent parameters!
 
1733
       */
 
1734
      start_offset = 1.0 - stop_threshold;
 
1735
    }
 
1736
  waveview->marker_scroll_stop = stop_threshold;
 
1737
  waveview->marker_scroll_start = start_offset;
 
1738
}
 
1739
 
 
1740
static void
 
1741
scroll_and_draw_marker (GtkWaveView *waveview, 
 
1742
                        gint32  frame, 
 
1743
                        gint32  win_width,
 
1744
                        gint32  wave_length,
 
1745
                        gdouble start_offset)
 
1746
{
 
1747
  GtkAdjustment *adj = GTK_ADJUSTMENT (waveview->adjust);
 
1748
  gint32 frame_offset, max_offset;
 
1749
 
 
1750
  max_offset = wave_length - (win_width * waveview->zoom) - 1;
 
1751
  max_offset = MAX (max_offset, 0);
 
1752
 
 
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);
 
1757
 
 
1758
  /* this will do the scrolling for us */
 
1759
  gtk_adjustment_set_value (adj, frame_offset);
 
1760
 
 
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);
 
1764
 
 
1765
  gtk_wave_view_update_units (waveview);
 
1766
}
 
1767
 
 
1768
 
 
1769
void
 
1770
gtk_wave_view_set_marker_and_scroll (GtkWaveView *waveview,
 
1771
                                     gint32      frame)
 
1772
{
 
1773
  gint32 win_pos_new, width, length;
 
1774
  //static int count;
 
1775
 
 
1776
  if (check_marker (waveview, &frame, &length, &win_pos_new) < 0)
 
1777
    {
 
1778
      /* no action necessary */
 
1779
      /* WRONG! we might still need to scroll... return; */
 
1780
    }
 
1781
 
 
1782
  width = waveview->area->allocation.width;
 
1783
 
 
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))) 
 
1788
    {
 
1789
      /* we're moving to the right */
 
1790
      scroll_and_draw_marker (waveview, frame, width, length,
 
1791
                              waveview->marker_scroll_start);
 
1792
    }
 
1793
  else if (win_pos_new >= width ||
 
1794
           (frame < waveview->marker && 
 
1795
            win_pos_new < width * waveview->marker_scroll_stop)) 
 
1796
    {
 
1797
      /* we're moving to the left */
 
1798
      scroll_and_draw_marker (waveview, frame, width, length,
 
1799
                              1.0 - waveview->marker_scroll_start);
 
1800
    }
 
1801
  else
 
1802
    {
 
1803
      /* redraw the marker */
 
1804
      draw_marker_from_frame_pos (waveview, waveview->marker);
 
1805
      draw_marker_from_frame_pos (waveview, frame);
 
1806
    }
 
1807
 
 
1808
  /* set the new marker */
 
1809
  waveview->marker = frame;
 
1810
}
 
1811
  
 
1812
 
 
1813
gint32 gtk_wave_view_get_marker (GtkWaveView *waveview)
 
1814
{
 
1815
  return waveview->marker;
 
1816
}
 
1817
 
 
1818
 
 
1819
/* Return zoom factor. */
 
1820
gdouble
 
1821
gtk_wave_view_get_zoom (GtkWaveView *waveview)
 
1822
{
 
1823
  return waveview->zoom;
 
1824
}
 
1825
 
 
1826
 
 
1827
/* Set zoom.  zoom = # of samples per pixel, must be >= 1.0 */
 
1828
void
 
1829
gtk_wave_view_set_zoom (GtkWaveView *waveview,
 
1830
                        gdouble      zoom)
 
1831
{
 
1832
  if (zoom < 1.0)
 
1833
    zoom = 1.0;
 
1834
 
 
1835
  if (waveview->area && waveview->wavebuffer) {
 
1836
          guint32 length;
 
1837
          gdouble max_zoom;
 
1838
 
 
1839
          if (GTK_WIDGET_REALIZED (waveview->area))
 
1840
                  length = GTK_WIDGET (waveview->area)->allocation.width;
 
1841
          else
 
1842
                  length = GTK_WIDGET (waveview->area)->requisition.width;
 
1843
          max_zoom = (gdouble)gtk_wave_buffer_get_length(waveview->wavebuffer)/(gdouble)length;
 
1844
 
 
1845
          if (zoom > max_zoom)
 
1846
                  zoom = max_zoom;
 
1847
  }
 
1848
 
 
1849
  if (waveview->zoom != zoom)
 
1850
    {
 
1851
      waveview->zoom = zoom;
 
1852
 
 
1853
      gtk_wave_view_cache_invalidate (waveview);
 
1854
      gtk_wave_view_update_units (waveview);
 
1855
      gtk_widget_queue_draw (GTK_WIDGET (waveview));
 
1856
    }
 
1857
}
 
1858
 
 
1859
 
 
1860
/* Zoom whole screen. */
 
1861
void
 
1862
gtk_wave_view_set_zoom_all (GtkWaveView *waveview)
 
1863
{
 
1864
  if (waveview->wavebuffer != NULL)
 
1865
    {
 
1866
      guint32 length;
 
1867
 
 
1868
      if (GTK_WIDGET_REALIZED (waveview->area))
 
1869
        length = GTK_WIDGET (waveview->area)->allocation.width;
 
1870
      else
 
1871
        length = GTK_WIDGET (waveview->area)->requisition.width;
 
1872
 
 
1873
      gtk_wave_view_set_zoom (waveview, ((gdouble) gtk_wave_buffer_get_length (waveview->wavebuffer)) / length);
 
1874
    }
 
1875
}
 
1876
 
 
1877
 
 
1878
/* Set zoom to selection (if there is one). */
 
1879
void
 
1880
gtk_wave_view_set_zoom_selection (GtkWaveView *waveview)
 
1881
{
 
1882
  if (waveview->select_left <= waveview->select_right)
 
1883
    {
 
1884
      gdouble zoom;
 
1885
      GtkAdjustment *adj = GTK_ADJUSTMENT (waveview->adjust);
 
1886
 
 
1887
      zoom = ((gdouble) (waveview->select_right - waveview->select_left + 1)) / waveview->area->allocation.width;
 
1888
 
 
1889
      gtk_wave_view_set_zoom (waveview, zoom);
 
1890
 
 
1891
      if (adj->value != waveview->select_left)
 
1892
        {
 
1893
          adj->value = waveview->select_left;
 
1894
          gtk_wave_view_update_units (waveview);
 
1895
          gtk_widget_queue_draw (waveview->area);
 
1896
        }
 
1897
    }
 
1898
}
 
1899
 
 
1900
 
 
1901
/* Return selection.  Length = 0 if nothing is selected. */
 
1902
void
 
1903
gtk_wave_view_get_selection (GtkWaveView *waveview,
 
1904
                             gint32      *start,
 
1905
                             gint32      *length)
 
1906
{
 
1907
  *start = waveview->select_left;
 
1908
 
 
1909
  if (waveview->select_left <= waveview->select_right)
 
1910
    *length = waveview->select_right - waveview->select_left + 1;
 
1911
  else
 
1912
    *length = 0;
 
1913
}
 
1914
 
 
1915
 
 
1916
/* Set selection and refresh screen. */
 
1917
void
 
1918
gtk_wave_view_set_selection (GtkWaveView *waveview,
 
1919
                             gint32 start,
 
1920
                             gint32 length)
 
1921
{
 
1922
  waveview->select_left = start;
 
1923
  waveview->select_right = start + length - 1;
 
1924
 
 
1925
  gtk_widget_queue_draw (waveview->area);
 
1926
}
 
1927
 
 
1928
 
 
1929
guint32
 
1930
gtk_wave_view_get_select_channels (GtkWaveView *waveview)
 
1931
{
 
1932
  return waveview->select_channels;
 
1933
}
 
1934
 
 
1935
 
 
1936
void
 
1937
gtk_wave_view_set_select_channels (GtkWaveView *waveview,
 
1938
                                   guint32      sel_mask)
 
1939
{
 
1940
  waveview->select_channels = sel_mask;
 
1941
  gtk_widget_queue_draw (waveview->area);
 
1942
}
 
1943
 
 
1944
 
 
1945
void
 
1946
gtk_wave_view_set_cache_size (GtkWaveView *waveview,
 
1947
                              guint32      size)
 
1948
{
 
1949
  if (size <= 0)
 
1950
    size = 1;
 
1951
 
 
1952
  if (waveview->cache_size != size)
 
1953
    {
 
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);
 
1958
    }
 
1959
}