missing commit in generator.h
[galan.git] / src / sample-display.c
blob7337b50e2512290e300ad6feddef7c15924fca7d
2 /*
3 * The Real SoundTracker - GTK+ sample display widget
5 * Copyright (C) 1998-2000 Michael Krause
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <stdlib.h>
24 #include "sample-display.h"
26 #include <string.h>
28 #include <gtk/gtksignal.h>
29 #include <gtk/gtkmain.h>
31 #define XPOS_TO_OFFSET(x) (s->win_start + ((guint64)(x)) * s->win_length / s->width)
32 #define OFFSET_RANGE(l, x) (x < 0 ? 0 : (x >= l ? l - 1 : x))
34 static const int default_colors[] = {
35 10, 20, 30,
36 230, 230, 230,
37 230, 200, 0,
38 230, 0, 0,
39 60, 60, 140,
42 enum {
43 SELECTING_NOTHING = 0,
44 SELECTING_SELECTION_START,
45 SELECTING_SELECTION_END,
46 SELECTING_LOOP_START,
47 SELECTING_LOOP_END,
48 SELECTING_PAN_WINDOW,
51 enum {
52 SIG_SELECTION_CHANGED,
53 SIG_LOOP_CHANGED,
54 SIG_WINDOW_CHANGED,
55 LAST_SIGNAL
58 #define IS_INITIALIZED(s) (s->datalen != 0)
60 static guint sample_display_signals[LAST_SIGNAL] = { 0 };
62 static int sample_display_startoffset_to_xpos (SampleDisplay *s,
63 int offset);
64 static gint sample_display_idle_draw_function (SampleDisplay *s);
66 static void
67 sample_display_idle_draw (SampleDisplay *s)
69 if(!s->idle_handler) {
70 s->idle_handler = gtk_idle_add((GtkFunction)sample_display_idle_draw_function,
71 (gpointer)s);
72 g_assert(s->idle_handler != 0);
76 void
77 sample_display_enable_zero_line (SampleDisplay *s,
78 gboolean enable)
80 s->display_zero_line = enable;
82 if(s->datalen) {
83 gtk_widget_queue_draw(GTK_WIDGET(s));
87 static void
88 sample_display_set_data (SampleDisplay *s,
89 void *data,
90 int type,
91 int len,
92 gboolean copy)
94 g_return_if_fail(s != NULL);
95 g_return_if_fail(IS_SAMPLE_DISPLAY(s));
97 gboolean len_changed = ( s->datalen != len );
98 if(!data || !len) {
99 s->datalen = 0;
100 } else {
101 if(copy) {
102 if(s->datacopy) {
103 if(s->datacopylen < len * type / 8) {
104 g_free(s->data);
105 s->data = g_new(gint8, len * type / 8);
106 s->datacopylen = len * type / 8;
108 } else {
109 s->data = g_new(gint8, len * type / 8);
110 s->datacopylen = len * type / 8;
112 g_assert(s->data != NULL);
113 memcpy(s->data, data, len * type / 8);
114 s->datalen = len;
115 } else {
116 if(s->datacopy) {
117 g_free(s->data);
119 s->data = data;
120 s->datalen = len;
122 s->datacopy = copy;
123 s->datatype = type;
126 s->old_mixerpos = -1;
127 s->mixerpos = -1;
129 if( len_changed ) {
130 s->win_start = 0;
131 s->win_length = len;
132 gtk_signal_emit(GTK_OBJECT(s), sample_display_signals[SIG_WINDOW_CHANGED], s->win_start, s->win_start + s->win_length);
134 s->sel_start = -1;
135 s->old_ss = s->old_se = -1;
136 s->selecting = 0;
138 s->loop_start = -1;
141 gtk_widget_queue_draw(GTK_WIDGET(s));
144 void
145 sample_display_set_data_16 (SampleDisplay *s,
146 gint16 *data,
147 int len,
148 gboolean copy)
150 sample_display_set_data(s, data, 16, len, copy);
153 void
154 sample_display_set_data_8 (SampleDisplay *s,
155 gint8 *data,
156 int len,
157 gboolean copy)
159 sample_display_set_data(s, data, 8, len, copy);
162 void
163 sample_display_set_loop (SampleDisplay *s,
164 int start,
165 int end)
167 g_return_if_fail(s != NULL);
168 g_return_if_fail(IS_SAMPLE_DISPLAY(s));
170 if(!s->edit || !IS_INITIALIZED(s))
171 return;
173 g_return_if_fail(start >= -1 && start < s->datalen);
174 g_return_if_fail(end > 0 && end <= s->datalen);
175 g_return_if_fail(end > start);
177 s->loop_start = start;
178 s->loop_end = end;
180 gtk_widget_queue_draw(GTK_WIDGET(s));
181 gtk_signal_emit(GTK_OBJECT(s), sample_display_signals[SIG_LOOP_CHANGED], start, end);
184 void
185 sample_display_set_selection (SampleDisplay *s,
186 int start,
187 int end)
189 g_return_if_fail(s != NULL);
190 g_return_if_fail(IS_SAMPLE_DISPLAY(s));
192 if(!s->edit || !IS_INITIALIZED(s))
193 return;
195 g_return_if_fail(start >= -1 && start < s->datalen);
196 g_return_if_fail(end >= 1 && end <= s->datalen);
197 g_return_if_fail(end > start);
199 s->sel_start = start;
200 s->sel_end = end;
202 sample_display_idle_draw(s);
203 gtk_signal_emit(GTK_OBJECT(s), sample_display_signals[SIG_SELECTION_CHANGED], start, end);
206 void
207 sample_display_set_mixer_position (SampleDisplay *s,
208 int offset)
210 g_return_if_fail(s != NULL);
211 g_return_if_fail(IS_SAMPLE_DISPLAY(s));
213 if(!s->edit || !IS_INITIALIZED(s))
214 return;
216 if(offset != s->mixerpos) {
217 s->mixerpos = offset;
218 sample_display_idle_draw(s);
222 void
223 sample_display_set_window (SampleDisplay *s,
224 int start,
225 int end)
227 g_return_if_fail(s != NULL);
228 g_return_if_fail(IS_SAMPLE_DISPLAY(s));
229 g_return_if_fail(start >= 0 && start < s->datalen);
230 g_return_if_fail(end > 0 && end <= s->datalen);
231 g_return_if_fail(end > start);
233 s->win_start = start;
234 s->win_length = end - start;
235 gtk_signal_emit(GTK_OBJECT(s), sample_display_signals[SIG_WINDOW_CHANGED], start, end);
237 gtk_widget_queue_draw(GTK_WIDGET(s));
240 static void
241 sample_display_init_display (SampleDisplay *s,
242 int w,
243 int h)
245 s->width = w;
246 s->height = h;
249 static void
250 sample_display_size_allocate (GtkWidget *widget,
251 GtkAllocation *allocation)
253 SampleDisplay *s;
255 g_return_if_fail (widget != NULL);
256 g_return_if_fail (IS_SAMPLE_DISPLAY (widget));
257 g_return_if_fail (allocation != NULL);
259 widget->allocation = *allocation;
260 if (GTK_WIDGET_REALIZED (widget)) {
261 s = SAMPLE_DISPLAY (widget);
263 gdk_window_move_resize (widget->window,
264 allocation->x, allocation->y,
265 allocation->width, allocation->height);
267 sample_display_init_display(s, allocation->width, allocation->height);
271 static void
272 sample_display_realize (GtkWidget *widget)
274 GdkWindowAttr attributes;
275 gint attributes_mask;
276 SampleDisplay *s;
278 g_return_if_fail (widget != NULL);
279 g_return_if_fail (IS_SAMPLE_DISPLAY (widget));
281 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
282 s = SAMPLE_DISPLAY(widget);
284 attributes.x = widget->allocation.x;
285 attributes.y = widget->allocation.y;
286 attributes.width = widget->allocation.width;
287 attributes.height = widget->allocation.height;
288 attributes.wclass = GDK_INPUT_OUTPUT;
289 attributes.window_type = GDK_WINDOW_CHILD;
290 attributes.event_mask = gtk_widget_get_events (widget)
291 | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
292 | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
294 attributes.visual = gtk_widget_get_visual (widget);
295 attributes.colormap = gtk_widget_get_colormap (widget);
297 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
298 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
300 widget->style = gtk_style_attach (widget->style, widget->window);
302 s->bg_gc = gdk_gc_new(widget->window);
303 s->fg_gc = gdk_gc_new(widget->window);
304 s->zeroline_gc = gdk_gc_new(widget->window);
305 gdk_gc_set_foreground(s->bg_gc, &SAMPLE_DISPLAY_CLASS(GTK_OBJECT_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_BG]);
306 gdk_gc_set_foreground(s->fg_gc, &SAMPLE_DISPLAY_CLASS(GTK_OBJECT_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_FG]);
307 gdk_gc_set_foreground(s->zeroline_gc, &SAMPLE_DISPLAY_CLASS(GTK_OBJECT_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_ZERO]);
308 if(s->edit) {
309 s->loop_gc = gdk_gc_new(widget->window);
310 s->mixerpos_gc = gdk_gc_new(widget->window);
311 gdk_gc_set_foreground(s->loop_gc, &SAMPLE_DISPLAY_CLASS(GTK_OBJECT_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_LOOP]);
312 gdk_gc_set_foreground(s->mixerpos_gc, &SAMPLE_DISPLAY_CLASS(GTK_OBJECT_GET_CLASS(widget))->colors[SAMPLE_DISPLAYCOL_MIXERPOS]);
315 sample_display_init_display(s, attributes.width, attributes.height);
317 gdk_window_set_user_data (widget->window, widget);
320 static void
321 sample_display_size_request (GtkWidget *widget,
322 GtkRequisition *requisition)
324 requisition->width = 10;
325 requisition->height = 32;
328 static void
329 sample_display_draw_data (GdkDrawable *win,
330 const SampleDisplay *s,
331 int color,
332 int x,
333 int width)
335 gint16 c, d;
336 GdkGC *gc;
337 const int sh = s->height;
339 if(width == 0)
340 return;
342 g_return_if_fail(x >= 0);
343 g_return_if_fail(x + width <= s->width);
345 gdk_draw_rectangle(win, color ? s->fg_gc : s->bg_gc,
346 TRUE, x, 0, width, s->height);
348 if(s->display_zero_line) {
349 gdk_draw_line(win, s->zeroline_gc, x, s->height / 2, x + width - 1, s->height / 2);
352 gc = color ? s->bg_gc : s->fg_gc;
354 if(s->datatype == 16) {
355 c = ((gint16*)s->data)[OFFSET_RANGE(s->datalen, XPOS_TO_OFFSET(x - 1))];
357 while(width >= 0) {
358 d = ((gint16*)s->data)[OFFSET_RANGE(s->datalen, XPOS_TO_OFFSET(x))];
359 gdk_draw_line(win, gc,
360 x - 1, ((32768 - c) * sh) >> 16,
361 x, ((32768 - d) * sh) >> 16);
362 c = d;
363 x++;
364 width--;
366 } else {
367 c = ((gint8*)s->data)[OFFSET_RANGE(s->datalen, XPOS_TO_OFFSET(x - 1))];
369 while(width >= 0) {
370 d = ((gint8*)s->data)[OFFSET_RANGE(s->datalen, XPOS_TO_OFFSET(x))];
371 gdk_draw_line(win, gc,
372 x - 1, ((128 - c) * sh) >> 8,
373 x, ((128 - d) * sh) >> 8);
374 c = d;
375 x++;
376 width--;
381 static int
382 sample_display_startoffset_to_xpos (SampleDisplay *s,
383 int offset)
385 gint64 d = offset - s->win_start;
387 if(d < 0)
388 return 0;
389 if(d >= s->win_length)
390 return s->width;
392 return d * s->width / s->win_length;
395 static int
396 sample_display_endoffset_to_xpos (SampleDisplay *s,
397 int offset)
399 if(s->win_length < s->width) {
400 return sample_display_startoffset_to_xpos(s, offset);
401 } else {
402 gint64 d = offset - s->win_start;
403 int l = (1 - s->win_length) / s->width;
405 /* you get these tests by setting the complete formula below equal to 0 or s->width, respectively,
406 and then resolving towards d. */
407 if(d < l)
408 return 0;
409 if(d > s->win_length + l)
410 return s->width;
412 return (d * s->width + s->win_length - 1) / s->win_length;
416 static void
417 sample_display_do_marker_line (GdkDrawable *win,
418 SampleDisplay *s,
419 int endoffset,
420 int offset,
421 int x_min,
422 int x_max,
423 GdkGC *gc)
425 int x;
427 if(offset >= s->win_start && offset <= s->win_start + s->win_length) {
428 if(!endoffset)
429 x = sample_display_startoffset_to_xpos(s, offset);
430 else
431 x = sample_display_endoffset_to_xpos(s, offset);
432 if(x+3 >= x_min && x-3 < x_max) {
433 gdk_draw_line(win, gc,
434 x, 0,
435 x, s->height);
436 gdk_draw_rectangle(win, gc, TRUE,
437 x - 3, 0, 7, 10);
438 gdk_draw_rectangle(win, gc, TRUE,
439 x - 3, s->height - 10, 7, 10);
444 static void
445 sample_display_draw_main (GtkWidget *widget,
446 GdkRectangle *area)
448 SampleDisplay *s = SAMPLE_DISPLAY(widget);
449 int x, x2;
451 g_return_if_fail(area->x >= 0);
453 if(area->width == 0)
454 return;
456 if(area->x + area->width > s->width)
457 return;
459 if(!IS_INITIALIZED(s)) {
460 gdk_draw_rectangle(widget->window,
461 s->bg_gc,
462 TRUE, area->x, area->y, area->width, area->height);
463 gdk_draw_line(widget->window,
464 s->fg_gc,
465 area->x, s->height / 2,
466 area->x + area->width - 1, s->height / 2);
467 } else {
468 const int x_min = area->x;
469 const int x_max = area->x + area->width;
471 if(s->sel_start != -1) {
472 /* draw the part to the left of the selection */
473 x = sample_display_startoffset_to_xpos(s, s->sel_start);
474 x = MIN(x_max, MAX(x_min, x));
475 sample_display_draw_data(widget->window, s, 0, x_min, x - x_min);
477 /* draw the selection */
478 x2 = sample_display_endoffset_to_xpos(s, s->sel_end);
479 x2 = MIN(x_max, MAX(x_min, x2));
480 sample_display_draw_data(widget->window, s, 1, x, x2 - x);
481 } else {
482 /* we don't have a selection */
483 x2 = x_min;
486 /* draw the part to the right of the selection */
487 sample_display_draw_data(widget->window, s, 0, x2, x_max - x2);
489 if(s->loop_start != -1) {
490 sample_display_do_marker_line(widget->window, s, 0, s->loop_start, x_min, x_max, s->loop_gc);
491 sample_display_do_marker_line(widget->window, s, 1, s->loop_end, x_min, x_max, s->loop_gc);
494 if(s->mixerpos != -1) {
495 sample_display_do_marker_line(widget->window, s, 0, s->mixerpos, x_min, x_max, s->mixerpos_gc);
496 s->old_mixerpos = s->mixerpos;
501 static void
502 sample_display_draw_update (GtkWidget *widget,
503 GdkRectangle *area)
505 SampleDisplay *s = SAMPLE_DISPLAY(widget);
506 GdkRectangle area2 = { 0, 0, 0, s->height };
507 int x, i;
508 const int x_min = area->x;
509 const int x_max = area->x + area->width;
510 gboolean special_draw = FALSE;
512 if(s->mixerpos != s->old_mixerpos) {
513 /* Redraw area of old position, redraw area of new position. */
514 for(i = 0; i < 2; i++) {
515 if(s->old_mixerpos >= s->win_start && s->old_mixerpos < s->win_start + s->win_length) {
516 x = sample_display_startoffset_to_xpos(s, s->old_mixerpos);
517 area2.x = MIN(x_max - 1, MAX(x_min, x - 3));
518 area2.width = 7;
519 if(area2.x + area2.width > x_max) {
520 area2.width = x_max - area2.x;
522 sample_display_draw_main(widget, &area2);
524 s->old_mixerpos = s->mixerpos;
526 special_draw = TRUE;
529 if(s->sel_start != s->old_ss || s->sel_end != s->old_se) {
530 if(s->sel_start == -1 || s->old_ss == -1) {
531 sample_display_draw_main(widget, area);
532 } else {
533 if(s->sel_start < s->old_ss) {
534 /* repaint left additional side */
535 x = sample_display_startoffset_to_xpos(s, s->sel_start);
536 area2.x = MIN(x_max, MAX(x_min, x));
537 x = sample_display_startoffset_to_xpos(s, s->old_ss);
538 area2.width = MIN(x_max, MAX(x_min, x)) - area2.x;
539 } else {
540 /* repaint left removed side */
541 x = sample_display_startoffset_to_xpos(s, s->old_ss);
542 area2.x = MIN(x_max, MAX(x_min, x));
543 x = sample_display_startoffset_to_xpos(s, s->sel_start);
544 area2.width = MIN(x_max, MAX(x_min, x)) - area2.x;
546 sample_display_draw_main(widget, &area2);
548 if(s->sel_end < s->old_se) {
549 /* repaint right removed side */
550 x = sample_display_endoffset_to_xpos(s, s->sel_end);
551 area2.x = MIN(x_max, MAX(x_min, x));
552 x = sample_display_endoffset_to_xpos(s, s->old_se);
553 area2.width = MIN(x_max, MAX(x_min, x)) - area2.x;
554 } else {
555 /* repaint right additional side */
556 x = sample_display_endoffset_to_xpos(s, s->old_se);
557 area2.x = MIN(x_max, MAX(x_min, x));
558 x = sample_display_endoffset_to_xpos(s, s->sel_end);
559 area2.width = MIN(x_max, MAX(x_min, x)) - area2.x;
561 sample_display_draw_main(widget, &area2);
564 s->old_ss = s->sel_start;
565 s->old_se = s->sel_end;
566 special_draw = TRUE;
569 if(!special_draw) {
570 sample_display_draw_main(widget, area);
574 static gint
575 sample_display_expose (GtkWidget *widget,
576 GdkEventExpose *event)
578 sample_display_draw_main(widget, &event->area);
579 return FALSE;
582 static gint
583 sample_display_idle_draw_function (SampleDisplay *s)
585 GdkRectangle area = { 0, 0, s->width, s->height };
587 if(GTK_WIDGET_MAPPED(GTK_WIDGET(s))) {
588 sample_display_draw_update(GTK_WIDGET(s), &area);
591 gtk_idle_remove(s->idle_handler);
592 s->idle_handler = 0;
593 return TRUE;
596 static void
597 sample_display_handle_motion (SampleDisplay *s,
598 int x,
599 int y,
600 int just_clicked)
602 int ol, or;
603 int ss = s->sel_start, se = s->sel_end;
604 int ls = s->loop_start, le = s->loop_end;
606 if(!s->selecting)
607 return;
609 if(x < 0)
610 x = 0;
611 else if(x >= s->width)
612 x = s->width - 1;
614 ol = XPOS_TO_OFFSET(x);
615 if(s->win_length < s->width) {
616 or = XPOS_TO_OFFSET(x) + 1;
617 } else {
618 or = XPOS_TO_OFFSET(x + 1);
621 g_return_if_fail(ol >= 0 && ol < s->datalen);
622 g_return_if_fail(or > 0 && or <= s->datalen);
623 g_return_if_fail(ol < or);
625 switch(s->selecting) {
626 case SELECTING_SELECTION_START:
627 if(just_clicked) {
628 if(ss != -1 && ol < se) {
629 ss = ol;
630 } else {
631 ss = ol;
632 se = ol + 1;
634 } else {
635 if(ol < se) {
636 ss = ol;
637 } else {
638 ss = se - 1;
639 se = or;
640 s->selecting = SELECTING_SELECTION_END;
643 break;
644 case SELECTING_SELECTION_END:
645 if(just_clicked) {
646 if(ss != -1 && or > ss) {
647 se = or;
648 } else {
649 ss = or - 1;
650 se = or;
652 } else {
653 if(or > ss) {
654 se = or;
655 } else {
656 se = ss + 1;
657 ss = ol;
658 s->selecting = SELECTING_SELECTION_START;
661 break;
662 case SELECTING_LOOP_START:
663 if(ol < s->loop_end)
664 ls = ol;
665 else
666 ls = le - 1;
667 break;
668 case SELECTING_LOOP_END:
669 if(or > s->loop_start)
670 le = or;
671 else
672 le = ls + 1;
673 break;
674 default:
675 g_assert_not_reached();
676 break;
679 if(s->sel_start != ss || s->sel_end != se) {
680 s->sel_start = ss;
681 s->sel_end = se;
682 sample_display_idle_draw(s);
683 gtk_signal_emit(GTK_OBJECT(s), sample_display_signals[SIG_SELECTION_CHANGED], ss, se);
686 if(s->loop_start != ls || s->loop_end != le) {
687 s->loop_start = ls;
688 s->loop_end = le;
689 sample_display_idle_draw(s);
690 gtk_signal_emit(GTK_OBJECT(s), sample_display_signals[SIG_LOOP_CHANGED], ls, le);
694 // Handle middle mousebutton display window panning
695 static void
696 sample_display_handle_motion_2 (SampleDisplay *s,
697 int x,
698 int y)
700 int new_win_start = s->selecting_wins0 + (s->selecting_x0 - x) * s->win_length / s->width;
702 new_win_start = CLAMP(new_win_start, 0, s->datalen - s->win_length);
704 if(new_win_start != s->win_start) {
705 sample_display_set_window (s,
706 new_win_start,
707 new_win_start + s->win_length);
711 static gint
712 sample_display_button_press (GtkWidget *widget,
713 GdkEventButton *event)
715 SampleDisplay *s;
716 int x, y;
717 GdkModifierType state;
719 g_return_val_if_fail (widget != NULL, FALSE);
720 g_return_val_if_fail (IS_SAMPLE_DISPLAY (widget), FALSE);
721 g_return_val_if_fail (event != NULL, FALSE);
723 s = SAMPLE_DISPLAY(widget);
725 if(!s->edit)
726 return FALSE;
728 if(!IS_INITIALIZED(s))
729 return TRUE;
731 if(s->selecting && event->button != s->button) {
732 s->selecting = 0;
733 } else {
734 s->button = event->button;
735 gdk_window_get_pointer (event->window, &x, &y, &state);
736 if(!(state & GDK_SHIFT_MASK)) {
737 if(s->button == 1) {
738 s->selecting = SELECTING_SELECTION_START;
739 } else if(s->button == 2) {
740 s->selecting = SELECTING_PAN_WINDOW;
741 gdk_window_get_pointer (event->window, &s->selecting_x0, NULL, NULL);
742 s->selecting_wins0 = s->win_start;
743 } else if(s->button == 3) {
744 s->selecting = SELECTING_SELECTION_END;
746 } else {
747 if(s->loop_start != -1) {
748 if(s->button == 1) {
749 s->selecting = SELECTING_LOOP_START;
750 } else if(s->button == 3) {
751 s->selecting = SELECTING_LOOP_END;
755 if(!s->selecting)
756 return TRUE;
757 if(s->selecting != SELECTING_PAN_WINDOW)
758 sample_display_handle_motion(s, x, y, 1);
761 return TRUE;
764 static gint
765 sample_display_button_release (GtkWidget *widget,
766 GdkEventButton *event)
768 SampleDisplay *s;
770 g_return_val_if_fail (widget != NULL, FALSE);
771 g_return_val_if_fail (IS_SAMPLE_DISPLAY (widget), FALSE);
772 g_return_val_if_fail (event != NULL, FALSE);
774 s = SAMPLE_DISPLAY(widget);
776 if(!s->edit)
777 return FALSE;
779 if(s->selecting && event->button == s->button) {
780 s->selecting = 0;
783 return TRUE;
786 static gint
787 sample_display_motion_notify (GtkWidget *widget,
788 GdkEventMotion *event)
790 SampleDisplay *s;
791 int x, y;
792 GdkModifierType state;
794 s = SAMPLE_DISPLAY(widget);
796 if(!s->edit)
797 return FALSE;
799 if(!IS_INITIALIZED(s) || !s->selecting)
800 return TRUE;
802 if (event->is_hint) {
803 gdk_window_get_pointer (event->window, &x, &y, &state);
804 } else {
805 x = event->x;
806 y = event->y;
807 state = event->state;
810 if(((state & GDK_BUTTON1_MASK) && s->button == 1) || ((state & GDK_BUTTON3_MASK) && s->button == 3)) {
811 sample_display_handle_motion(SAMPLE_DISPLAY(widget), x, y, 0);
812 } else if((state & GDK_BUTTON2_MASK) && s->button == 2) {
813 sample_display_handle_motion_2(SAMPLE_DISPLAY(widget), x, y);
814 } else {
815 s->selecting = 0;
818 return TRUE;
821 static void
822 sample_display_class_init (SampleDisplayClass *class)
824 GtkObjectClass *object_class;
825 GtkWidgetClass *widget_class;
826 int n;
827 const int *p;
828 GdkColor *c;
830 object_class = (GtkObjectClass*) class;
831 widget_class = (GtkWidgetClass*) class;
833 widget_class->realize = sample_display_realize;
834 widget_class->size_allocate = sample_display_size_allocate;
835 widget_class->expose_event = sample_display_expose;
836 //widget_class->draw = sample_display_draw;
837 widget_class->size_request = sample_display_size_request;
838 widget_class->button_press_event = sample_display_button_press;
839 widget_class->button_release_event = sample_display_button_release;
840 widget_class->motion_notify_event = sample_display_motion_notify;
842 sample_display_signals[SIG_SELECTION_CHANGED] = gtk_signal_new ("selection_changed",
843 GTK_RUN_FIRST,
844 GTK_CLASS_TYPE(object_class),
845 GTK_SIGNAL_OFFSET(SampleDisplayClass, selection_changed),
846 gtk_marshal_NONE__INT_INT,
847 GTK_TYPE_NONE, 2,
848 GTK_TYPE_INT,
849 GTK_TYPE_INT);
850 sample_display_signals[SIG_LOOP_CHANGED] = gtk_signal_new ("loop_changed",
851 GTK_RUN_FIRST,
852 GTK_CLASS_TYPE(object_class),
853 GTK_SIGNAL_OFFSET(SampleDisplayClass, loop_changed),
854 gtk_marshal_NONE__INT_INT,
855 GTK_TYPE_NONE, 2,
856 GTK_TYPE_INT,
857 GTK_TYPE_INT);
858 sample_display_signals[SIG_WINDOW_CHANGED] = gtk_signal_new ("window_changed",
859 GTK_RUN_FIRST,
860 GTK_CLASS_TYPE(object_class),
861 GTK_SIGNAL_OFFSET(SampleDisplayClass, window_changed),
862 gtk_marshal_NONE__INT_INT,
863 GTK_TYPE_NONE, 2,
864 GTK_TYPE_INT,
865 GTK_TYPE_INT);
867 //gtk_object_class_add_signals(object_class, sample_display_signals, LAST_SIGNAL);
869 class->selection_changed = NULL;
870 class->loop_changed = NULL;
871 class->window_changed = NULL;
873 for(n = 0, p = default_colors, c = class->colors; n < SAMPLE_DISPLAYCOL_LAST; n++, c++) {
874 c->red = *p++ * 65535 / 255;
875 c->green = *p++ * 65535 / 255;
876 c->blue = *p++ * 65535 / 255;
877 c->pixel = (gulong)((c->red & 0xff00)*256 + (c->green & 0xff00) + (c->blue & 0xff00)/256);
878 gdk_color_alloc(gdk_colormap_get_system(), c);
882 static void
883 sample_display_init (SampleDisplay *s)
885 s->idle_handler = 0;
888 guint
889 sample_display_get_type (void)
891 static guint sample_display_type = 0;
893 if (!sample_display_type) {
894 GtkTypeInfo sample_display_info =
896 "SampleDisplay",
897 sizeof(SampleDisplay),
898 sizeof(SampleDisplayClass),
899 (GtkClassInitFunc) sample_display_class_init,
900 (GtkObjectInitFunc) sample_display_init,
901 NULL,
902 NULL,
905 sample_display_type = gtk_type_unique (gtk_widget_get_type (), &sample_display_info);
908 return sample_display_type;
911 GtkWidget*
912 sample_display_new (gboolean edit)
914 SampleDisplay *s = SAMPLE_DISPLAY(gtk_type_new(sample_display_get_type()));
916 s->edit = edit;
917 s->datacopy = 0;
918 s->display_zero_line = 0;
919 return GTK_WIDGET(s);