missing commit in generator.h
[galan.git] / src / gtkslider.c
blob0fe20221e67a0127b80cd1d7a027e3e1fc47e889
1 /* gAlan - Graphical Audio Language
2 * Copyright (C) 1999 Tony Garnock-Jones
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <math.h>
20 #include <stdio.h>
21 #include <gtk/gtkmain.h>
22 #include <gtk/gtksignal.h>
24 #include "gtkslider.h"
26 #ifndef M_PI
27 # define M_PI 3.14159265358979323846 /* pi */
28 #endif
30 #define SCROLL_DELAY_LENGTH 300
31 #define SLIDER_WIDTH 32
32 #define DEFAULT_SLIDER_SIZE 100 /* travel distance, in pixels */
33 #define SLIDER_GAP 12
35 #define STATE_IDLE 0
36 #define STATE_PRESSED 1
37 #define STATE_DRAGGING 2
39 /* XPM */
40 static char * slider_xpm[] = {
41 "24 8 94 2",
42 " c None",
43 ". c #EBEBEB",
44 "+ c #EAEAEA",
45 "@ c #E5E5E5",
46 "# c #E4E4E4",
47 "$ c #E2E2E2",
48 "% c #E3E3E3",
49 "& c #E6E6E6",
50 "* c #E9E9E9",
51 "= c #E7E7E7",
52 "- c #E8E8E8",
53 "; c #E1E1E1",
54 "> c #E0E0E0",
55 ", c #DBDBDB",
56 "' c #D4D4D4",
57 ") c #C7C7C7",
58 "! c #D9D9D9",
59 "~ c #D5D5D5",
60 "{ c #D7D7D7",
61 "] c #D8D8D8",
62 "^ c #DDDDDD",
63 "/ c #DADADA",
64 "( c #D6D6D6",
65 "_ c #D0D0D0",
66 ": c #CECECE",
67 "< c #D1D1D1",
68 "[ c #CBCBCB",
69 "} c #BDBDBD",
70 "| c #AEAEAE",
71 "1 c #EEEEEE",
72 "2 c #C4C4C4",
73 "3 c #BBBBBB",
74 "4 c #C0C0C0",
75 "5 c #BFBFBF",
76 "6 c #C2C2C2",
77 "7 c #C1C1C1",
78 "8 c #BEBEBE",
79 "9 c #BCBCBC",
80 "0 c #B4B4B4",
81 "a c #999999",
82 "b c #868686",
83 "c c #AFAFAF",
84 "d c #A3A3A3",
85 "e c #858585",
86 "f c #7F7F7F",
87 "g c #7D7D7D",
88 "h c #6F6F6F",
89 "i c #616161",
90 "j c #DCDCDC",
91 "k c #CCCCCC",
92 "l c #C9C9C9",
93 "m c #ADADAD",
94 "n c #929292",
95 "o c #B6B6B6",
96 "p c #A6A6A6",
97 "q c #A4A4A4",
98 "r c #A5A5A5",
99 "s c #A8A8A8",
100 "t c #A7A7A7",
101 "u c #A9A9A9",
102 "v c #9E9E9E",
103 "w c #9F9F9F",
104 "x c #A1A1A1",
105 "y c #959595",
106 "z c #555555",
107 "A c #A2A2A2",
108 "B c #919191",
109 "C c #8B8B8B",
110 "D c #898989",
111 "E c #878787",
112 "F c #888888",
113 "G c #8D8D8D",
114 "H c #8C8C8C",
115 "I c #8A8A8A",
116 "J c #848484",
117 "K c #797979",
118 "L c #696969",
119 "M c #5C5C5C",
120 "N c #B1B1B1",
121 "O c #939393",
122 "P c #818181",
123 "Q c #7B7B7B",
124 "R c #787878",
125 "S c #747474",
126 "T c #6C6C6C",
127 "U c #6A6A6A",
128 "V c #727272",
129 "W c #717171",
130 "X c #737373",
131 "Y c #707070",
132 "Z c #6E6E6E",
133 "` c #646464",
134 " . c #686868",
135 ".. c #666666",
136 ". + @ @ # # $ $ % & * * & & = - @ ; > ; > , ' ) ",
137 ". @ ! ~ { { ] ! ] , ^ ^ / ] ! ! ( _ : _ < [ } | ",
138 "1 % 2 3 } } 4 5 4 4 6 7 8 3 8 8 9 9 9 } } 0 a b ",
139 "c d e f f f f f f f f f f f f f f f f f f g h i ",
140 "j ] : k k k k k k k k k k k k k k k k k k l m n ",
141 "+ { o p q d d r r s t u t t r d v v w x v y h z ",
142 "j ) A B C D D E E F G H C H C I E J J e f K L M ",
143 "l N O P Q R S T U h V V W W X X Y Z W U ` ...` "};
145 /* Forward declarations */
147 static void gtk_slider_class_init(GtkSliderClass *klass);
148 static void gtk_slider_init(GtkSlider *slider);
149 static void gtk_slider_destroy(GtkObject *object);
150 static void gtk_slider_realize(GtkWidget *widget);
151 static void gtk_slider_size_request(GtkWidget *widget, GtkRequisition *requisition);
152 static void gtk_slider_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
153 static gint gtk_slider_expose(GtkWidget *widget, GdkEventExpose *event);
154 static gint gtk_slider_button_press(GtkWidget *widget, GdkEventButton *event);
155 static gint gtk_slider_button_release(GtkWidget *widget, GdkEventButton *event);
156 static gint gtk_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event);
157 static gint gtk_slider_timer(GtkSlider *slider);
159 static void gtk_slider_update_mouse_update(GtkSlider *slider);
160 static void gtk_slider_update_mouse(GtkSlider *slider, gint x, gint y);
161 static void gtk_slider_update_mouse_abs(GtkSlider *slider, gint x, gint y);
162 static void gtk_slider_update(GtkSlider *slider);
163 static void gtk_slider_adjustment_changed(GtkAdjustment *adjustment, gpointer data);
164 static void gtk_slider_adjustment_value_changed(GtkAdjustment *adjustment, gpointer data);
166 /* Local data */
168 static GtkWidgetClass *parent_class = NULL;
170 guint gtk_slider_get_type(void) {
171 static guint slider_type = 0;
173 if (!slider_type) {
174 GtkTypeInfo slider_info = {
175 "GtkSlider",
176 sizeof (GtkSlider),
177 sizeof (GtkSliderClass),
178 (GtkClassInitFunc) gtk_slider_class_init,
179 (GtkObjectInitFunc) gtk_slider_init,
180 NULL,
181 NULL,
184 slider_type = gtk_type_unique(gtk_widget_get_type(), &slider_info);
187 return slider_type;
190 static void gtk_slider_class_init (GtkSliderClass *class) {
191 GtkObjectClass *object_class;
192 GtkWidgetClass *widget_class;
194 object_class = (GtkObjectClass*) class;
195 widget_class = (GtkWidgetClass*) class;
197 parent_class = gtk_type_class(gtk_widget_get_type());
199 object_class->destroy = gtk_slider_destroy;
201 widget_class->realize = gtk_slider_realize;
202 widget_class->expose_event = gtk_slider_expose;
203 widget_class->size_request = gtk_slider_size_request;
204 widget_class->size_allocate = gtk_slider_size_allocate;
205 widget_class->button_press_event = gtk_slider_button_press;
206 widget_class->button_release_event = gtk_slider_button_release;
207 widget_class->motion_notify_event = gtk_slider_motion_notify;
210 static void gtk_slider_init (GtkSlider *slider) {
211 slider->policy = GTK_UPDATE_CONTINUOUS;
212 slider->state = STATE_IDLE;
213 slider->saved_x = slider->saved_y = 0;
214 slider->timer = 0;
215 slider->pixmap = NULL;
216 slider->size = DEFAULT_SLIDER_SIZE;
217 slider->old_value = 0.0;
218 slider->old_lower = 0.0;
219 slider->old_upper = 0.0;
220 slider->adjustment = NULL;
223 GtkWidget *gtk_slider_new(GtkAdjustment *adjustment, gint size) {
224 GtkSlider *slider;
226 slider = gtk_type_new(gtk_slider_get_type());
228 if (!adjustment)
229 adjustment = (GtkAdjustment*) gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
232 if (size == 0)
233 size = DEFAULT_SLIDER_SIZE;
235 slider->size = size;
237 gtk_slider_set_adjustment(slider, adjustment);
239 return GTK_WIDGET(slider);
242 static void gtk_slider_destroy(GtkObject *object) {
243 GtkSlider *slider;
245 g_return_if_fail(object != NULL);
246 g_return_if_fail(GTK_IS_SLIDER(object));
248 slider = GTK_SLIDER(object);
250 if (slider->adjustment) {
251 gtk_object_unref(GTK_OBJECT(slider->adjustment));
252 slider->adjustment = NULL;
255 if (slider->pixmap) {
256 gdk_pixmap_unref(slider->pixmap);
257 slider->pixmap = NULL;
260 if (GTK_OBJECT_CLASS(parent_class)->destroy)
261 (*GTK_OBJECT_CLASS(parent_class)->destroy)(object);
264 GtkAdjustment* gtk_slider_get_adjustment(GtkSlider *slider) {
265 g_return_val_if_fail(slider != NULL, NULL);
266 g_return_val_if_fail(GTK_IS_SLIDER(slider), NULL);
268 return slider->adjustment;
271 void gtk_slider_set_update_policy(GtkSlider *slider, GtkUpdateType policy) {
272 g_return_if_fail (slider != NULL);
273 g_return_if_fail (GTK_IS_SLIDER (slider));
275 slider->policy = policy;
278 void gtk_slider_set_adjustment(GtkSlider *slider, GtkAdjustment *adjustment) {
279 g_return_if_fail (slider != NULL);
280 g_return_if_fail (GTK_IS_SLIDER (slider));
282 if (slider->adjustment) {
283 gtk_signal_disconnect_by_data(GTK_OBJECT(slider->adjustment), (gpointer)slider);
284 gtk_object_unref(GTK_OBJECT(slider->adjustment));
287 slider->adjustment = adjustment;
288 gtk_object_ref(GTK_OBJECT(slider->adjustment));
289 gtk_object_sink(GTK_OBJECT( slider-> adjustment ) );
291 gtk_signal_connect(GTK_OBJECT(adjustment), "changed",
292 GTK_SIGNAL_FUNC(gtk_slider_adjustment_changed), (gpointer) slider);
293 gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed",
294 GTK_SIGNAL_FUNC(gtk_slider_adjustment_value_changed), (gpointer) slider);
296 slider->old_value = adjustment->value;
297 slider->old_lower = adjustment->lower;
298 slider->old_upper = adjustment->upper;
300 gtk_slider_update(slider);
303 static void gtk_slider_realize(GtkWidget *widget) {
304 GtkSlider *slider;
305 GdkWindowAttr attributes;
306 gint attributes_mask;
307 GdkBitmap *mask;
309 g_return_if_fail(widget != NULL);
310 g_return_if_fail(GTK_IS_SLIDER(widget));
312 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
313 slider = GTK_SLIDER(widget);
315 attributes.x = widget->allocation.x;
316 attributes.y = widget->allocation.y;
317 attributes.width = widget->allocation.width;
318 attributes.height = widget->allocation.height;
319 attributes.wclass = GDK_INPUT_OUTPUT;
320 attributes.window_type = GDK_WINDOW_CHILD;
321 attributes.event_mask =
322 gtk_widget_get_events (widget) |
323 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
324 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
325 GDK_POINTER_MOTION_HINT_MASK;
326 attributes.visual = gtk_widget_get_visual(widget);
327 attributes.colormap = gtk_widget_get_colormap(widget);
329 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
330 widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask);
332 widget->style = gtk_style_attach(widget->parent->style, widget->window);
334 gdk_window_set_user_data(widget->window, widget);
336 slider->pixmap = gdk_pixmap_colormap_create_from_xpm_d(widget->window, gdk_colormap_get_system(), &mask,
337 &widget->style->bg[GTK_STATE_NORMAL],
338 slider_xpm);
340 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
343 static void gtk_slider_size_request (GtkWidget *widget, GtkRequisition *requisition) {
344 requisition->width = SLIDER_WIDTH;
345 requisition->height = GTK_SLIDER(widget)->size + SLIDER_GAP * 2;
348 static void gtk_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation) {
349 GtkSlider *slider;
351 g_return_if_fail(widget != NULL);
352 g_return_if_fail(GTK_IS_SLIDER(widget));
353 g_return_if_fail(allocation != NULL);
355 widget->allocation = *allocation;
356 slider = GTK_SLIDER(widget);
358 if (GTK_WIDGET_REALIZED(widget)) {
359 gdk_window_move_resize(widget->window,
360 allocation->x, allocation->y,
361 allocation->width, allocation->height);
365 static gint gtk_slider_expose(GtkWidget *widget, GdkEventExpose *event) {
366 GtkSlider *slider;
367 gfloat dy;
369 g_return_val_if_fail(widget != NULL, FALSE);
370 g_return_val_if_fail(GTK_IS_SLIDER(widget), FALSE);
371 g_return_val_if_fail(event != NULL, FALSE);
373 if (event->count > 0)
374 return FALSE;
376 slider = GTK_SLIDER(widget);
378 gdk_window_clear_area(widget->window, 0, 0, widget->allocation.width, widget->allocation.height);
380 // gdk_draw_rectangle(widget->window, widget->style->bg_gc[widget->state], TRUE,
381 // 0, 0, widget->allocation.width, widget->allocation.height);
383 gdk_draw_line(widget->window, widget->style->black_gc,
384 SLIDER_WIDTH>>1, SLIDER_GAP, SLIDER_WIDTH>>1, SLIDER_GAP + slider->size);
386 dy = slider->adjustment->upper - slider->adjustment->lower;
388 if (dy != 0) {
389 dy = (slider->adjustment->value - slider->adjustment->lower) / dy;
390 dy = MIN(MAX(dy, 0), 1);
391 dy = (1 - dy) * slider->size + SLIDER_GAP;
393 gdk_draw_pixmap(widget->window, widget->style->bg_gc[widget->state], slider->pixmap,
394 0, 0, (SLIDER_WIDTH>>1)-12, dy-4, 24, 8);
397 return FALSE;
400 static gint gtk_slider_button_press(GtkWidget *widget, GdkEventButton *event) {
401 GtkSlider *slider;
403 g_return_val_if_fail(widget != NULL, FALSE);
404 g_return_val_if_fail(GTK_IS_SLIDER(widget), FALSE);
405 g_return_val_if_fail(event != NULL, FALSE);
407 slider = GTK_SLIDER(widget);
409 switch (slider->state) {
410 case STATE_IDLE:
411 switch (event->button) {
412 #if 0
413 case 2:
414 gtk_slider_update_mouse_abs(slider, event->x, event->y);
415 /* FALL THROUGH */
416 #endif
418 case 1:
419 case 3:
420 gtk_grab_add(widget);
421 slider->state = STATE_PRESSED;
422 slider->saved_x = event->x;
423 slider->saved_y = event->y;
424 break;
426 default:
427 break;
429 break;
431 default:
432 break;
435 return FALSE;
438 static gint gtk_slider_button_release(GtkWidget *widget, GdkEventButton *event) {
439 GtkSlider *slider;
441 g_return_val_if_fail(widget != NULL, FALSE);
442 g_return_val_if_fail(GTK_IS_SLIDER(widget), FALSE);
443 g_return_val_if_fail(event != NULL, FALSE);
445 slider = GTK_SLIDER(widget);
447 switch (slider->state) {
448 case STATE_PRESSED:
449 gtk_grab_remove(widget);
450 slider->state = STATE_IDLE;
452 switch (event->button) {
453 case 1:
454 slider->adjustment->value -= slider->adjustment->page_increment;
455 gtk_signal_emit_by_name(GTK_OBJECT(slider->adjustment), "value_changed");
456 break;
458 case 3:
459 slider->adjustment->value += slider->adjustment->page_increment;
460 gtk_signal_emit_by_name(GTK_OBJECT(slider->adjustment), "value_changed");
461 break;
463 default:
464 break;
466 break;
468 case STATE_DRAGGING:
469 gtk_grab_remove(widget);
470 slider->state = STATE_IDLE;
472 if (slider->policy != GTK_UPDATE_CONTINUOUS && slider->old_value != slider->adjustment->value)
473 gtk_signal_emit_by_name(GTK_OBJECT(slider->adjustment), "value_changed");
475 break;
477 default:
478 break;
481 return FALSE;
484 static gint gtk_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event) {
485 GtkSlider *slider;
486 GdkModifierType mods;
487 gint x, y;
489 g_return_val_if_fail(widget != NULL, FALSE);
490 g_return_val_if_fail(GTK_IS_SLIDER(widget), FALSE);
491 g_return_val_if_fail(event != NULL, FALSE);
493 slider = GTK_SLIDER(widget);
495 x = event->x;
496 y = event->y;
498 if (event->is_hint || (event->window != widget->window))
499 gdk_window_get_pointer(widget->window, &x, &y, &mods);
501 switch (slider->state) {
502 case STATE_PRESSED:
503 slider->state = STATE_DRAGGING;
504 /* fall through */
506 case STATE_DRAGGING:
507 if (mods & GDK_BUTTON1_MASK) {
508 gtk_slider_update_mouse(slider, x, y);
509 return TRUE;
510 } else if (mods & GDK_BUTTON3_MASK) {
511 gtk_slider_update_mouse_abs(slider, x, y);
512 return TRUE;
514 break;
516 default:
517 break;
520 return FALSE;
523 static gint gtk_slider_timer(GtkSlider *slider) {
524 g_return_val_if_fail(slider != NULL, FALSE);
525 g_return_val_if_fail(GTK_IS_SLIDER(slider), FALSE);
527 if (slider->policy == GTK_UPDATE_DELAYED)
528 gtk_signal_emit_by_name(GTK_OBJECT(slider->adjustment), "value_changed");
530 return FALSE; /* don't keep running this timer */
533 static void gtk_slider_update_mouse_update(GtkSlider *slider) {
534 if (slider->policy == GTK_UPDATE_CONTINUOUS)
535 gtk_signal_emit_by_name(GTK_OBJECT(slider->adjustment), "value_changed");
536 else {
537 gtk_widget_draw(GTK_WIDGET(slider), NULL);
539 if (slider->policy == GTK_UPDATE_DELAYED) {
540 if (slider->timer)
541 gtk_timeout_remove(slider->timer);
543 slider->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, (GtkFunction) gtk_slider_timer,
544 (gpointer) slider);
549 static void gtk_slider_update_mouse(GtkSlider *slider, gint x, gint y) {
550 gfloat old_value;
551 gfloat dv;
553 g_return_if_fail(slider != NULL);
554 g_return_if_fail(GTK_IS_SLIDER(slider));
556 old_value = slider->adjustment->value;
558 dv = (slider->saved_y - y) * slider->adjustment->step_increment;
559 slider->saved_x = x;
560 slider->saved_y = y;
562 slider->adjustment->value += dv;
564 if (slider->adjustment->value != old_value)
565 gtk_slider_update_mouse_update(slider);
568 static void gtk_slider_update_mouse_abs(GtkSlider *slider, gint x, gint y) {
569 gfloat old_value;
570 gfloat dy;
572 g_return_if_fail(slider != NULL);
573 g_return_if_fail(GTK_IS_SLIDER(slider));
575 old_value = slider->adjustment->value;
577 y -= SLIDER_GAP;
578 y = slider->size - y;
580 dy = y / ((gfloat) slider->size);
581 dy *= slider->adjustment->upper - slider->adjustment->lower;
582 dy += slider->adjustment->lower;
584 slider->adjustment->value = dy;
586 if (slider->adjustment->value != old_value)
587 gtk_slider_update_mouse_update(slider);
590 static void gtk_slider_update(GtkSlider *slider) {
591 gfloat new_value;
593 g_return_if_fail(slider != NULL);
594 g_return_if_fail(GTK_IS_SLIDER (slider));
596 new_value = slider->adjustment->value;
598 if (new_value < slider->adjustment->lower)
599 new_value = slider->adjustment->lower;
601 if (new_value > slider->adjustment->upper)
602 new_value = slider->adjustment->upper;
604 if (new_value != slider->adjustment->value) {
605 slider->adjustment->value = new_value;
606 gtk_signal_emit_by_name(GTK_OBJECT(slider->adjustment), "value_changed");
609 gtk_widget_draw(GTK_WIDGET(slider), NULL);
612 static void gtk_slider_adjustment_changed(GtkAdjustment *adjustment, gpointer data) {
613 GtkSlider *slider;
615 g_return_if_fail(adjustment != NULL);
616 g_return_if_fail(data != NULL);
618 slider = GTK_SLIDER(data);
620 if ((slider->old_value != adjustment->value) ||
621 (slider->old_lower != adjustment->lower) ||
622 (slider->old_upper != adjustment->upper)) {
623 gtk_slider_update (slider);
625 slider->old_value = adjustment->value;
626 slider->old_lower = adjustment->lower;
627 slider->old_upper = adjustment->upper;
631 static void gtk_slider_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) {
632 GtkSlider *slider;
634 g_return_if_fail(adjustment != NULL);
635 g_return_if_fail(data != NULL);
637 slider = GTK_SLIDER(data);
639 if (slider->old_value != adjustment->value) {
640 gtk_slider_update (slider);
642 slider->old_value = adjustment->value;