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