1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  *
6  * This widget was originally based on sample-display by Michael Krause
7  * in ``The Real Soundtracker'', Copyright (C) 1998-1999 Michael Krause
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27 
28 #include <stdlib.h>
29 #include <math.h>
30 #include <time.h>
31 
32 #include "sample-display.h"
33 
34 #include <gdk/gdkkeysyms.h>
35 #include <gtk/gtk.h>
36 
37 #include <sweep/sweep_i18n.h>
38 
39 #include "sweep_app.h"
40 #include "sample.h"
41 #include "head.h"
42 #include "cursors.h"
43 #include "play.h"
44 #include "callbacks.h"
45 #include "edit.h"
46 #include "undo_dialog.h"
47 
48 /*#define DEBUG*/
49 
50 /*#define DOUBLE_BUFFER */
51 
52 /*#define ALWAYS_REDRAW_ALL*/
53 
54 /*#define LEGACY_DRAW_MODE*/
55 
56 #define SEL_SCRUBS
57 
58 extern GdkCursor * sweep_cursors[];
59 
60 /* Maximum number of samples to consider per pixel */
61 #define STEP_MAX 32
62 
63 
64 /* Whether or not to compile in support for
65  * drawing the crossing vectors
66  */
67 /* #define DRAW_CROSSING_VECTORS */
68 
69 #define PIXEL_TO_OFFSET(p) \
70   ((sw_framecount_t)(((gdouble)(p)) * (((gdouble)(s->view->end - s->view->start)) / ((gdouble)s->width))))
71 
72 #define XPOS_TO_OFFSET(x) \
73   CLAMP(s->view->start + PIXEL_TO_OFFSET(x), 0, s->view->sample->sounddata->nr_frames)
74 
75 #define SAMPLE_TO_PIXEL(n) \
76   ((sw_framecount_t)((gdouble)(n) * (gdouble)s->width / (gdouble)(s->view->end - s->view->start)))
77 
78 #define OFFSET_TO_XPOS(o) \
79   SAMPLE_TO_PIXEL((o) - s->view->start)
80 
81 #define OFFSET_RANGE(l, x) ((x) < 0 ? 0 : ((x) >= (l) ? (l) - 1 : (x)))
82 
83 #define SET_CURSOR(w, c) \
84   gdk_window_set_cursor ((w)->window, sweep_cursors[SWEEP_CURSOR_##c])
85 
86 #define YPOS_TO_CHANNEL(y) \
87   (s->view->sample->sounddata->format->channels * y / s->height)
88 
89 #define CHANNEL_HEIGHT \
90   (s->height / s->view->sample->sounddata->format->channels)
91 
92 #define YPOS_TO_VALUE(y) \
93   ((sw_audio_t)(CHANNEL_HEIGHT/2 - (y - (YPOS_TO_CHANNEL(y) * CHANNEL_HEIGHT)))/(CHANNEL_HEIGHT/2))
94 
95 #if 0
96 #define YPOS_TO_CHANNEL(y) \
97   (s->view->sample->sounddata->format->channels == 2 ? (y > s->height/2) : 0)
98 
99 #define YPOS_TO_VALUE_1(y) \
100   ((sw_audio_t)(s->height/2 - y)/(s->height/2))
101 
102 #define YPOS_TO_VALUE_L(y) \
103   ((sw_audio_t)(s->height/4 - y)/(s->height/4))
104 
105 #define YPOS_TO_VALUE_R(y) \
106   ((sw_audio_t)(3*s->height/4 - y)/(s->height/4))
107 
108 #define YPOS_TO_VALUE_2(y) \
109   (YPOS_TO_CHANNEL(y) ? YPOS_TO_VALUE_R(y) : YPOS_TO_VALUE_L(y))
110 #endif
111 
112 #define MARCH_INTERVAL 300
113 #define PULSE_INTERVAL 450
114 #define HAND_SCROLL_INTERVAL 50
115 
116 extern sw_view * last_tmp_view;
117 
118 static int last_button; /* button index which started the last selection;
119 			 * This is global to allow comparison for
120 			 * last_tmp_view
121 			 */
122 
123 #if 1
124 
125 static const int default_colors[] = {
126   200, 200, 193,  /* bg */
127   199, 203, 158,  /* fg */
128   0, 0xaa, 0, /* play (mask) */
129   220, 230, 255, /* user */
130   100, 100, 100, /* zero */
131   240, 230, 240, /* sel box */
132   110, 110, 100, /* tmp_sel XOR mask */
133 #if 1
134   108, 115, 134,    /* sel bg */
135 #else
136   62, 68, 118,  /* sel bg */
137 #endif
138   166, 166, 154, /* minmax */
139   240, 250, 240, /* highlight */
140   81, 101, 81,   /* lowlight */
141   230, 0, 0,     /* rec */
142 };
143 
144 #else
145 
146 static const int default_colors[] = {
147 #if 0
148   86, 86, 80,    /* bg */
149 #elif 0
150   220, 220, 210, /* bg */
151 #else
152   200, 200, 193,    /* bg */
153 #endif
154   199, 203, 158, /* fg */
155   20, 230, 0,    /* play */
156   200, 200, 200, /* user */
157   200, 200, 200, /* zero */
158   240, 230, 240, /* sel box */
159   110, 110, 100, /* tmp_sel XOR mask */
160   118, 118, 108, /* sel bg XOR mask */
161   154, 166, 154, /* minmax */
162   219, 219, 211, /* highlight */
163   81, 101, 81,   /* lowlight */
164   240, 0, 0,     /* rec */
165 };
166 #endif
167 
168 static const int bg_colors[] = {
169   250, 250, 237,    /* black bg */
170   200, 200, 193,    /* red bg */
171   147, 147, 140,    /* orange bg */
172   160, 160, 150,    /* yellow bg */
173 #if 0
174   210, 210, 193,    /* blue bg */
175 #else
176   250, 250, 237,    /* blue bg */
177 #endif
178   160, 160, 150,    /* white bg */
179   0, 0, 0,          /* greenscreen bg */
180   60, 70, 170,          /* bluescreen bg */
181 };
182 
183 static const int fg_colors[] = {
184   80, 80, 60,    /* black fg */
185   220, 80, 40,   /* red fg */
186   220, 170, 120, /* orange fg */
187   199, 203, 158, /* yellow fg */
188   128, 138, 184, /* blue fg */
189   230, 240, 255, /* white fg */
190   0, 220, 0,     /* greenscreen fg */
191   240, 240, 240,     /* bluescreen fg */
192 };
193 
194 /* Values for s->selecting */
195 enum {
196   SELECTING_NOTHING = 0,
197   SELECTING_SELECTION_START,
198   SELECTING_SELECTION_END,
199   SELECTING_PAN_WINDOW,
200   SELECTING_PLAYMARKER,
201   SELECTING_PENCIL,
202   SELECTING_NOISE,
203   SELECTING_HAND,
204 };
205 
206 enum {
207   SELECTION_MODE_NONE = 0, /* Not selecting; used for consistency check. */
208   SELECTION_MODE_REPLACE,
209   SELECTION_MODE_INTERSECT,
210   SELECTION_MODE_SUBTRACT,
211   SELECTION_MODE_MAX
212 };
213 
214 enum {
215   SIG_SELECTION_CHANGED,
216   SIG_WINDOW_CHANGED,
217   SIG_MOUSE_OFFSET_CHANGED,
218   LAST_SIGNAL
219 };
220 
221 static gchar * selection_mode_names[SELECTION_MODE_MAX] = {
222   N_(""), /* NONE */
223   N_("New selection"), /* REPLACE */
224   N_("Selection: add/modify region"), /* INTERSECT */
225   N_("Selection: subtract region"), /* SUBTRACT */
226 };
227 
228 #define IS_INITIALIZED(s) (s->view != NULL)
229 
230 static guint sample_display_signals[LAST_SIGNAL] = { 0 };
231 
232 static gint8 sel_dash_list[2] = { 4, 4 }; /* Equivalent to GDK's default
233 					  *  dash list.
234 					  */
235 
236 void
sample_display_refresh(SampleDisplay * s)237 sample_display_refresh (SampleDisplay *s)
238 {
239   sw_sample * sample;
240 
241   g_return_if_fail(s != NULL);
242   g_return_if_fail(IS_SAMPLE_DISPLAY(s));
243 
244   if(!IS_INITIALIZED(s))
245     return;
246 
247   sample = s->view->sample;
248 
249   s->old_user_offset_x = s->user_offset_x =
250     OFFSET_TO_XPOS(sample->user_offset);
251 
252   s->old_play_offset_x = s->play_offset_x =
253     OFFSET_TO_XPOS(sample->play_head->offset);
254 
255   if (sample->rec_head != NULL) {
256     s->old_rec_offset_x = s->rec_offset_x =
257       OFFSET_TO_XPOS(sample->rec_head->offset);
258   }
259 
260   gtk_widget_queue_draw_area (GTK_WIDGET(s), 0, 0, s->width, s->height);
261 }
262 
263 sw_framecount_t
sample_display_get_mouse_offset(SampleDisplay * s)264 sample_display_get_mouse_offset (SampleDisplay * s)
265 {
266   int x, y;
267   GdkModifierType state;
268 
269   gdk_window_get_pointer (GTK_WIDGET(s)->window, &x, &y, &state);
270 
271   return XPOS_TO_OFFSET(x);
272 }
273 
274 void
sample_display_set_view(SampleDisplay * s,sw_view * view)275 sample_display_set_view (SampleDisplay *s, sw_view *view)
276 {
277   g_return_if_fail(s != NULL);
278   g_return_if_fail(IS_SAMPLE_DISPLAY(s));
279 
280   s->view = view;
281   s->old_user_offset_x = -1;
282   s->user_offset_x = -1;
283   s->old_play_offset_x = -1;
284   s->play_offset_x = -1;
285 
286   /*  gtk_signal_emit(GTK_OBJECT(s), sample_display_signals[SIG_WINDOW_CHANGED], s->view->start, s->view->start + (s->view->end - s->view->start));*/
287 
288   s->selecting = SELECTING_NOTHING;
289   s->selection_mode = SELECTION_MODE_NONE;
290 
291   gtk_widget_queue_draw(GTK_WIDGET(s));
292 }
293 
294 void
sample_display_refresh_user_marker(SampleDisplay * s)295 sample_display_refresh_user_marker (SampleDisplay *s)
296 {
297   sw_sample * sample;
298   gint x, width;
299 
300   g_return_if_fail(s != NULL);
301   g_return_if_fail(IS_SAMPLE_DISPLAY(s));
302 
303   if(!IS_INITIALIZED(s))
304     return;
305 
306   sample = s->view->sample;
307 
308   s->user_offset_x = OFFSET_TO_XPOS(sample->user_offset);
309 
310   /* paint changed user cursor pos */
311   if (s->old_user_offset_x != s->user_offset_x) {
312     x = CLAMP (s->old_user_offset_x - 15, 0, s->width);
313     width = MIN (s->width - x, 29);
314     gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, width, s->height);
315   }
316 
317   /* paint cursor */
318   if (s->user_offset_x >= 0 && s->user_offset_x <= s->width) {
319     x = CLAMP (s->user_offset_x - 15, 0, s->width);
320     width = MIN (s->width - x, 29);
321 
322     gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, width, s->height);
323 
324     s->old_user_offset_x = s->user_offset_x;
325   }
326 }
327 
328 void
sample_display_refresh_play_marker(SampleDisplay * s)329 sample_display_refresh_play_marker (SampleDisplay *s)
330 {
331   sw_sample * sample;
332   sw_head * head;
333   gint x, width;
334 
335   g_return_if_fail(s != NULL);
336   g_return_if_fail(IS_SAMPLE_DISPLAY(s));
337 
338   if(!IS_INITIALIZED(s))
339     return;
340 
341   sample = s->view->sample;
342   head = sample->play_head;
343 
344   s->play_offset_x = OFFSET_TO_XPOS(head->offset);
345 
346   /* paint play offset */
347   if (s->old_play_offset_x != s->play_offset_x) {
348     x = CLAMP (s->old_play_offset_x - 15, 0, s->width);
349     width = MIN (s->width - x, 29);
350     gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, width, s->height);
351   }
352 
353   if (s->play_offset_x >= 0 && s->play_offset_x <= s->width) {
354     x = CLAMP (s->play_offset_x - 15, 0, s->width);
355     width = MIN (s->width - x, 29);
356     gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, width, s->height);
357 
358     s->old_play_offset_x = s->play_offset_x;
359   }
360 }
361 
362 void
sample_display_refresh_rec_marker(SampleDisplay * s)363 sample_display_refresh_rec_marker (SampleDisplay *s)
364 {
365   sw_sample * sample;
366   sw_head * rec_head;
367   gint x, width;
368 
369   g_return_if_fail(s != NULL);
370   g_return_if_fail(IS_SAMPLE_DISPLAY(s));
371 
372   if(!IS_INITIALIZED(s))
373     return;
374 
375   sample = s->view->sample;
376   rec_head = sample->rec_head;
377 
378   if (rec_head == NULL) return;
379 
380   s->rec_offset_x = OFFSET_TO_XPOS(rec_head->offset);
381 
382   /* paint rec offset */
383   if (s->old_rec_offset_x != s->rec_offset_x) {
384     x = CLAMP (s->old_rec_offset_x - 15, 0, s->width);
385     width = MIN (s->width - x, 29);
386     gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, width, s->height);
387   }
388 
389   if (s->rec_offset_x >= 0 && s->rec_offset_x <= s->width) {
390     x = CLAMP (s->rec_offset_x - 15, 0, s->width);
391     width = MIN (s->width - x, 29);
392     gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, width, s->height);
393 
394     s->old_rec_offset_x = s->rec_offset_x;
395   }
396 }
397 
398 static void
sample_display_refresh_sels(SampleDisplay * s)399 sample_display_refresh_sels (SampleDisplay * s)
400 {
401   int x, x2;
402   sw_sample * sample;
403   GList * gl;
404   sw_sel * sel;
405 
406   g_return_if_fail(s != NULL);
407   g_return_if_fail(IS_SAMPLE_DISPLAY(s));
408 
409   if(!IS_INITIALIZED(s))
410     return;
411 
412   sample = s->view->sample;
413 
414   /* paint marching ants */
415 
416   /* real selection */
417   for (gl = sample->sounddata->sels; gl; gl = gl->next) {
418     sel = (sw_sel *)gl->data;
419 
420     x = OFFSET_TO_XPOS(sel->sel_start);
421     x2 = OFFSET_TO_XPOS(sel->sel_end);
422 
423     if ((x >= 0) && (x <= s->width)) {
424       gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, 1, s->height);
425     }
426     if ((x2 >= 0) && (x2 <= s->width)) {
427       gtk_widget_queue_draw_area (GTK_WIDGET(s), x2, 0, 1, s->height);
428     }
429 
430     if ((x <= s->width) && (x2 >= 0)) {
431       x = CLAMP (x, 0, s->width);
432       x2 = CLAMP (x2, 0, s->width);
433       gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, x2 - x, 1);
434       gtk_widget_queue_draw_area (GTK_WIDGET(s), x, s->height - 1, x2 - x, 1);
435     }
436   }
437 
438   /* temporary selection */
439   sel = sample->tmp_sel;
440 
441   if (sel) {
442     x = OFFSET_TO_XPOS(sel->sel_start);
443     x2 = OFFSET_TO_XPOS(sel->sel_end);
444 
445     if ((x >= 0) && (x <= s->width)) {
446       gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, 1, s->height);
447     }
448     if ((x2 >= 0) && (x2 <= s->width)) {
449       gtk_widget_queue_draw_area (GTK_WIDGET(s), x2, 0, 1, s->height);
450     }
451 
452     if ((x <= s->width) && (x2 >= 0)) {
453       x = CLAMP (x, 0, s->width);
454       x2 = CLAMP (x2, 0, s->width);
455       gtk_widget_queue_draw_area (GTK_WIDGET(s), x, 0, x2 - x, 1);
456       gtk_widget_queue_draw_area (GTK_WIDGET(s), x, s->height - 1, x2 - x, 1);
457     }
458   }
459 }
460 
461 void
sample_display_set_cursor(SampleDisplay * s,GdkCursor * cursor)462 sample_display_set_cursor (SampleDisplay * s, GdkCursor * cursor)
463 {
464   gdk_window_set_cursor (GTK_WIDGET(s)->window, cursor);
465 }
466 
467 void
sample_display_set_default_cursor(SampleDisplay * s)468 sample_display_set_default_cursor (SampleDisplay * s)
469 {
470   GdkCursor * cursor;
471 
472   switch (s->view->current_tool) {
473   case TOOL_SELECT:
474     cursor = sweep_cursors[SWEEP_CURSOR_CROSSHAIR];
475     break;
476   case TOOL_ZOOM:
477     cursor = sweep_cursors[SWEEP_CURSOR_ZOOM_IN];
478     break;
479   case TOOL_MOVE:
480     cursor = sweep_cursors[SWEEP_CURSOR_MOVE];
481     break;
482   case TOOL_SCRUB:
483     cursor = sweep_cursors[SWEEP_CURSOR_NEEDLE];
484     break;
485   case TOOL_PENCIL:
486     cursor = sweep_cursors[SWEEP_CURSOR_PENCIL];
487     break;
488   case TOOL_NOISE:
489     cursor = sweep_cursors[SWEEP_CURSOR_NOISE];
490     break;
491   case TOOL_HAND:
492     cursor = sweep_cursors[SWEEP_CURSOR_HAND_OPEN];
493     break;
494   default:
495     cursor = NULL;
496     break;
497   }
498 
499   gdk_window_set_cursor (GTK_WIDGET(s)->window, cursor);
500 }
501 
502 static void
sample_display_set_intersect_cursor(SampleDisplay * s)503 sample_display_set_intersect_cursor (SampleDisplay * s)
504 {
505   sw_sample * sample = s->view->sample;
506   GtkWidget * widget = GTK_WIDGET(s);
507 
508   /* Check if there are other selection regions.
509    * NB. This assumes that tmp_sel has already been
510    * set.
511    */
512   if (sample_sel_nr_regions(sample) > 0) {
513     SET_CURSOR(widget, HORIZ_PLUS);
514   } else {
515     SET_CURSOR(widget, HORIZ);
516   }
517 }
518 
519 static void
sample_display_set_subtract_cursor(SampleDisplay * s)520 sample_display_set_subtract_cursor (SampleDisplay * s)
521 {
522   sw_sample * sample = s->view->sample;
523   GtkWidget * widget = GTK_WIDGET(s);
524 
525   /* Check if there are other selection regions.
526    * NB. This assumes that tmp_sel has already been
527    * set.
528    */
529   if (sample_sel_nr_regions(sample) > 0) {
530     SET_CURSOR(widget, HORIZ_MINUS);
531   } else {
532     SET_CURSOR(widget, HORIZ);
533   }
534 }
535 
536 void
sample_display_set_window(SampleDisplay * s,sw_framecount_t start,sw_framecount_t end)537 sample_display_set_window (SampleDisplay *s,
538 			   sw_framecount_t start,
539 			   sw_framecount_t end)
540 {
541   sw_framecount_t len, vlen;
542 
543   g_return_if_fail(s != NULL);
544   g_return_if_fail(IS_SAMPLE_DISPLAY(s));
545 
546   len = s->view->sample->sounddata->nr_frames;
547   vlen = end - start;
548 
549   g_return_if_fail(end >= start);
550 
551 
552   if (vlen > len) {
553     /* Align to middle if entire length of sample is visible */
554     start = (len - vlen) / 2;
555     end = start + vlen;
556   } else if (vlen == 0 && len > 0) {
557     /* Zoom normal if window is zero but there is data; eg. after pasting
558      * into an empty buffer */
559     start = 0;
560     end = MIN (len, s->width * 1024);
561   }
562 
563   s->view->start = start;
564   s->view->end = end;
565 
566   sample_display_refresh_user_marker (s);
567 
568   g_signal_emit_by_name(GTK_OBJECT(s), "window-changed");
569 
570   s->mouse_offset = XPOS_TO_OFFSET (s->mouse_x);
571   g_signal_emit_by_name(GTK_OBJECT(s),
572 		  "mouse-offset-changed");
573 
574   gtk_widget_queue_draw(GTK_WIDGET(s));
575 }
576 
577 static void
sample_display_init_display(SampleDisplay * s,int w,int h)578 sample_display_init_display (SampleDisplay *s,
579 			     int w,
580 			     int h)
581 {
582   GdkWindow * window;
583   GdkVisual * visual;
584   sw_framecount_t len, vlen, vlendelta;
585 
586 
587   /* If the window was already displaying data before this event
588    * was received, we are handling a resize event.
589    * We want to ensure that the relative size of displayed data
590    * remains constant over the resize -- the window simply 'uncovers'
591    * or 'covers' the visualisation.
592    */
593   if (s->width > 1) {
594 
595     len = s->view->sample->sounddata->nr_frames;
596     vlen = s->view->end - s->view->start;
597 
598     /* If we're already viewing EXACTLY the entire sample,
599      * and dealing with a widening of the window, then
600      * allow the visualisation to stretch. */
601     if (s->view->start == 0 && vlen == len && w > s->width)
602       goto stretch;
603 
604     /*
605      * Funky integer error minimisation: this gives non-lossy results,
606      *  as opposed to just using:
607      *
608      * s->view->end = s->view->start +
609      *   (s->view->end - s->view->start) * w / s->width;
610      *
611      * However there is a noticeable waver when resizing the display
612      * when zoomed in far enough that individual samples are visible.
613      *
614      * The alternative is to represent s->view->end (from which the
615      * visible length is determined) as a floating point number.
616      */
617 
618     vlendelta = vlen * (w - s->width) / s->width;
619 
620     if (vlen+vlendelta > len) {
621       s->view->start = (len - (vlen+vlendelta)) / 2;
622       s->view->end = s->view->start + vlen + vlendelta;
623     } else if (s->view->start < 0) {
624       s->view->end += vlendelta - s->view->start;
625       s->view->start = 0;
626     } else if (s->view->end > len) {
627       s->view->start = s->view->end - vlen - vlendelta;
628       s->view->end = len;
629     } else {
630       s->view->end += vlendelta;
631     }
632 
633     g_signal_emit_by_name(GTK_OBJECT(s), "window-changed");
634   }
635 
636  stretch:
637 
638   s->width = w;
639   s->height = h;
640 
641   window = GTK_WIDGET(s)->window;
642   visual = gdk_rgb_get_visual();
643 
644 #if DOUBLE_BUFFER
645   if(s->backing_pixmap) {
646     g_object_unref(s->backing_pixmap);
647   }
648   s->backing_pixmap = gdk_pixmap_new (GTK_WIDGET(s)->window,
649                                       w, h, visual->depth);
650 #endif
651 
652 }
653 
654 static void
sample_display_size_request(GtkWidget * widget,GtkRequisition * requisition)655 sample_display_size_request (GtkWidget *widget,
656 			     GtkRequisition *requisition)
657 {
658   requisition->width = 40;
659   requisition->height = 20;
660 }
661 
662 static void
sample_display_size_allocate(GtkWidget * widget,GtkAllocation * allocation)663 sample_display_size_allocate (GtkWidget *widget,
664 			      GtkAllocation *allocation)
665 {
666   SampleDisplay *s;
667 
668   g_return_if_fail (widget != NULL);
669   g_return_if_fail (IS_SAMPLE_DISPLAY (widget));
670   g_return_if_fail (allocation != NULL);
671 
672   widget->allocation = *allocation;
673   if (GTK_WIDGET_REALIZED (widget)) {
674     s = SAMPLE_DISPLAY (widget);
675 
676     gdk_window_move_resize (widget->window,
677 			    allocation->x, allocation->y,
678 			    allocation->width, allocation->height);
679 
680     sample_display_init_display(s, allocation->width, allocation->height);
681   }
682 }
683 
684 static void
sample_display_realize(GtkWidget * widget)685 sample_display_realize (GtkWidget *widget)
686 {
687   GdkWindowAttr attributes;
688   gint attributes_mask;
689   SampleDisplay *s;
690   gint i;
691 
692   g_return_if_fail (widget != NULL);
693   g_return_if_fail (IS_SAMPLE_DISPLAY (widget));
694 
695   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
696   s = SAMPLE_DISPLAY(widget);
697 
698   attributes.x = widget->allocation.x;
699   attributes.y = widget->allocation.y;
700   attributes.width = widget->allocation.width;
701   attributes.height = widget->allocation.height;
702   attributes.wclass = GDK_INPUT_OUTPUT;
703   attributes.window_type = GDK_WINDOW_CHILD;
704 #if 0
705   attributes.event_mask = gtk_widget_get_events (widget)
706     | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
707     | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK
708     | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
709     GDK_FOCUS_CHANGE_MASK | GDK_KEY_PRESS_MASK;
710 #else
711   attributes.event_mask = GDK_ALL_EVENTS_MASK;
712 #endif
713 
714   attributes.visual = gtk_widget_get_visual (widget);
715   attributes.colormap = gtk_widget_get_colormap (widget);
716 
717   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
718   widget->window = gdk_window_new (widget->parent->window,
719 				   &attributes, attributes_mask);
720 
721   widget->style = gtk_style_attach (widget->style, widget->window);
722 
723   s->width = 0;
724 
725   s->bg_gc = gdk_gc_new(widget->window);
726   gdk_gc_set_foreground(s->bg_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_BG]);
727 
728   s->fg_gc = gdk_gc_new(widget->window);
729   gdk_gc_set_foreground(s->fg_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_FG]);
730 
731   s->zeroline_gc = gdk_gc_new(widget->window);
732   gdk_gc_set_foreground(s->zeroline_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_ZERO]);
733 
734   s->play_gc = gdk_gc_new(widget->window);
735   gdk_gc_set_foreground(s->play_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_PLAY]);
736   gdk_gc_set_function (s->play_gc, GDK_OR_REVERSE);
737 
738   s->user_gc = gdk_gc_new(widget->window);
739   gdk_gc_set_foreground(s->user_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_PAUSE]);
740 
741   s->rec_gc = gdk_gc_new(widget->window);
742   gdk_gc_set_foreground(s->rec_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_REC]);
743 
744   s->sel_gc = gdk_gc_new(widget->window);
745   gdk_gc_set_foreground(s->sel_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_SEL]);
746   gdk_gc_set_line_attributes(s->sel_gc, 1 /* line width */,
747 			     GDK_LINE_DOUBLE_DASH,
748 			     GDK_CAP_BUTT,
749 			     GDK_JOIN_MITER);
750 
751   s->tmp_sel_gc = gdk_gc_new(widget->window);
752   gdk_gc_set_foreground(s->tmp_sel_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_TMP_SEL]);
753   gdk_gc_set_function (s->tmp_sel_gc, GDK_XOR);
754 
755   s->crossing_gc = gdk_gc_new(widget->window);
756   gdk_gc_set_foreground(s->crossing_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_CROSSING]);
757 
758   s->minmax_gc = gdk_gc_new (widget->window);
759   gdk_gc_set_foreground(s->minmax_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_MINMAX]);
760 
761   s->highlight_gc = gdk_gc_new (widget->window);
762   gdk_gc_set_foreground(s->highlight_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_HIGHLIGHT]);
763 
764   s->lowlight_gc = gdk_gc_new (widget->window);
765   gdk_gc_set_foreground(s->lowlight_gc, &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_LOWLIGHT]);
766 
767   for (i = 0; i < VIEW_COLOR_MAX; i++) {
768     s->bg_gcs[i] = gdk_gc_new (widget->window);
769     gdk_gc_set_foreground(s->bg_gcs[i], &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->bg_colors[i]);
770 
771     s->fg_gcs[i] = gdk_gc_new (widget->window);
772     gdk_gc_set_foreground(s->fg_gcs[i], &SAMPLE_DISPLAY_CLASS(GTK_WIDGET_GET_CLASS(widget))->fg_colors[i]);
773   }
774 
775   sample_display_init_display(s, attributes.width, attributes.height);
776 
777   sample_display_set_default_cursor (s);
778 
779   gdk_window_set_user_data (widget->window, widget);
780 }
781 
782 
783 static void
sample_display_draw_data_channel(GdkDrawable * win,const SampleDisplay * s,int x,int y,int width,int height,int channel)784 sample_display_draw_data_channel (GdkDrawable * win,
785 				  const SampleDisplay * s,
786 				  int x,
787 				  int y,
788 				  int width,
789 				  int height,
790 				  int channel)
791 {
792   GList * gl;
793   GdkGC * gc, * fg_gc;
794   sw_sel * sel;
795   int x1, x2, y1;
796   sw_audio_t vhigh, vlow;
797   sw_audio_intermediate_t totpos, totneg;
798   sw_audio_t d, maxpos, avgpos, minneg, avgneg;
799   sw_audio_t prev_maxpos, prev_minneg;
800   sw_framecount_t i, step, nr_frames, nr_pos, nr_neg;
801   sw_sample * sample;
802   const int channels = s->view->sample->sounddata->format->channels;
803 
804   sample = s->view->sample;
805 
806   fg_gc = s->fg_gcs[sample->color];
807 
808   gdk_draw_rectangle(win, s->bg_gcs[sample->color],
809 		     TRUE, x, y, width, height);
810 
811   /* Draw real selection */
812   for (gl = sample->sounddata->sels; gl; gl = gl->next) {
813     sel = (sw_sel *)gl->data;
814 
815     x1 = OFFSET_TO_XPOS(sel->sel_start);
816     x1 = CLAMP(x1, x, x+width);
817 
818     x2 = OFFSET_TO_XPOS(sel->sel_end);
819     x2 = CLAMP(x2, x, x+width);
820 
821     if (x2 - x1 > 1){
822       gdk_draw_rectangle (win, s->crossing_gc, TRUE,
823 			  x1, y, x2 - x1, y + height -1);
824     }
825   }
826 
827   /* Draw temporary selection */
828   sel = sample->tmp_sel;
829 
830   if (sel) {
831     if (sel->sel_start != sel->sel_end) {
832       x1 = OFFSET_TO_XPOS(sel->sel_start);
833       x1 = CLAMP(x1, x, x+width);
834 
835       x2 = OFFSET_TO_XPOS(sel->sel_end);
836       x2 = CLAMP(x2, x, x+width);
837 
838       if (x2 - x1 > 1) {
839 	gdk_draw_rectangle (win, s->tmp_sel_gc, TRUE,
840 			    x1, y, x2 - x1, y + height -1);
841       }
842     }
843   }
844 
845   vhigh = s->view->vhigh;
846   vlow = s->view->vlow;
847 
848 #define YPOS(v) CLAMP(y + height - ((((v) - vlow) * height) \
849 		               / (vhigh - vlow)), y, y+height)
850 
851   /* Draw zero and 6db lines */
852   y1 = YPOS(0.5);
853   gdk_draw_line(win, s->zeroline_gc,
854 		x, y1, x + width - 1, y1);
855 
856   y1 = YPOS(0.0);
857   gdk_draw_line(win, s->zeroline_gc,
858 		x, y1, x + width - 1, y1);
859 
860   y1 = YPOS(-0.5);
861   gdk_draw_line(win, s->zeroline_gc,
862 		x, y1, x + width - 1, y1);
863 
864   totpos = totneg = 0.0;
865   maxpos = minneg = prev_maxpos = prev_minneg = 0.0;
866 
867   nr_frames = sample->sounddata->nr_frames;
868 
869   /* 'step' ensures that no more than STEP_MAX values get looked at
870    * per pixel */
871   step = MAX (1, PIXEL_TO_OFFSET(1)/STEP_MAX);
872 
873 #ifdef LEGACY_DRAW_MODE
874   {
875     int py, ty;
876     sw_audio_t peak;
877 
878     py = y+height/2;
879 
880     while (width >= 0) {
881       peak = 0;
882       for (i = OFFSET_RANGE(nr_frames, XPOS_TO_OFFSET(x));
883 	   i < OFFSET_RANGE(nr_frames, XPOS_TO_OFFSET(x+1));
884 	   i+=step) {
885 	d = ((sw_audio_t *)sample->sounddata->data)[i*channels + channel];
886 	if (fabs(d) > fabs(peak)) peak = d;
887       }
888 
889       ty = YPOS(peak);
890 
891       gdk_draw_line (win, fg_gc, x-1, py, x, ty);
892 
893       py = ty;
894 
895       x++;
896       width--;
897     }
898   }
899 
900 #else
901 
902   for (i = OFFSET_RANGE (nr_frames, XPOS_TO_OFFSET(x-1));
903        i < OFFSET_RANGE (nr_frames, XPOS_TO_OFFSET(x));
904        i += step) {
905     d = ((sw_audio_t *)sample->sounddata->data)[i*channels + channel];
906     if (d >= 0) {
907       if (d > prev_maxpos) prev_maxpos = d;
908     } else {
909       if (d < prev_minneg) prev_minneg = d;
910     }
911   }
912 
913   while(width >= 0) {
914     nr_pos = nr_neg = 0;
915     totpos = totneg = 0;
916 
917     maxpos = minneg = 0;
918 
919     /* lock the sounddata against destructive ops to make sure
920      * sounddata->data doesn't change under us */
921     g_mutex_lock (sample->ops_mutex);
922 
923     for (i = OFFSET_RANGE(nr_frames, XPOS_TO_OFFSET(x));
924 	 i < OFFSET_RANGE(nr_frames, XPOS_TO_OFFSET(x+1));
925 	 i+=step) {
926       d = ((sw_audio_t *)sample->sounddata->data)[i*channels + channel];
927       if (d >= 0) {
928 	if (d > maxpos) maxpos = d;
929 	totpos += d;
930 	nr_pos++;
931       } else {
932 	if (d < minneg) minneg = d;
933 	totneg += d;
934 	nr_neg++;
935       }
936     }
937 
938     g_mutex_unlock (sample->ops_mutex);
939 
940     if (nr_pos > 0) {
941       avgpos = totpos / nr_pos;
942     } else {
943       avgpos = 0;
944     }
945 
946     if (nr_neg > 0) {
947       avgneg = totneg / nr_neg;
948     } else {
949       avgneg = 0;
950     }
951 
952     gdk_draw_line(win, s->minmax_gc,
953 		  x, YPOS(maxpos),
954 		  x, YPOS(minneg));
955 
956     gc = maxpos > prev_maxpos ? s->highlight_gc : s->lowlight_gc;
957     gdk_draw_line(win, gc,
958 		  x, YPOS(prev_maxpos),
959 		  x, YPOS(maxpos));
960 
961     gc = minneg > prev_minneg ? s->lowlight_gc : s->highlight_gc;
962     gdk_draw_line(win, gc,
963 		  x, YPOS(prev_minneg),
964 		  x, YPOS(minneg));
965 
966     gdk_draw_line(win, fg_gc,
967 		  x, YPOS(avgpos),
968 		  x, YPOS(avgneg));
969 
970     prev_maxpos = maxpos;
971     prev_minneg = minneg;
972 
973     x++;
974     width--;
975   }
976 #endif
977 
978 }
979 
980 static void
sample_display_draw_data(GdkDrawable * win,const SampleDisplay * s,int x,int width)981 sample_display_draw_data (GdkDrawable *win, const SampleDisplay *s,
982 			  int x, int width)
983 {
984   const int sh = s->height;
985   int start_x, end_x, i, cy, cheight, cerr;
986   const int channels = s->view->sample->sounddata->format->channels;
987 
988   if (width == 0)
989     return;
990 
991   g_return_if_fail(x >= 0);
992   g_return_if_fail(x + width <= s->width);
993 
994 #ifdef DEBUG
995   g_print("draw_data: view %u --> %u, drawing x=%d, width=%d\n",
996 	  s->view->start, s->view->end, x, width);
997 #endif
998 
999   start_x = OFFSET_TO_XPOS(0);
1000   end_x = OFFSET_TO_XPOS(s->view->sample->sounddata->nr_frames);
1001 
1002   if (start_x > x + width || end_x < x) {
1003     gtk_style_apply_default_background (GTK_WIDGET(s)->style, win,
1004 					TRUE, GTK_STATE_NORMAL,
1005 					NULL,
1006 					x, 0,
1007 					width, sh);
1008     return;
1009   }
1010 
1011   if (start_x > x) {
1012     gtk_style_apply_default_background (GTK_WIDGET(s)->style, win,
1013 					TRUE, GTK_STATE_NORMAL,
1014 					NULL,
1015 					x, 0,
1016 					start_x - x, sh);
1017 
1018     if (start_x > 0)
1019       gdk_draw_line (win, s->lowlight_gc, start_x-1, 0, start_x-1, sh);
1020 
1021     x = start_x;
1022   }
1023 
1024   if (end_x < x + width) {
1025     gtk_style_apply_default_background (GTK_WIDGET(s)->style, win,
1026 					TRUE, GTK_STATE_NORMAL,
1027 					NULL,
1028 					end_x, 0,
1029 					x + width - end_x, sh);
1030 
1031     gdk_draw_line (win, s->highlight_gc,
1032 		   end_x, 0, end_x, sh);
1033 
1034     width = end_x - x;
1035   }
1036 
1037 #if 0
1038   cheight = (sh+3)/channels;
1039   cerr = (sh+3) - (channels * cheight);
1040   if (cerr == channels - 1) {
1041     cheight++;
1042     cerr = 0;
1043   }
1044   cy = 0;
1045 #else
1046   cheight = sh / channels;
1047   cerr = sh - (channels * cheight);
1048   if (cerr == channels - 1) {
1049     cheight++;
1050     cerr = 0;
1051   }
1052   cy = 0;
1053 #endif
1054 
1055   for (i = 0; i < channels; i++) {
1056     if (i >= 0) {
1057       gtk_style_apply_default_background (GTK_WIDGET(s)->style, win,
1058 					  TRUE, GTK_STATE_NORMAL, NULL,
1059 					  x, cy, width, 1);
1060       cy += 1;
1061 
1062 #if 0
1063       if (i == channels/2) {
1064 	gtk_style_apply_default_background (GTK_WIDGET(s)->style, win,
1065 					    TRUE, GTK_STATE_NORMAL, NULL,
1066 					    x, cy, width, cerr);
1067 	cy += cerr;
1068       }
1069 #endif
1070     }
1071 
1072     sample_display_draw_data_channel (win, s,
1073 				      x, cy, width, cheight-2, i);
1074     cy += cheight-2;
1075 
1076     gtk_style_apply_default_background (GTK_WIDGET(s)->style, win,
1077 					TRUE, GTK_STATE_NORMAL, NULL,
1078 					x, cy, width, 1);
1079     cy += 1;
1080 
1081   }
1082 
1083   if (cy < sh) {
1084     gtk_style_apply_default_background (GTK_WIDGET(s)->style, win,
1085 					TRUE, GTK_STATE_NORMAL, NULL,
1086 					x, cy, width, sh-cy);
1087   }
1088 
1089 }
1090 
1091 /*** CROSSING VECTORS ***/
1092 
1093 #ifdef DRAW_CROSSING_VECTORS
1094 
1095 static void
sample_display_draw_crossing_vector(GdkDrawable * win,GdkGC * gc,const SampleDisplay * s,int x)1096 sample_display_draw_crossing_vector (GdkDrawable * win,
1097 				     GdkGC * gc,
1098 				     const SampleDisplay * s,
1099 				     int x)
1100 {
1101   sw_sample * sample = s->view->sample;
1102   const int sh = s->height;
1103   int cx1, cx2, cy1, cy2;
1104 
1105 #define VRAD 8
1106 
1107   cx1 = ( x > VRAD ? VRAD : 0 );
1108   cx2 = ( x < sample->sounddata->nr_frames - VRAD ? VRAD : 0 );
1109 
1110   cy1 = ((sw_audio_t *)sample->sounddata->data)[OFFSET_RANGE(sample->sounddata->nr_frames, XPOS_TO_OFFSET(x)) - cx1];
1111   cy2 = ((sw_audio_t *)sample->sounddata->data)[OFFSET_RANGE(sample->sounddata->nr_frames, XPOS_TO_OFFSET(x)) + cx2];
1112 
1113   gdk_draw_line(win, s->crossing_gc,
1114 		x - cx1, (((cy1 + 1.0) * sh) / 2.0),
1115 		x + cx2, (((cy2 + 1.0) * sh) / 2.0));
1116 }
1117 
1118 #endif
1119 
1120 /*** MARCHING ANTS ***/
1121 
1122 /*
1123  * sample_display_sel_box_march_ants ()
1124  *
1125  * gtk_idle function to move the marching ants used by
1126  * selections.
1127  */
1128 static gint
sd_march_ants(gpointer data)1129 sd_march_ants (gpointer data)
1130 {
1131   SampleDisplay * s = (SampleDisplay *)data;
1132   GdkGC * gc = s->sel_gc;
1133   static int dash_offset = 0;
1134 
1135   gdk_gc_set_dashes (gc, dash_offset, sel_dash_list, 2);
1136 
1137   dash_offset++;
1138   dash_offset %= 8;
1139 
1140   sample_display_refresh_sels (s);
1141 
1142   return TRUE;
1143 }
1144 
1145 static void
sd_start_marching_ants_timeout(SampleDisplay * s)1146 sd_start_marching_ants_timeout (SampleDisplay * s)
1147 {
1148   if (s->marching_tag > 0)
1149     g_source_remove (s->marching_tag);
1150 
1151   s->marching_tag = g_timeout_add (MARCH_INTERVAL,
1152 				     (GSourceFunc)sd_march_ants,
1153 				     s);
1154 }
1155 
1156 void
sample_display_start_marching_ants(SampleDisplay * s)1157 sample_display_start_marching_ants (SampleDisplay * s)
1158 {
1159   sd_start_marching_ants_timeout (s);
1160   s->marching = TRUE;
1161 }
1162 
1163 static void
sd_stop_marching_ants_timeout(SampleDisplay * s)1164 sd_stop_marching_ants_timeout (SampleDisplay * s)
1165 {
1166   if (s->marching_tag > 0)
1167     g_source_remove (s->marching_tag);
1168 
1169   s->marching_tag = 0;
1170 }
1171 
1172 void
sample_display_stop_marching_ants(SampleDisplay * s)1173 sample_display_stop_marching_ants (SampleDisplay * s)
1174 {
1175   sd_stop_marching_ants_timeout (s);
1176   s->marching = FALSE;
1177 }
1178 
1179 /*** SELECTION BOXES ***/
1180 
1181 static void
sample_display_draw_sel_box(GdkDrawable * win,GdkGC * gc,const SampleDisplay * s,int x,int width,int draw_left,int draw_right)1182 sample_display_draw_sel_box(GdkDrawable * win,
1183 			    GdkGC * gc,
1184 			    const SampleDisplay * s,
1185 			    int x,
1186 			    int width,
1187 			    int draw_left, int draw_right)
1188 {
1189   if (width <= 0) {
1190     gdk_draw_line (win, gc, x, 0, x, s->height - 1);
1191     return;
1192   }
1193 
1194   /* Must draw individual lines for these: if you optimise by
1195    * drawing a rectangle where possible, the marching ants go
1196    * crazy. We don't want that to happen, they are cute.
1197    */
1198 
1199   gdk_draw_line(win, gc,
1200 		x, 0,
1201 		x+width, 0);
1202   gdk_draw_line(win, gc,
1203 		  x, s->height - 1,
1204 		x+width, s->height - 1);
1205   if (draw_left) {
1206     gdk_draw_line(win, gc,
1207 		  x, 0,
1208 		  x, s->height - 1);
1209 
1210 #ifdef DRAW_CROSSING_VECTORS
1211     /* crossing vector */
1212     sample_display_draw_crossing_vector (win, gc, s, x);
1213 #endif
1214   }
1215   if (draw_right) {
1216     gdk_draw_line(win, gc,
1217 		  x+width, 0,
1218 		  x+width, s->height - 1);
1219 
1220 #ifdef DRAW_CROSSING_VECTORS
1221     /* crossing vector */
1222     sample_display_draw_crossing_vector (win, gc, s, x+width);
1223 #endif
1224   }
1225 }
1226 
1227 static void
sample_display_draw_sel(GdkDrawable * win,const SampleDisplay * s,int x_min,int x_max)1228 sample_display_draw_sel (GdkDrawable * win,
1229 			 const SampleDisplay * s,
1230 			 int x_min, int x_max)
1231 {
1232   sw_sample * sample = s->view->sample;
1233   GList * gl;
1234   sw_sel * sel;
1235   int x, x2;
1236   int l_end, r_end; /* draw left + right ends of sel */
1237 
1238   /* Draw real selection */
1239   for (gl = sample->sounddata->sels; gl; gl = gl->next) {
1240     sel = (sw_sel *)gl->data;
1241 
1242     x = OFFSET_TO_XPOS(sel->sel_start);
1243     x2 = OFFSET_TO_XPOS(sel->sel_end);
1244 
1245     if (x > x_max) break;
1246     if (x2 < x_min) continue;
1247 
1248     l_end = (x >= x_min) && (x <= x_max);
1249     x = CLAMP (x, x_min, x_max);
1250 
1251     r_end = (x2 >= x_min) && (x2 <= x_max);
1252     x2 = CLAMP (x2, x_min, x_max);
1253 
1254     /* draw the selection */
1255     sample_display_draw_sel_box(win, s->sel_gc,
1256 				s, x, x2 - x - 1,
1257 				l_end, r_end /* draw_ends */);
1258 
1259 
1260   }
1261 
1262   /* Draw temporary selection */
1263   sel = sample->tmp_sel;
1264 
1265   if (sel) {
1266     x = OFFSET_TO_XPOS(sel->sel_start);
1267     l_end = (x >= x_min) && (x <= x_max);
1268     x = CLAMP (x, x_min, x_max);
1269 
1270     x2 = OFFSET_TO_XPOS(sel->sel_end);
1271     r_end = (x2 >= x_min) && (x2 <= x_max);
1272     x2 = CLAMP (x2, x_min, x_max);
1273 
1274     /* draw the selection */
1275     sample_display_draw_sel_box(win, s->tmp_sel_gc,
1276 				s, x, x2 - x - 1,
1277 				l_end, r_end /* draw_ends */);
1278   }
1279 }
1280 
1281 
1282 /*** PLAY MARKER, CURSOR ***/
1283 
1284 #if 0
1285 static int
1286 sample_display_startoffset_to_xpos (SampleDisplay *s,
1287 				    int offset)
1288 {
1289   int d = offset - s->view->start;
1290 
1291   if(d < 0)
1292     return 0;
1293   if(d >= (s->view->end - s->view->start))
1294     return s->width;
1295 
1296   return d * s->width / (s->view->end - s->view->start);
1297 }
1298 
1299 
1300 static int
1301 sample_display_endoffset_to_xpos (SampleDisplay *s,
1302 				  int offset)
1303 {
1304   if((s->view->end - s->view->start) < s->width) {
1305     return sample_display_startoffset_to_xpos(s, offset);
1306   } else {
1307     int d = offset - s->view->start;
1308     int l = (1 - (s->view->end - s->view->start)) / s->width;
1309 
1310     /* you get these tests by setting the complete formula below
1311      * equal to 0 or s->width, respectively, and then resolving
1312      * towards d.
1313      */
1314     if(d < l)
1315       return 0;
1316     if(d > (s->view->end - s->view->start) + l)
1317       return s->width;
1318 
1319     return (d * s->width + (s->view->end - s->view->start) - 1) / (s->view->end - s->view->start);
1320   }
1321 }
1322 #endif /* _{start,end}offset_to_xpos */
1323 
1324 static gint
sd_pulse_cursor(gpointer data)1325 sd_pulse_cursor (gpointer data)
1326 {
1327   SampleDisplay * s = (SampleDisplay *)data;
1328 
1329   if (s->pulse)
1330     gdk_gc_set_function (s->user_gc, GDK_NOOP);
1331   else
1332     gdk_gc_set_function (s->user_gc, GDK_COPY);
1333 
1334   s->pulse = (!s->pulse);
1335 
1336   sample_display_refresh_user_marker (s);
1337 
1338   return TRUE;
1339 }
1340 
1341 void
sample_display_start_cursor_pulse(SampleDisplay * s)1342 sample_display_start_cursor_pulse (SampleDisplay * s)
1343 {
1344   gdk_gc_set_function (s->user_gc, GDK_NOOP);
1345 
1346   sample_display_refresh_user_marker (s);
1347 
1348   s->pulsing_tag = g_timeout_add (PULSE_INTERVAL,
1349 				    (GSourceFunc)sd_pulse_cursor, s);
1350 }
1351 
1352 void
sample_display_stop_cursor_pulse(SampleDisplay * s)1353 sample_display_stop_cursor_pulse (SampleDisplay * s)
1354 {
1355   if (s->pulsing_tag > 0)
1356     g_source_remove (s->pulsing_tag);
1357 
1358   s->pulsing_tag = 0;
1359 
1360   gdk_gc_set_function (s->user_gc, GDK_COPY);
1361 
1362   sample_display_refresh_user_marker (s);
1363 }
1364 
1365 static void
sample_display_draw_user_offset(GdkDrawable * win,GdkGC * gc,SampleDisplay * s,int x,int x_min,int x_max)1366 sample_display_draw_user_offset (GdkDrawable * win, GdkGC * gc,
1367 				 SampleDisplay * s, int x,
1368 				 int x_min, int x_max)
1369 {
1370   GdkPoint poly[4];
1371   gboolean fill;
1372 
1373   if(x >= x_min && x <= x_max) {
1374     gdk_draw_line(win, s->zeroline_gc,
1375 		  x-2, 0,
1376 		  x-2, s->height);
1377 
1378     gdk_draw_line(win, gc,
1379 		  x-1, 0,
1380 		  x-1, s->height);
1381     gdk_draw_line(win, gc,
1382 		  x+1, 0,
1383 		  x+1, s->height);
1384 
1385     gdk_draw_line(win, s->zeroline_gc,
1386 		  x+2, 0,
1387 		  x+2, s->height);
1388 
1389 
1390 
1391     if (!s->view->sample->play_head->going) {
1392       fill = !s->view->sample->play_head->mute;
1393 
1394       if (x < 20) {
1395 	poly[0].x = 11;
1396 	poly[1].x = 11;
1397 	poly[2].x = 14;
1398 	poly[3].x = 14;
1399       } else {
1400 	poly[0].x = x - 8;
1401 	poly[1].x = x - 8;
1402 	poly[2].x = x - 5;
1403 	poly[3].x = x - 5;
1404       }
1405 
1406       poly[0].y = 4;
1407       poly[1].y = 14;
1408       poly[2].y = 14;
1409       poly[3].y = 4;
1410 
1411       gdk_draw_polygon (win, gc, fill, poly, 4);
1412       gdk_draw_polygon (win, s->zeroline_gc, FALSE, poly, 4);
1413 
1414       poly[0].x -= 5;
1415       poly[1].x -= 5;
1416       poly[2].x -= 5;
1417       poly[3].x -= 5;
1418 
1419       gdk_draw_polygon (win, gc, fill, poly, 4);
1420       gdk_draw_polygon (win, s->zeroline_gc, FALSE, poly, 4);
1421     }
1422   }
1423 }
1424 
1425 static void
sample_display_draw_play_offset(GdkDrawable * win,GdkGC * gc,SampleDisplay * s,int x,int x_min,int x_max)1426 sample_display_draw_play_offset (GdkDrawable * win, GdkGC * gc,
1427 				 SampleDisplay * s, int x,
1428 				 int x_min, int x_max)
1429 {
1430   sw_sample * sample;
1431   GdkPoint poly[4];
1432   sw_head * head;
1433 
1434   if(x >= x_min && x <= x_max) {
1435     gdk_draw_rectangle(win, gc, TRUE,
1436 		       x-1, 0,
1437 		       3, s->height);
1438 
1439     sample = s->view->sample;
1440     head = sample->play_head;
1441 
1442     if (head->going) {
1443       if (x < 20) {
1444 	if (head->reverse) {
1445 	  poly[0].x = 14;
1446 	  poly[1].x = 14;
1447 	  poly[2].x = 6;
1448 	} else {
1449 	  poly[0].x = 6;
1450 	  poly[1].x = 6;
1451 	  poly[2].x = 14;
1452 	}
1453       } else {
1454 	if (head->reverse) {
1455 	  poly[0].x = x - 5;
1456 	  poly[1].x = x - 5;
1457 	  poly[2].x = x - 13;
1458 	} else {
1459 	  poly[0].x = x - 13;
1460 	  poly[1].x = x - 13;
1461 	  poly[2].x = x - 5;
1462 	}
1463       }
1464 
1465       poly[0].y = 4;
1466       poly[1].y = 14;
1467       poly[2].y = 9;
1468 
1469       gdk_draw_polygon (win, gc, !head->mute, poly, 3);
1470       gdk_draw_polygon (win, s->zeroline_gc, FALSE, poly, 3);
1471     }
1472   }
1473 }
1474 
1475 static void
sample_display_draw_rec_offset(GdkDrawable * win,GdkGC * gc,SampleDisplay * s,int x,int x_min,int x_max)1476 sample_display_draw_rec_offset (GdkDrawable * win, GdkGC * gc,
1477 				SampleDisplay * s, int x,
1478 				int x_min, int x_max)
1479 {
1480   sw_sample * sample;
1481 
1482   if(x >= x_min && x <= x_max) {
1483 #if 0
1484     gdk_draw_rectangle(win, gc, TRUE,
1485 		       x-1, 0,
1486 		       3, s->height);
1487 #endif
1488 
1489     gdk_draw_line(win, s->zeroline_gc,
1490 		  x-2, 0,
1491 		  x-2, s->height);
1492 #if 1
1493     gdk_draw_line(win, gc,
1494 		  x-1, 0,
1495 		  x-1, s->height);
1496     gdk_draw_line(win, gc,
1497 		  x+1, 0,
1498 		  x+1, s->height);
1499 #endif
1500 
1501     gdk_draw_line(win, s->zeroline_gc,
1502 		  x+2, 0,
1503 		  x+2, s->height);
1504 
1505     sample = s->view->sample;
1506 
1507     if (x < 20) x = 19;
1508     gdk_draw_arc (win, gc, TRUE, x-14, 15, 8, 8, 0, 360 * 64);
1509     gdk_draw_arc (win, s->zeroline_gc, FALSE, x-14, 15, 8, 8, 0, 360 * 64);
1510 
1511   }
1512 }
1513 
1514 
1515 /*** DRAW ***/
1516 
1517 static void
sample_display_draw(GtkWidget * widget,GdkRectangle * area)1518 sample_display_draw (GtkWidget *widget, GdkRectangle *area)
1519 {
1520   SampleDisplay *s = SAMPLE_DISPLAY(widget);
1521   sw_sample * sample = s->view->sample;
1522   GdkDrawable * drawable;
1523 
1524   /*  g_return_if_fail(area->x >= 0);*/
1525   if (area->x < 0) return;
1526   if (area->y < 0) return;
1527 
1528   if(area->width == 0)
1529     return;
1530 
1531   if(area->x + area->width > s->width)
1532     return;
1533 
1534 #ifdef DEBUG
1535     g_print ("sample_display_draw: (%d, %d) [%d, %d]\n",
1536 	     area->x, area->y, area->width, area->height);
1537 #endif
1538 
1539   if(!IS_INITIALIZED(s)) {
1540     gtk_style_apply_default_background (GTK_WIDGET(s)->style, widget->window,
1541 					TRUE, GTK_STATE_NORMAL,
1542 					NULL, 0, 0, s->width, s->height);
1543 #if 0
1544 					area->x, area->y,
1545 					area->width, area->height);
1546 #endif
1547   } else {
1548     const int x_min = area->x;
1549     const int x_max = area->x + area->width;
1550 
1551 #ifdef DOUBLE_BUFFER
1552     drawable = s->backing_pixmap;
1553 #else
1554     drawable = widget->window;
1555 #endif
1556 
1557     /* draw the sample graph */
1558     sample_display_draw_data(drawable, s, x_min, x_max - x_min);
1559 
1560     /* draw the selection bounds */
1561     sample_display_draw_sel (drawable, s, x_min, x_max);
1562 
1563 
1564     /* draw the offset cursors */
1565 
1566     if(!sample->play_head->going) {
1567       /* Draw user offset */
1568       sample_display_draw_user_offset (drawable, s->user_gc,
1569 				       s, s->user_offset_x,
1570 				       x_min, x_max);
1571     } else {
1572 #if 1
1573       /* Draw play offset */
1574       sample_display_draw_play_offset (drawable, s->play_gc,
1575 				       s, s->play_offset_x,
1576 				       x_min, x_max);
1577 #endif
1578       /* Draw user offset */
1579       sample_display_draw_user_offset (drawable, s->user_gc,
1580 				       s, s->user_offset_x,
1581 				       x_min, x_max);
1582 
1583     }
1584 
1585     /* Draw rec offset */
1586     if (sample->rec_head /*&& sample->rec_head->transport_mode != SWEEP_TRANSPORT_STOP*/ ) {
1587       sample_display_draw_rec_offset (drawable, s->rec_gc,
1588 				      s, s->rec_offset_x,
1589 				      x_min, x_max);
1590     }
1591 
1592 #if 0
1593     /* Draw focus indicator */
1594     if (GTK_WIDGET_HAS_FOCUS(widget)) {
1595       /* ??? */
1596     }
1597 #endif
1598 
1599 #ifdef DOUBLE_BUFFER
1600     gdk_draw_pixmap(widget->window, s->fg_gc, s->backing_pixmap,
1601 		    area->x, area->y,
1602 		    area->x, area->y,
1603 		    area->width, area->height);
1604 #endif
1605   }
1606 }
1607 
1608 /*** EVENT HANDLERS ***/
1609 
1610 
1611 static gint
sample_display_expose(GtkWidget * widget,GdkEventExpose * event)1612 sample_display_expose (GtkWidget *widget,
1613 		       GdkEventExpose *event)
1614 {
1615   GdkRectangle * a;
1616   a = &event->area;
1617 
1618 #ifdef DEBUG
1619   g_print ("received expose event for (%d, %d) [%d, %d]; %d follow\n",
1620 	   a->x, a->y, a->width, a->height, event->count);
1621 #endif
1622 
1623   sample_display_draw (widget, a);
1624 
1625   return FALSE;
1626 }
1627 
1628 static gint
sample_display_hand_scroll(SampleDisplay * s)1629 sample_display_hand_scroll (SampleDisplay * s)
1630 {
1631   gint new_win_start, win_length;
1632   gfloat step;
1633 
1634   win_length = s->view->end - s->view->start;
1635 
1636   step = win_length * 1.0 / s->width;
1637 
1638   new_win_start = s->view->start + s->hand_scroll_delta * step;
1639 
1640   new_win_start = CLAMP(new_win_start, 0,
1641 			s->view->sample->sounddata->nr_frames -
1642 			(s->view->end - s->view->start));
1643 
1644   if(new_win_start != s->view->start) {
1645     sample_display_set_window (s,
1646 			       new_win_start,
1647 			       new_win_start + win_length);
1648   } else {
1649 	  s->hand_scroll_delta = 0;
1650   }
1651 /*
1652   g_print ("s->delta: %i new_win_start: %i\n", s->hand_scroll_delta, new_win_start);
1653 */
1654   s->hand_scroll_delta *= 0.98;
1655 
1656   return (s->hand_scroll_delta != 0);
1657 }
1658 
1659 static gint
sample_display_scroll_left(gpointer data)1660 sample_display_scroll_left (gpointer data)
1661 {
1662   SampleDisplay * s = (SampleDisplay *)data;
1663   int new_win_start, win_length;
1664 
1665   win_length = s->view->end - s->view->start;
1666   new_win_start = s->view->start - win_length/8;
1667 
1668   new_win_start = CLAMP(new_win_start, 0,
1669 			s->view->sample->sounddata->nr_frames -
1670 			(s->view->end - s->view->start));
1671 
1672   if(new_win_start != s->view->start) {
1673     sample_display_set_window (s,
1674 			       new_win_start,
1675 			       new_win_start + win_length);
1676   }
1677 
1678   s->view->sample->tmp_sel->sel_start = new_win_start;
1679 
1680   return (new_win_start > 0);
1681 }
1682 
1683 static gint
sample_display_scroll_right(gpointer data)1684 sample_display_scroll_right (gpointer data)
1685 {
1686   SampleDisplay * s = (SampleDisplay *)data;
1687   int new_win_start, win_length;
1688 
1689   win_length = s->view->end - s->view->start;
1690   new_win_start = s->view->start + win_length/8;
1691 
1692   new_win_start = CLAMP(new_win_start, 0,
1693 			s->view->sample->sounddata->nr_frames -
1694 			(s->view->end - s->view->start));
1695 
1696   if(new_win_start != s->view->start) {
1697     sample_display_set_window (s,
1698 			       new_win_start,
1699 			       new_win_start + win_length);
1700   }
1701 
1702   s->view->sample->tmp_sel->sel_end = s->view->end;
1703 
1704   return (new_win_start >= (s->view->end - win_length));
1705 }
1706 
1707 static void
sample_display_handle_playmarker_motion(SampleDisplay * s,int x,int y)1708 sample_display_handle_playmarker_motion (SampleDisplay * s, int x, int y)
1709 {
1710   sw_sample * sample;
1711   sw_framecount_t offset;
1712 
1713   sample = s->view->sample;
1714   offset = XPOS_TO_OFFSET(x);
1715 
1716   sample_set_playmarker (sample, offset, TRUE);
1717 }
1718 
1719 void
sample_display_clear_sel(SampleDisplay * s)1720 sample_display_clear_sel (SampleDisplay * s)
1721 {
1722   sample_clear_tmp_sel (s->view->sample);
1723   s->selecting = SELECTING_NOTHING;
1724   s->selection_mode = SELECTION_MODE_NONE;
1725   sample_display_set_default_cursor (s);
1726   sample_clear_tmp_message (s->view->sample);
1727   g_signal_emit_by_name(GTK_OBJECT(s),
1728 		  "selection-changed");
1729 }
1730 
1731 static void
sample_display_handle_sel_motion(SampleDisplay * s,int x,int y,int just_clicked)1732 sample_display_handle_sel_motion (SampleDisplay *s,
1733 			      int x,
1734 			      int y,
1735 			      int just_clicked)
1736 {
1737   sw_sample * sample;
1738   sw_sel * sel;
1739   int o;
1740   int ss, se;
1741   gboolean scroll_left = FALSE, scroll_right = FALSE;
1742 
1743   if (s->view->current_tool != TOOL_SELECT) return;
1744 
1745   if(!s->selecting)
1746     return;
1747 
1748   if (!s->view->sample)
1749     return;
1750 
1751   if (!s->view->sample->tmp_sel)
1752     return;
1753 
1754   sample = s->view->sample;
1755 
1756   if (sample->edit_mode != SWEEP_EDIT_MODE_READY) {
1757     sample_display_clear_sel (s);
1758     return;
1759   }
1760 
1761   o = XPOS_TO_OFFSET(x);
1762 
1763 #ifdef DEBUG
1764   if (o < 0) {
1765     g_print ("OI! setting an offset < 0!\n");
1766   }
1767 #endif
1768 
1769   if (!sample->play_head->going) {
1770     sample_set_playmarker (sample, o, TRUE);
1771   }
1772 
1773   sel = sample->tmp_sel;
1774 
1775   ss = sel->sel_start;
1776   se = sel->sel_end;
1777 
1778   if(x < 0) {
1779     scroll_left = TRUE;
1780     x = 0;
1781   } else if(x >= s->width - 1) {
1782     scroll_right = TRUE;
1783     x = s->width - 1;
1784   }
1785 
1786   if (just_clicked) {
1787     ss = o;
1788     se = o+1;
1789   } else {
1790     switch (s->selecting) {
1791     case SELECTING_SELECTION_START:
1792       if (o < se) {
1793 	ss = o;
1794       } else {
1795 	if (o != ss+1) ss = se;
1796 	se = o;
1797 	s->selecting = SELECTING_SELECTION_END;      }
1798       break;
1799     case SELECTING_SELECTION_END:
1800       if (o > ss) {
1801 	se = o;
1802       } else {
1803 	if (o != se-1) se = ss;
1804 	ss = o;
1805 	s->selecting = SELECTING_SELECTION_START;
1806       }
1807       break;
1808     default:
1809       g_assert_not_reached ();
1810       break;
1811     }
1812   }
1813 
1814   if(sel->sel_start != ss || sel->sel_end != se || just_clicked) {
1815     sel->sel_start = ss;
1816     sel->sel_end = se;
1817     g_signal_emit_by_name(GTK_OBJECT(s),
1818 		    "selection-changed");
1819   }
1820 
1821   if (scroll_left && s->scroll_left_tag == 0) {
1822     if (s->scroll_right_tag != 0) {
1823       g_source_remove (s->scroll_right_tag);
1824       s->scroll_right_tag = 0;
1825     }
1826 
1827     s->scroll_left_tag = g_timeout_add (100, sample_display_scroll_left,
1828 					  (gpointer)s);
1829 
1830   } else if (scroll_right && s->scroll_right_tag == 0) {
1831     if (s->scroll_left_tag != 0) {
1832       g_source_remove (s->scroll_left_tag);
1833       s->scroll_left_tag = 0;
1834     }
1835 
1836     s->scroll_right_tag = g_timeout_add (100, sample_display_scroll_right,
1837 					   (gpointer)s);
1838 
1839   } else if (!scroll_right && !scroll_left) {
1840     if (s->scroll_right_tag != 0) {
1841       g_source_remove (s->scroll_right_tag);
1842       s->scroll_right_tag = 0;
1843     }
1844     if (s->scroll_left_tag != 0) {
1845       g_source_remove (s->scroll_left_tag);
1846       s->scroll_left_tag = 0;
1847     }
1848   }
1849 }
1850 
1851 /* Handle middle mousebutton display window panning */
1852 static void
sample_display_handle_move_motion(SampleDisplay * s,int x,int y)1853 sample_display_handle_move_motion (SampleDisplay *s, int x, int y)
1854 {
1855   sw_sample * sample = s->view->sample;
1856   sw_framecount_t vlen, offset_xpos, new_offset;
1857   int new_win_start;
1858 
1859   vlen = s->view->end - s->view->start;
1860 
1861   offset_xpos = OFFSET_TO_XPOS(sample->user_offset);
1862 
1863   new_win_start =
1864     s->selecting_wins0 + (s->selecting_x0 - x) * vlen / s->width;
1865 
1866   new_win_start = CLAMP(new_win_start, 0,
1867 			sample->sounddata->nr_frames - vlen);
1868 
1869   new_offset = new_win_start + offset_xpos * vlen / s->width;
1870 
1871   sample_set_scrubbing (sample, TRUE);
1872   sample_set_playmarker (sample, new_offset, TRUE);
1873 
1874   if(new_win_start != s->view->start) {
1875     sample_display_set_window (s,
1876 			       new_win_start,
1877 			       new_win_start + vlen);
1878   }
1879 }
1880 
1881 static void
sample_display_handle_pencil_motion(SampleDisplay * s,int x,int y)1882 sample_display_handle_pencil_motion (SampleDisplay * s, int x, int y)
1883 {
1884   sw_sample * sample;
1885   sw_framecount_t offset;
1886   int channel, channels;
1887   sw_audio_t value;
1888   sw_audio_t * sampledata;
1889 
1890   offset = XPOS_TO_OFFSET(x);
1891 
1892   if (offset < s->view->start || offset > s->view->end) return;
1893 
1894   sample = s->view->sample;
1895   sampledata = (sw_audio_t *)sample->sounddata->data;
1896   channels = sample->sounddata->format->channels;
1897 
1898   y = CLAMP (y, 0, s->height);
1899 
1900   channel = YPOS_TO_CHANNEL(y);
1901   value = YPOS_TO_VALUE(y);
1902   sampledata[offset*channels + channel] = value;
1903 
1904 #if 0
1905   if (sample->sounddata->format->channels == 1) {
1906     value = YPOS_TO_VALUE_1(y);
1907     sampledata[offset] = value;
1908   } else {
1909     channel = YPOS_TO_CHANNEL(y);
1910     value = YPOS_TO_VALUE_2(y);
1911     sampledata[offset*2 + channel] = value;
1912   }
1913 #endif
1914 
1915   sample_refresh_views (sample);
1916 }
1917 
1918 static void
sample_display_handle_hand_motion(SampleDisplay * s,int x,int y)1919 sample_display_handle_hand_motion (SampleDisplay * s, int x, int y)
1920 {
1921   gdouble move, vstart, vend;
1922   gdouble step = (gdouble)(s->view->end - s->view->start) / ((gdouble)s->width);
1923   GtkAdjustment * adj = GTK_ADJUSTMENT(s->view->adj);
1924   gint delta;
1925 
1926   delta = s->view->hand_offset - x;
1927 
1928   s->hand_scroll_delta *= 0.9;
1929 
1930   if (abs (delta) > abs (s->hand_scroll_delta))
1931 	  s->hand_scroll_delta = delta;
1932 
1933   if (s->view->hand_offset != x){
1934     move = s->view->hand_offset - x;
1935     move *= step;
1936 
1937     vstart = s->view->start + move;
1938     vend = s->view->end + move;
1939 
1940     if (vstart < 0){
1941 	vstart = 0;
1942 	vend = adj->page_size;
1943     }
1944     if (vend > s->view->sample->sounddata->nr_frames){
1945 	vstart = s->view->sample->sounddata->nr_frames - adj->page_size;
1946 	vend = s->view->sample->sounddata->nr_frames;
1947     }
1948 
1949 	vstart = ceil(vstart + (move < 0 ? 0.5 : -0.5));
1950     vend = ceil(vend + (move < 0 ? 0.5 : -0.5));
1951 
1952     if (s->view->start != vstart && s->view->end != vend)
1953 	    s->view->hand_offset = x;
1954 
1955     s->view->start = vstart;
1956     s->view->end = vend;
1957 
1958     view_refresh_display(s->view);
1959 
1960     gtk_adjustment_set_value( GTK_ADJUSTMENT(s->view->adj), vstart);
1961   }
1962 }
1963 
1964 static void
sample_display_handle_noise_motion(SampleDisplay * s,int x,int y)1965 sample_display_handle_noise_motion (SampleDisplay * s, int x, int y)
1966 {
1967   sw_sample * sample;
1968   sw_framecount_t offset;
1969   int channel;
1970   sw_audio_t value, oldvalue;
1971   sw_audio_t * sampledata;
1972 
1973   offset = XPOS_TO_OFFSET(x);
1974 
1975   if (offset < s->view->start || offset > s->view->end) return;
1976 
1977   sample = s->view->sample;
1978   sampledata = (sw_audio_t *)sample->sounddata->data;
1979 
1980   y = CLAMP (y, 0, s->height);
1981 
1982   value = 2.0 * (random() - RAND_MAX/2) / (sw_audio_t)RAND_MAX;
1983 
1984   if (sample->sounddata->format->channels == 1) {
1985     oldvalue = sampledata[offset];
1986   } else {
1987     channel = YPOS_TO_CHANNEL(y);
1988     offset = offset*2 + channel;
1989     oldvalue = sampledata[offset];
1990   }
1991 
1992   sampledata[offset] = CLAMP(oldvalue * 0.8 + value * 0.2,
1993 			     SW_AUDIO_T_MIN, SW_AUDIO_T_MAX);
1994 
1995   sample_refresh_views (sample);
1996 }
1997 
1998 static void
sample_display_handle_sel_button_press(SampleDisplay * s,int x,int y,GdkModifierType state)1999 sample_display_handle_sel_button_press (SampleDisplay * s, int x, int y,
2000 					GdkModifierType state)
2001 {
2002   sw_sample * sample;
2003   GList * gl;
2004   sw_sel * sel, * tmp_sel = NULL;
2005   int xss, xse;
2006   int min_xs;
2007   gboolean just_clicked = TRUE;
2008 
2009   sample = s->view->sample;
2010 
2011   if (sample->edit_mode != SWEEP_EDIT_MODE_READY) {
2012     sample_display_clear_sel (s);
2013     return;
2014   }
2015 
2016   for (gl = sample->sounddata->sels; gl; gl = gl->next) {
2017 
2018     /* If the cursor is near the current start or end of
2019      * the selection, move that.
2020      */
2021 
2022     sel = (sw_sel *)gl->data;
2023 
2024     xss = OFFSET_TO_XPOS(sel->sel_start);
2025     xse = OFFSET_TO_XPOS(sel->sel_end);
2026 
2027     if(abs(x-xss) < 5) {
2028       sample_set_tmp_sel (sample, s->view, sel);
2029       s->selecting = SELECTING_SELECTION_START;
2030       s->selection_mode = SELECTION_MODE_INTERSECT;
2031       sample_display_set_intersect_cursor (s);
2032       just_clicked = FALSE;
2033       goto motion;
2034     } else if(abs(x-xse) < 5) {
2035       sample_set_tmp_sel (sample, s->view, sel);
2036       s->selecting = SELECTING_SELECTION_END;
2037       s->selection_mode = SELECTION_MODE_INTERSECT;
2038       sample_display_set_intersect_cursor (s);
2039       just_clicked = FALSE;
2040       goto motion;
2041     }
2042   }
2043 
2044   /* If shift is held down, move the closest selection edge to the mouse */
2045 
2046   if ((state & GDK_SHIFT_MASK) && (sample->sounddata->sels != NULL)) {
2047     min_xs = G_MAXINT;
2048 
2049     for (gl = sample->sounddata->sels; gl; gl = gl->next) {
2050       sel = (sw_sel *)gl->data;
2051 
2052       xss = OFFSET_TO_XPOS(sel->sel_start);
2053       xse = OFFSET_TO_XPOS(sel->sel_end);
2054 
2055       if (abs(x-xss) > min_xs) break;
2056 
2057       tmp_sel = sel;
2058 
2059       min_xs = abs(x-xss);
2060 
2061       s->selecting = SELECTING_SELECTION_START;
2062 
2063       if (abs(x-xse) > min_xs) break;
2064 
2065       min_xs = abs(x-xse);
2066 
2067       s->selecting = SELECTING_SELECTION_END;
2068     }
2069 
2070     sample_set_tmp_sel (sample, s->view, tmp_sel);
2071     s->selection_mode = SELECTION_MODE_INTERSECT;
2072     sample_display_set_intersect_cursor (s);
2073     just_clicked = FALSE;
2074     goto motion;
2075   }
2076 
2077   /* Otherwise, start a new selection region. */
2078 
2079   sample_set_tmp_sel_1(sample, s->view,
2080 		       XPOS_TO_OFFSET(x),
2081 		       XPOS_TO_OFFSET(x)+1);
2082 
2083   s->selecting = SELECTING_SELECTION_END;
2084 
2085   if(state & GDK_CONTROL_MASK) {
2086     s->selection_mode = SELECTION_MODE_INTERSECT;
2087     sample_display_set_intersect_cursor (s);
2088   } else if (state & GDK_MOD1_MASK) /* how to get ALT? */{
2089     s->selection_mode = SELECTION_MODE_SUBTRACT;
2090     sample_display_set_subtract_cursor (s);
2091   } else {
2092     s->selection_mode = SELECTION_MODE_REPLACE;
2093     SET_CURSOR(GTK_WIDGET(s), HORIZ);
2094   }
2095 
2096   just_clicked = TRUE;
2097 
2098  motion:
2099 
2100   sample_set_tmp_message (sample, _(selection_mode_names[s->selection_mode]));
2101   sample_set_progress_ready (sample);
2102 
2103   sample_display_handle_sel_motion (s, x, y, just_clicked);
2104 }
2105 
2106 static gint
sample_display_on_playmarker(SampleDisplay * s,gint x,gint y)2107 sample_display_on_playmarker (SampleDisplay * s, gint x, gint y)
2108 {
2109   gint xp = OFFSET_TO_XPOS(s->view->sample->user_offset);
2110 
2111   if (abs(x-xp) < 5 || ((abs(x-xp) < 15) && (y < 17)))
2112     return TRUE;
2113 
2114   return FALSE;
2115 }
2116 
2117 static gint
sample_display_on_sel(SampleDisplay * s,gint x,gint y)2118 sample_display_on_sel (SampleDisplay * s, gint x, gint y)
2119 {
2120   GList * gl;
2121   sw_sel * sel;
2122   int xss, xse;
2123 
2124   for (gl = s->view->sample->sounddata->sels; gl; gl = gl->next) {
2125     sel = (sw_sel *)gl->data;
2126 
2127     xss = OFFSET_TO_XPOS(sel->sel_start);
2128     xse = OFFSET_TO_XPOS(sel->sel_end);
2129 
2130     if(abs(x-xss) < 5 || abs(x-xse) < 5)
2131       return TRUE;
2132   }
2133 
2134   return FALSE;
2135 }
2136 
2137 static gint
sample_display_scroll_event(GtkWidget * widget,GdkEventScroll * event)2138 sample_display_scroll_event(GtkWidget *widget,
2139 				 GdkEventScroll *event)
2140 {
2141   SampleDisplay *s;
2142 
2143   s = SAMPLE_DISPLAY(widget);
2144 
2145   if (event->direction == GDK_SCROLL_UP) {    /* mouse wheel scroll up */
2146   	view_zoom_in (s->view, 2.0);
2147 	return TRUE;
2148   }  else if (event->direction == GDK_SCROLL_DOWN) {   /* mouse wheel scroll down */
2149   	view_zoom_out (s->view, 2.0);
2150 	return TRUE;
2151   }
2152   return FALSE; /* redundant? */
2153 }
2154 
2155 static gint
sample_display_button_press(GtkWidget * widget,GdkEventButton * event)2156 sample_display_button_press (GtkWidget      *widget,
2157 			     GdkEventButton *event)
2158 {
2159   SampleDisplay *s;
2160   GdkModifierType state;
2161   sw_sample * sample;
2162   int x, y;
2163   int o;
2164 
2165   g_return_val_if_fail (widget != NULL, FALSE);
2166   g_return_val_if_fail (IS_SAMPLE_DISPLAY (widget), FALSE);
2167   g_return_val_if_fail (event != NULL, FALSE);
2168 
2169   s = SAMPLE_DISPLAY(widget);
2170 
2171   if(!IS_INITIALIZED(s))
2172     return TRUE;
2173 
2174   gtk_widget_grab_focus (widget);
2175 
2176   sample = s->view->sample;
2177 
2178   if (s->meta_down && s->view->current_tool == TOOL_SCRUB &&
2179       s->selecting == SELECTING_PLAYMARKER) {
2180     gdk_window_get_pointer (event->window, &x, &y, &state);
2181     sample_display_handle_playmarker_motion (s, x, y);
2182   } else
2183   if(s->selecting && event->button != last_button) {
2184     /* Cancel the current operation if a different button is pressed. */
2185     sample_display_clear_sel (s);
2186   } else
2187   if (last_tmp_view && last_tmp_view != s->view && event->button != last_button) {
2188     view_clear_last_tmp_view ();
2189   } else {
2190     last_button = event->button;
2191     gdk_window_get_pointer (event->window, &x, &y, &state);
2192 
2193     if(last_button == 1) {
2194 
2195       if (XPOS_TO_OFFSET(x) < 0 ||
2196 	  XPOS_TO_OFFSET(x) > sample->sounddata->nr_frames)
2197 	return TRUE;
2198 
2199       switch (s->view->current_tool) {
2200       case TOOL_SCRUB:
2201 	s->selecting = SELECTING_PLAYMARKER;
2202 	SET_CURSOR(widget, NEEDLE);
2203 	sample_set_scrubbing (s->view->sample, TRUE);
2204 	if (sample->play_head->going) {
2205 	  head_set_restricted (sample->play_head, FALSE);
2206 	  sample_refresh_playmode (sample);
2207 	} else {
2208 	  play_view_all (s->view);
2209 	}
2210 	sample_display_handle_playmarker_motion (s, x, y);
2211 	return TRUE;
2212 	break;
2213       case TOOL_SELECT:
2214 	/* If the cursor is near a sel, move that */
2215 	if (sample_display_on_sel (s, x, y)) {
2216 	  sample_display_handle_sel_button_press (s, x, y, state);
2217 #if 0
2218 	} else if (sample_display_on_playmarker (s, x, y)) {
2219 	  /* If the cursor is near the play marker, move that */
2220 	  s->selecting = SELECTING_PLAYMARKER;
2221 	  SET_CURSOR(widget, NEEDLE);
2222 #ifndef SEL_SCRUBS
2223 	  sample_set_scrubbing (sample, TRUE);
2224 	  sample_display_handle_playmarker_motion (s, x, y);
2225 #endif
2226 #endif
2227 	} else {
2228 	  sample_display_handle_sel_button_press (s, x, y, state);
2229 	}
2230 #ifdef SEL_SCRUBS
2231 	/* scrub along the changing selection edge, unless we're already
2232 	 * playing. NB. the play_head->scrubbing state is used by the
2233 	 * motion and release callbacks here to determine whether or not
2234 	 * to scrub the moving edge, and whether or not to stop playback
2235 	 * upon release. */
2236 	if (sample->play_head->going) {
2237 	  sample_set_scrubbing (sample, FALSE);
2238 	  sample_refresh_playmode (sample);
2239 	} else {
2240 	  /*sample_set_monitor (sample, TRUE);*/
2241 	  sample_set_scrubbing (sample, TRUE);
2242 	  play_view_all (s->view);
2243 	  sample_display_handle_playmarker_motion (s, x, y);
2244 	}
2245 #endif
2246 	break;
2247       case TOOL_HAND:
2248 	    s->selecting = SELECTING_HAND;
2249 	    s->view->hand_offset = x;
2250 	    s->hand_scroll_delta = 0;
2251 	    if (s->hand_scroll_tag){
2252 		   g_source_remove (s->hand_scroll_tag);
2253 		   s->hand_scroll_tag = 0;
2254 	    }
2255 	    SET_CURSOR(widget, HAND_CLOSE);
2256 	    sample_display_handle_hand_motion (s, x, y);
2257 	break;
2258       case TOOL_ZOOM:
2259 	    o = XPOS_TO_OFFSET(x);
2260 	    view_center_on (s->view, o);
2261 	    if (state & GDK_SHIFT_MASK) {
2262 	      view_zoom_out (s->view, 2.0);
2263 	    } else {
2264 	      view_zoom_in (s->view, 2.0);
2265 	    }
2266 	break;
2267       case TOOL_PENCIL:
2268 	s->selecting = SELECTING_PENCIL;
2269 	sample_display_handle_pencil_motion (s, x, y);
2270 	break;
2271       case TOOL_NOISE:
2272 	s->selecting = SELECTING_NOISE;
2273 	sample_display_handle_noise_motion (s, x, y);
2274 	break;
2275       default:
2276 	break;
2277       }
2278 
2279     } else if(last_button == 2) {
2280       s->selecting = SELECTING_PAN_WINDOW;
2281       gdk_window_get_pointer (event->window, &s->selecting_x0, NULL, NULL);
2282       s->selecting_wins0 = s->view->start;
2283       SET_CURSOR(widget, MOVE);
2284       sample_set_scrubbing (s->view->sample, TRUE);
2285     } else if(last_button == 3) {
2286       if(s->view && s->view->menu) {
2287 	view_popup_context_menu (s->view, 3, event->time);
2288       }
2289     }
2290   }
2291 
2292   return TRUE;
2293 }
2294 
2295 void
sample_display_sink_tmp_sel(SampleDisplay * s)2296 sample_display_sink_tmp_sel (SampleDisplay * s)
2297 {
2298   sw_sample * sample = s->view->sample;
2299   sw_sel * t;
2300 
2301   s->selecting = SELECTING_NOTHING;
2302 
2303   if (s->scroll_right_tag != 0) {
2304     g_source_remove (s->scroll_right_tag);
2305     s->scroll_right_tag = 0;
2306   }
2307   if (s->scroll_left_tag != 0) {
2308     g_source_remove (s->scroll_left_tag);
2309     s->scroll_left_tag = 0;
2310   }
2311 
2312   t = sample->tmp_sel;
2313 
2314   if (t->sel_end == (t->sel_start + 1)) {
2315     if (!sample->play_head->going) {
2316       sample_set_playmarker (sample, t->sel_start, TRUE);
2317     }
2318     sample_clear_tmp_sel (sample);
2319   } else {
2320 
2321     if (s->selecting == SELECTING_SELECTION_START) {
2322       sample_set_playmarker (sample, t->sel_start, TRUE);
2323     } else if (s->selecting == SELECTING_SELECTION_END) {
2324       sample_set_playmarker (sample, t->sel_end, TRUE);
2325     }
2326 
2327     if(s->selection_mode == SELECTION_MODE_REPLACE) {
2328       sample_selection_replace_with_tmp_sel (sample);
2329     } else if (s->selection_mode == SELECTION_MODE_SUBTRACT) {
2330       sample_selection_subtract_tmp_sel (sample);
2331     } else {
2332       sample_selection_insert_tmp_sel (sample);
2333     }
2334     s->selection_mode = SELECTION_MODE_NONE;
2335 
2336     g_signal_emit_by_name(GTK_OBJECT(s),
2337 		    "selection-changed");
2338   }
2339 }
2340 
2341 static gint
sample_display_button_release(GtkWidget * widget,GdkEventButton * event)2342 sample_display_button_release (GtkWidget      *widget,
2343 			       GdkEventButton *event)
2344 {
2345   SampleDisplay *s;
2346 #ifdef SEL_SCRUBS
2347   GdkModifierType state;
2348   int x, y;
2349 #endif
2350 
2351   g_return_val_if_fail (widget != NULL, FALSE);
2352   g_return_val_if_fail (IS_SAMPLE_DISPLAY (widget), FALSE);
2353   g_return_val_if_fail (event != NULL, FALSE);
2354 
2355   s = SAMPLE_DISPLAY(widget);
2356 
2357   switch (s->view->current_tool) {
2358   case TOOL_SELECT:
2359 
2360     /* If the user has released the button they were selecting with,
2361      * sink this sample's temporary selection.
2362      */
2363     if (s->selecting && event->button == last_button) {
2364       switch (s->selecting) {
2365       case SELECTING_SELECTION_START:
2366       case SELECTING_SELECTION_END:
2367 	sample_display_sink_tmp_sel (s);
2368 	break;
2369       default:
2370 	break;
2371       }
2372     }
2373 
2374     /* If the user has released the button in a sweep window different
2375      * to that used for selection, then sink the appropriate temporary
2376      * selection.
2377      */
2378     if (last_tmp_view != s->view) {
2379       view_sink_last_tmp_view();
2380     }
2381 
2382 #ifdef SEL_SCRUBS
2383     if (s->view->sample->play_head->scrubbing) {
2384       gdk_window_get_pointer (event->window, &x, &y, &state);
2385       pause_playback (s->view->sample);
2386       sample_display_handle_playmarker_motion (s, x, y);
2387     }
2388 #endif
2389 
2390     break;
2391   case TOOL_SCRUB:
2392     if (s->meta_down) return TRUE;
2393     break;
2394   case TOOL_HAND:
2395     s->view->hand_offset = -1;
2396 
2397     s->hand_scroll_tag = g_timeout_add (HAND_SCROLL_INTERVAL,
2398 		    (GSourceFunc)sample_display_hand_scroll,
2399 		    s);
2400 
2401     break;
2402   case TOOL_MOVE:
2403     break;
2404   case TOOL_ZOOM:
2405     break;
2406   default:
2407     break;
2408   }
2409 
2410   if (s->meta_down && s->selecting == SELECTING_PLAYMARKER)
2411     return TRUE;
2412 
2413   s->selecting = SELECTING_NOTHING;
2414 
2415   sample_set_scrubbing (s->view->sample, FALSE);
2416 
2417   sample_display_set_default_cursor (s);
2418 
2419   return FALSE;
2420 }
2421 
2422 static gint
sample_display_motion_notify(GtkWidget * widget,GdkEventMotion * event)2423 sample_display_motion_notify (GtkWidget *widget,
2424 			      GdkEventMotion *event)
2425 {
2426   SampleDisplay *s;
2427   gint x, y;
2428   GdkModifierType state;
2429   sw_framecount_t o;
2430 
2431   s = SAMPLE_DISPLAY(widget);
2432 
2433   if(!IS_INITIALIZED(s))
2434     return FALSE;
2435 
2436   if (event->is_hint) {
2437     gdk_window_get_pointer (event->window, &x, &y, &state);
2438   } else {
2439     x = event->x;
2440     y = event->y;
2441     state = event->state;
2442   }
2443 
2444   o = XPOS_TO_OFFSET(x);
2445   s->mouse_x = x;
2446   s->mouse_offset = o;
2447   g_signal_emit_by_name(GTK_OBJECT(s),
2448 		  "mouse-offset-changed");
2449 
2450   if (s->selecting) {
2451     if (s->meta_down && s->selecting == SELECTING_PLAYMARKER) {
2452       sample_display_handle_playmarker_motion (s, x, y);
2453     } else if((state & GDK_BUTTON1_MASK) && last_button == 1) {
2454       switch (s->selecting) {
2455       case SELECTING_PLAYMARKER:
2456 	sample_display_handle_playmarker_motion (s, x, y);
2457 	break;
2458       case SELECTING_HAND:
2459 	    sample_display_handle_hand_motion (s, x, y);
2460 	    break;
2461       case SELECTING_PENCIL:
2462 	sample_display_handle_pencil_motion (s, x, y);
2463 	break;
2464       case SELECTING_NOISE:
2465 	sample_display_handle_noise_motion (s, x, y);
2466 	break;
2467       default:
2468 	sample_display_handle_sel_motion(s, x, y, 0);
2469 #ifdef SEL_SCRUBS
2470 	if (s->view->sample->play_head->scrubbing) {
2471 	  sample_display_handle_playmarker_motion (s, x, y);
2472 	}
2473 #endif
2474 	break;
2475       }
2476     } else if((state & GDK_BUTTON2_MASK) && last_button == 2) {
2477       sample_display_handle_move_motion (s, x, y);
2478     } else {
2479       /*    sample_display_clear_sel (s);*/
2480       if (s->selecting == SELECTING_SELECTION_START ||
2481 	  s->selecting == SELECTING_SELECTION_END) {
2482 	/* XXX: Need to sink_tmp_sel here instead for consistency ???
2483 	 *  It seems to be clearing fast tmp_sels now, but at least not
2484 	 * leaving them lying around.*/
2485 	sample_display_sink_tmp_sel (s);
2486 
2487 	sample_display_set_default_cursor (s);
2488       }
2489     }
2490 
2491   } else {
2492     if (s->view->current_tool == TOOL_SELECT &&
2493 	sample_display_on_sel (s, x, y)) {
2494       SET_CURSOR(widget, HORIZ);
2495     } else if (s->view->current_tool == TOOL_SELECT &&
2496 	       sample_display_on_playmarker (s, x, y)) {
2497       SET_CURSOR(widget, NEEDLE);
2498     } else {
2499 
2500       if (o > 0 && o < s->view->sample->sounddata->nr_frames)
2501 	sample_display_set_default_cursor (SAMPLE_DISPLAY(widget));
2502       else
2503 	gdk_window_set_cursor (widget->window, NULL);
2504     }
2505 
2506 #if 0
2507     /* Consistency check: without this, some button release events
2508      * are lost if they occur during motion. Here, we ensure that
2509      * if this sample_display s is not selecting yet has a selection
2510      */
2511     if(s->selection_mode && s->view->sample->tmp_sel) {
2512       sample_display_sink_tmp_sel (s);
2513     }
2514 #endif
2515   }
2516 
2517   return FALSE;
2518 }
2519 
2520 static gint
sample_display_enter_notify(GtkWidget * widget,GdkEventCrossing * event)2521 sample_display_enter_notify (GtkWidget *widget,
2522 			     GdkEventCrossing *event)
2523 {
2524   gtk_widget_grab_focus (widget);
2525   return TRUE;
2526 }
2527 
2528 static gint
sample_display_leave_notify(GtkWidget * widget,GdkEventCrossing * event)2529 sample_display_leave_notify (GtkWidget *widget,
2530 			     GdkEventCrossing *event)
2531 {
2532   SampleDisplay *s;
2533 
2534   s = SAMPLE_DISPLAY(widget);
2535   s->mouse_offset = -1;
2536   g_signal_emit_by_name(GTK_OBJECT(s),
2537 		 "mouse-offset-changed");
2538 
2539   return TRUE;
2540 }
2541 
2542 static gint
sample_display_focus_in(GtkWidget * widget,GdkEventFocus * event)2543 sample_display_focus_in (GtkWidget * widget, GdkEventFocus * event)
2544 {
2545   SampleDisplay * s;
2546 
2547   g_return_val_if_fail (widget != NULL, FALSE);
2548   g_return_val_if_fail (IS_SAMPLE_DISPLAY(widget), FALSE);
2549 
2550   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2551  /*
2552   * FIXME: nonexistant in GTK+-2.0
2553   * docs say draw in the expose function. draw what though?
2554   *
2555   *	gtk_widget_draw_focus (widget);
2556   */
2557 
2558   s = SAMPLE_DISPLAY(widget);
2559 
2560   if (s->marching) {
2561     sd_start_marching_ants_timeout (s);
2562   }
2563 
2564   sample_display_start_cursor_pulse (s);
2565 
2566   undo_dialog_set_sample (s->view->sample);
2567 
2568   return FALSE;
2569 }
2570 
2571 static gint
sample_display_focus_out(GtkWidget * widget,GdkEventFocus * event)2572 sample_display_focus_out (GtkWidget * widget, GdkEventFocus * event)
2573 {
2574   SampleDisplay * s;
2575 
2576   g_return_val_if_fail (widget != NULL, FALSE);
2577   g_return_val_if_fail (IS_SAMPLE_DISPLAY(widget), FALSE);
2578 
2579   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2580  /*
2581   * FIXME: nonexistant in GTK+-2.0
2582   * docs say draw in the expose function. draw what though?
2583   *
2584   *	gtk_widget_draw_focus (widget);
2585   */
2586 
2587   s = SAMPLE_DISPLAY(widget);
2588 
2589   sd_stop_marching_ants_timeout (s);
2590 
2591   sample_display_stop_cursor_pulse (s);
2592 
2593   return FALSE;
2594 }
2595 
2596 static gint
sample_display_key_press(GtkWidget * widget,GdkEventKey * event)2597 sample_display_key_press (GtkWidget * widget, GdkEventKey * event)
2598 {
2599   SampleDisplay * s = SAMPLE_DISPLAY(widget);
2600   sw_view * view = s->view;
2601   sw_sample * sample;
2602   sw_framecount_t vlen, move_delta = 0, sel_t;
2603   GList * gl;
2604   sw_sel * sel;
2605   int x, y, xss, xse;
2606 
2607   sample = view->sample;
2608   vlen = view->end - view->start;
2609 
2610   /*g_print ("key 0x%X pressed\n", event->keyval);*/
2611 
2612   switch (event->keyval) {
2613   case GDK_Meta_L:
2614   case GDK_Super_L:
2615   case GDK_Multi_key:
2616     if (sample->edit_mode == SWEEP_EDIT_MODE_ALLOC) break;
2617 
2618     s->meta_down = TRUE;
2619 
2620     if (s->selecting == SELECTING_NOTHING) {
2621       s->selecting = SELECTING_PLAYMARKER;
2622       SET_CURSOR(widget, NEEDLE);
2623       sample_set_scrubbing (sample, TRUE);
2624     }
2625 
2626     if (s->selecting == SELECTING_PLAYMARKER) {
2627       gdk_window_get_pointer (widget->window, &x, &y, NULL);
2628       sample_display_handle_playmarker_motion (s, x, y);
2629       if (!sample->play_head->going) {
2630 	play_view_all (s->view);
2631       }
2632     }
2633 
2634     return TRUE;
2635     break;
2636   case GDK_Menu:
2637     if(view->menu) {
2638       gtk_menu_popup(GTK_MENU(view->menu),
2639 		     NULL, NULL, NULL,
2640 		     NULL, 3, event->time);
2641     }
2642     return TRUE;
2643     break;
2644   case GDK_BackSpace:
2645     if (sample->edit_mode == SWEEP_EDIT_MODE_READY)
2646       do_clear (sample);
2647     return TRUE;
2648     break;
2649   case GDK_Delete:
2650     if (sample->edit_mode == SWEEP_EDIT_MODE_READY)
2651       do_delete (sample);
2652     return TRUE;
2653     break;
2654   case GDK_less:
2655     if (sample->edit_mode == SWEEP_EDIT_MODE_READY)
2656       select_shift_left_cb (widget, s);
2657     return TRUE;
2658   case GDK_greater:
2659     if (sample->edit_mode == SWEEP_EDIT_MODE_READY)
2660       select_shift_right_cb (widget, s);
2661     return TRUE;
2662   case GDK_Up:
2663   case GDK_KP_Up:
2664     if (event->state & GDK_CONTROL_MASK) {
2665       zoom_1to1_cb (GTK_WIDGET(s), s);
2666     } else if (event->state & GDK_SHIFT_MASK) {
2667       view_vzoom_in (view, 1.2);
2668     } else {
2669       view_zoom_in (view, 2.0);
2670     }
2671     return TRUE;
2672     break;
2673   case GDK_Down:
2674   case GDK_KP_Down:
2675     if (event->state & GDK_CONTROL_MASK) {
2676       zoom_norm_cb (GTK_WIDGET(s), s);
2677     } else if (event->state & GDK_SHIFT_MASK) {
2678       view_vzoom_out (view, 1.2);
2679     } else {
2680       view_zoom_out (view, 2.0);
2681     }
2682     return TRUE;
2683     break;
2684   case GDK_Left:
2685   case GDK_KP_Left:
2686     move_delta = MIN(-1,  -vlen/s->width);
2687     if (event->state & GDK_CONTROL_MASK) {
2688       if (!(event->state & GDK_SHIFT_MASK)) {
2689 	sample_set_offset_next_bound_left (sample);
2690 	return TRUE;
2691       }
2692       move_delta *= 10;
2693     }
2694     break;
2695   case GDK_Right:
2696   case GDK_KP_Right:
2697     move_delta = MAX(1,  vlen/s->width);
2698     if (event->state & GDK_CONTROL_MASK) {
2699       if (!(event->state & GDK_SHIFT_MASK)) {
2700 	sample_set_offset_next_bound_right (sample);
2701 	return TRUE;
2702       }
2703       move_delta *= 10;
2704     }
2705     break;
2706   default: /* Random other key pressed */
2707     return FALSE;
2708     break;
2709   }
2710 
2711   /* Handle movement only from here on */
2712 
2713   if ((event->state & GDK_SHIFT_MASK) &&
2714       (sample->edit_mode == SWEEP_EDIT_MODE_READY)) {
2715     sel = sample->tmp_sel;
2716 
2717     switch (s->selecting) {
2718     case SELECTING_SELECTION_START:
2719       sel->sel_start += move_delta;
2720       if (sel->sel_start > sel->sel_end) {
2721 	sel_t = sel->sel_start;
2722 	sel->sel_start = sel->sel_end;
2723 	sel->sel_end = sel_t;
2724 	s->selecting = SELECTING_SELECTION_END;
2725       }
2726       break;
2727     case SELECTING_SELECTION_END:
2728       sample->tmp_sel->sel_end += move_delta;
2729       if (sel->sel_start > sel->sel_end) {
2730 	sel_t = sel->sel_start;
2731 	sel->sel_start = sel->sel_end;
2732 	sel->sel_end = sel_t;
2733 	s->selecting = SELECTING_SELECTION_START;
2734       }
2735       break;
2736     default:
2737       last_button = 0;
2738 
2739       x = OFFSET_TO_XPOS(sample->user_offset);
2740 
2741       if ((sel = sample->tmp_sel) != NULL) {
2742 
2743 	xss = OFFSET_TO_XPOS(sel->sel_start);
2744 	xse = OFFSET_TO_XPOS(sel->sel_end);
2745 
2746 	if(abs(x-xss) < 5) {
2747 	  s->selecting = SELECTING_SELECTION_START;
2748 	  sel->sel_start += move_delta;
2749 	  if (sel->sel_start > sel->sel_end) {
2750 	    sel_t = sel->sel_start;
2751 	    sel->sel_start = sel->sel_end;
2752 	    sel->sel_end = sel_t;
2753 	    s->selecting = SELECTING_SELECTION_END;
2754 	  }
2755 	  break;
2756 	} else if(abs(x-xse) < 5) {
2757 	  s->selecting = SELECTING_SELECTION_END;
2758 	  sel->sel_end += move_delta;
2759 	  if (sel->sel_start > sel->sel_end) {
2760 	    sel_t = sel->sel_start;
2761 	    sel->sel_start = sel->sel_end;
2762 	    sel->sel_end = sel_t;
2763 	    s->selecting = SELECTING_SELECTION_START;
2764 	  }
2765 	  break;
2766 	}
2767       }
2768 
2769       if (s->selecting != SELECTING_SELECTION_START &&
2770 	  s->selecting != SELECTING_SELECTION_END) {
2771 
2772 	for (gl = sample->sounddata->sels; gl; gl = gl->next) {
2773 
2774 
2775 	  /* If the cursor is near the current start or end of
2776 	   * the selection, move that.
2777 	   */
2778 
2779 	  sel = (sw_sel *)gl->data;
2780 
2781 	  xss = OFFSET_TO_XPOS(sel->sel_start);
2782 	  xse = OFFSET_TO_XPOS(sel->sel_end);
2783 
2784 	  if(abs(x-xss) < 5) {
2785 	    sample_set_tmp_sel (sample, s->view, sel);
2786 	    s->selecting = SELECTING_SELECTION_START;
2787 	    s->selection_mode = SELECTION_MODE_INTERSECT;
2788 	    sample_display_set_intersect_cursor (s);
2789 	    break;
2790 	  } else if(abs(x-xse) < 5) {
2791 	    sample_set_tmp_sel (sample, s->view, sel);
2792 	    s->selecting = SELECTING_SELECTION_END;
2793 	    s->selection_mode = SELECTION_MODE_INTERSECT;
2794 	    sample_display_set_intersect_cursor (s);
2795 	    break;
2796 	  }
2797 	}
2798       }
2799 
2800       if (s->selecting != SELECTING_SELECTION_START &&
2801 	  s->selecting != SELECTING_SELECTION_END) {
2802 
2803 	sample_set_tmp_sel_1 (sample, view, sample->user_offset,
2804 			      sample->user_offset + move_delta);
2805 	s->selecting = SELECTING_SELECTION_START;
2806 	s->selection_mode = SELECTION_MODE_REPLACE;
2807 	SET_CURSOR (GTK_WIDGET(s), HORIZ);
2808       }
2809       break;
2810     }
2811     g_signal_emit_by_name(GTK_OBJECT(s),
2812 		    "selection-changed");
2813   } else if (s->selecting == SELECTING_SELECTION_START ||
2814 	     s->selecting == SELECTING_SELECTION_END) {
2815     sample_display_sink_tmp_sel (s);
2816     s->selecting = SELECTING_NOTHING;
2817     sample_display_set_default_cursor (s);
2818   }
2819 
2820   sample_set_playmarker (sample, sample->user_offset + move_delta, TRUE);
2821 
2822   return TRUE;
2823 }
2824 
2825 static gint
sample_display_key_release(GtkWidget * widget,GdkEventKey * event)2826 sample_display_key_release (GtkWidget * widget, GdkEventKey * event)
2827 {
2828   SampleDisplay * s = SAMPLE_DISPLAY(widget);
2829   GdkModifierType state;
2830 
2831   switch (event->keyval) {
2832   case GDK_Meta_L:
2833   case GDK_Super_L:
2834   case GDK_Multi_key:
2835     s->meta_down = FALSE;
2836 
2837     gdk_window_get_pointer (widget->window, NULL, NULL, &state);
2838 
2839     /* Don't cancel scrubbing if the mouse is down for it */
2840     if ((state & GDK_BUTTON1_MASK) && s->view->current_tool == TOOL_SCRUB)
2841       return TRUE;
2842 
2843     if (s->selecting == SELECTING_PLAYMARKER) {
2844       s->selecting = SELECTING_NOTHING;
2845       sample_set_scrubbing (s->view->sample, FALSE);
2846       sample_display_set_default_cursor (s);
2847     }
2848 
2849     return TRUE;
2850     break;
2851   default:
2852     break;
2853   }
2854 
2855   return FALSE;
2856 }
2857 
2858 static gint
sample_display_destroy(GtkWidget * widget,GdkEventAny * event)2859 sample_display_destroy (GtkWidget * widget, GdkEventAny * event)
2860 {
2861   gtk_widget_queue_draw(widget);
2862   return 0;
2863 }
2864 
2865 static void
sample_display_class_init(SampleDisplayClass * class)2866 sample_display_class_init (SampleDisplayClass *class)
2867 {
2868   GtkObjectClass *object_class;
2869   GtkWidgetClass *widget_class;
2870   int n;
2871   const int *p;
2872   GdkColor *c;
2873 
2874   object_class = (GtkObjectClass*) class;
2875   widget_class = (GtkWidgetClass*) class;
2876 
2877   widget_class->realize = sample_display_realize;
2878   widget_class->size_allocate = sample_display_size_allocate;
2879   widget_class->expose_event = sample_display_expose;
2880   widget_class->size_request = sample_display_size_request;
2881   widget_class->button_press_event = sample_display_button_press;
2882   widget_class->button_release_event = sample_display_button_release;
2883   widget_class->scroll_event = sample_display_scroll_event;
2884   widget_class->motion_notify_event = sample_display_motion_notify;
2885   widget_class->enter_notify_event = sample_display_enter_notify;
2886   widget_class->leave_notify_event = sample_display_leave_notify;
2887   widget_class->key_press_event = sample_display_key_press;
2888   widget_class->key_release_event = sample_display_key_release;
2889   widget_class->focus_in_event = sample_display_focus_in;
2890   widget_class->focus_out_event = sample_display_focus_out;
2891 
2892   widget_class->destroy_event = sample_display_destroy;
2893 
2894   sample_display_signals[SIG_SELECTION_CHANGED] =
2895     g_signal_new ("selection-changed",
2896 					 			  G_TYPE_FROM_CLASS (object_class),
2897 	                              G_SIGNAL_RUN_FIRST,
2898 	                              G_STRUCT_OFFSET (SampleDisplayClass, selection_changed),
2899                                   NULL,
2900                                   NULL,
2901 					 			  g_cclosure_marshal_VOID__VOID,
2902                                   G_TYPE_NONE, 0);
2903 
2904 
2905   sample_display_signals[SIG_WINDOW_CHANGED] =
2906     g_signal_new ("window-changed",
2907 					 			  G_TYPE_FROM_CLASS (object_class),
2908 	                              G_SIGNAL_RUN_FIRST,
2909 	                              G_STRUCT_OFFSET (SampleDisplayClass, window_changed),
2910                                   NULL,
2911                                   NULL,
2912 					 			  g_cclosure_marshal_VOID__VOID,
2913                                   G_TYPE_NONE, 0);
2914 
2915 
2916   sample_display_signals[SIG_MOUSE_OFFSET_CHANGED] =
2917     g_signal_new ("mouse-offset-changed",
2918 					 			  G_TYPE_FROM_CLASS (object_class),
2919 	                              G_SIGNAL_RUN_FIRST,
2920 	                              G_STRUCT_OFFSET (SampleDisplayClass, mouse_offset_changed),
2921                                   NULL,
2922                                   NULL,
2923 					 			  g_cclosure_marshal_VOID__VOID,
2924                                   G_TYPE_NONE, 0);
2925 
2926   class->selection_changed = NULL;
2927   class->window_changed = NULL;
2928   class->mouse_offset_changed = NULL;
2929 
2930   for(n = 0, p = default_colors, c = class->colors;
2931       n < SAMPLE_DISPLAYCOL_LAST; n++, c++) {
2932     c->red = *p++ * 65535 / 255;
2933     c->green = *p++ * 65535 / 255;
2934     c->blue = *p++ * 65535 / 255;
2935     c->pixel = (glong)((c->red & 0xff00)*256 +
2936 			(c->green & 0xff00) +
2937 			(c->blue & 0xff00)/256);
2938     gdk_colormap_alloc_color(gdk_colormap_get_system(), c, TRUE, TRUE);
2939   }
2940 
2941   for(n = 0, p = bg_colors, c = class->bg_colors;
2942       n < VIEW_COLOR_MAX; n++, c++) {
2943     c->red = *p++ * 65535 / 255;
2944     c->green = *p++ * 65535 / 255;
2945     c->blue = *p++ * 65535 / 255;
2946     c->pixel = (glong)((c->red & 0xff00)*256 +
2947 			(c->green & 0xff00) +
2948 			(c->blue & 0xff00)/256);
2949     gdk_colormap_alloc_color(gdk_colormap_get_system(), c, TRUE, TRUE);
2950   }
2951 
2952   for(n = 0, p = fg_colors, c = class->fg_colors;
2953       n < VIEW_COLOR_MAX; n++, c++) {
2954     c->red = *p++ * 65535 / 255;
2955     c->green = *p++ * 65535 / 255;
2956     c->blue = *p++ * 65535 / 255;
2957     c->pixel = (glong)((c->red & 0xff00)*256 +
2958 			(c->green & 0xff00) +
2959 			(c->blue & 0xff00)/256);
2960     gdk_colormap_alloc_color(gdk_colormap_get_system(), c, TRUE, TRUE);
2961   }
2962 }
2963 
2964 static void
sample_display_init(SampleDisplay * s)2965 sample_display_init (SampleDisplay *s)
2966 {
2967   GTK_WIDGET_SET_FLAGS (GTK_WIDGET(s), GTK_CAN_FOCUS);
2968 
2969   s->backing_pixmap = NULL;
2970   s->view = NULL;
2971   s->selecting = SELECTING_NOTHING;
2972   s->selection_mode = SELECTION_MODE_NONE;
2973   s->marching_tag = 0;
2974   s->marching = FALSE;
2975   s->pulsing_tag = 0;
2976   s->pulse = FALSE;
2977   s->hand_scroll_tag = 0;
2978   s->mouse_x = 0;
2979   s->mouse_offset = 0;
2980   s->scroll_left_tag = 0;
2981   s->scroll_right_tag = 0;
2982 }
2983 
2984 
2985 
2986 
2987 GType
sample_display_get_type(void)2988 sample_display_get_type (void)
2989 {
2990   static GType sample_display_type = 0;
2991 
2992   if (!sample_display_type)
2993 	{
2994       static const GTypeInfo sample_display_info =
2995     {
2996       sizeof(SampleDisplayClass),
2997 	   NULL, /* base_init */
2998 	   NULL, /* base_finalize */
2999 	   (GClassInitFunc) sample_display_class_init,
3000 	   NULL, /* class_finalize */
3001 	   NULL, /* class_data */
3002        sizeof (SampleDisplay),
3003 	   0,    /* n_preallocs */
3004 	   (GInstanceInitFunc) sample_display_init,
3005 
3006     };
3007 
3008 		sample_display_type = g_type_register_static (GTK_TYPE_WIDGET,
3009 												  "SampleDisplay", &sample_display_info, 0);
3010 
3011   }
3012 
3013   return sample_display_type;
3014 }
3015 
3016 GtkWidget*
sample_display_new(void)3017 sample_display_new (void)
3018 {
3019   return GTK_WIDGET (g_object_new (sample_display_get_type (), NULL));
3020 }
3021