audiofile support + improved sample rate support + results of a -Wall -Werr
[terminatorX.git] / src / tX_dial.c
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2002  Alexander K├Ânig
4  
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9  
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_dial.ch
20  
21     Description: Implements the dial widget - this widget is based on the 
22     gtk_dial example from the gtk+ tutorial which is
23     Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
24 */    
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #ifdef USE_DIAL
31
32 #include <math.h>
33 #include <stdio.h>
34 #include <gtk/gtkmain.h>
35 #include <gtk/gtksignal.h>
36 #include "tX_knobloader.h"
37
38 #include "tX_dial.h"
39
40 #define SCROLL_DELAY_LENGTH  300
41 #define TX_DIAL_DEFAULT_SIZE 100
42
43 /* Forward declarations */
44
45 static void gtk_tx_dial_class_init            (GtkTxDialClass    *klass);
46 static void gtk_tx_dial_init                  (GtkTxDial         *tx_dial);
47 static void gtk_tx_dial_destroy               (GtkObject        *object);
48 static void gtk_tx_dial_realize               (GtkWidget        *widget);
49 static void gtk_tx_dial_size_request          (GtkWidget      *widget,
50                                                GtkRequisition *requisition);
51 static void gtk_tx_dial_size_allocate         (GtkWidget     *widget,
52                                                GtkAllocation *allocation);
53 static gint gtk_tx_dial_expose                (GtkWidget        *widget,
54                                                 GdkEventExpose   *event);
55 static gint gtk_tx_dial_button_press          (GtkWidget        *widget,
56                                                 GdkEventButton   *event);
57 static gint gtk_tx_dial_button_release        (GtkWidget        *widget,
58                                                 GdkEventButton   *event);
59 static gint gtk_tx_dial_motion_notify         (GtkWidget        *widget,
60                                                 GdkEventMotion   *event);
61 static gint gtk_tx_dial_timer                 (GtkTxDial         *tx_dial);
62
63 static void gtk_tx_dial_update_mouse          (GtkTxDial *tx_dial, gint x, gint y);
64 static void gtk_tx_dial_update                (GtkTxDial *tx_dial);
65 static void gtk_tx_dial_adjustment_changed       (GtkAdjustment *adjustment,
66                                                 gpointer          data);
67 static void gtk_tx_dial_adjustment_value_changed (GtkAdjustment *adjustment,
68                                                 gpointer          data);
69
70 /* Local data */
71
72 static GtkWidgetClass *parent_class = NULL;
73
74 #define calc_image(f,i); i=(gint) ((f - tx_dial->old_lower)/(tx_dial->old_range) * ((float) TX_MAX_KNOB_PIX)); if(i>TX_MAX_KNOB_PIX) i=TX_MAX_KNOB_PIX; else if (i<0) i=0;
75
76 guint
77 gtk_tx_dial_get_type ()
78 {
79   static guint tx_dial_type = 0;
80
81   if (!tx_dial_type)
82     {
83       GtkTypeInfo tx_dial_info =
84       {
85         "GtkTxDial",
86         sizeof (GtkTxDial),
87         sizeof (GtkTxDialClass),
88         (GtkClassInitFunc) gtk_tx_dial_class_init,
89         (GtkObjectInitFunc) gtk_tx_dial_init,
90         /* reserved */ NULL,
91         /* reserved */ NULL,
92         /* reserved */ NULL
93       };
94
95       tx_dial_type = gtk_type_unique (gtk_widget_get_type (), &tx_dial_info);
96     }
97
98   return tx_dial_type;
99 }
100
101 static void
102 gtk_tx_dial_class_init (GtkTxDialClass *class)
103 {
104   GtkObjectClass *object_class;
105   GtkWidgetClass *widget_class;
106
107   object_class = (GtkObjectClass*) class;
108   widget_class = (GtkWidgetClass*) class;
109
110   parent_class = gtk_type_class (gtk_widget_get_type ());
111
112   object_class->destroy = gtk_tx_dial_destroy;
113
114   widget_class->realize = gtk_tx_dial_realize;
115   widget_class->expose_event = gtk_tx_dial_expose;
116   widget_class->size_request = gtk_tx_dial_size_request;
117   widget_class->size_allocate = gtk_tx_dial_size_allocate;
118   widget_class->button_press_event = gtk_tx_dial_button_press;
119   widget_class->button_release_event = gtk_tx_dial_button_release;
120   widget_class->motion_notify_event = gtk_tx_dial_motion_notify;
121 }
122
123 static void
124 gtk_tx_dial_init (GtkTxDial *tx_dial)
125 {
126   tx_dial->button = 0;
127   tx_dial->policy = GTK_UPDATE_CONTINUOUS;
128   tx_dial->timer = 0;
129
130   tx_dial->old_value = 0.0;
131   tx_dial->old_lower = 0.0;
132   tx_dial->old_upper = 0.0;
133   tx_dial->old_range = 0.0; // Dangerous!
134   
135   tx_dial->old_image = 0;
136
137   tx_dial->yofs=0;
138   tx_dial->xofs=0;
139   
140   tx_dial->adjustment = NULL;
141 }
142
143 GtkWidget*
144 gtk_tx_dial_new (GtkAdjustment *adjustment)
145 {
146   GtkTxDial *tx_dial;
147
148   tx_dial = gtk_type_new (gtk_tx_dial_get_type ());
149
150   if (!adjustment)
151     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0,
152                                                       0.0, 0.0, 0.0);
153
154   gtk_tx_dial_set_adjustment (tx_dial, adjustment);
155   gtk_object_ref (GTK_OBJECT (tx_dial->adjustment));
156
157   return GTK_WIDGET (tx_dial);
158 }
159
160 static void
161 gtk_tx_dial_destroy (GtkObject *object)
162 {
163   GtkTxDial *tx_dial;
164
165   g_return_if_fail (object != NULL);
166   g_return_if_fail (GTK_IS_TX_DIAL (object));
167
168   tx_dial = GTK_TX_DIAL (object);
169
170   if (tx_dial->adjustment)
171     gtk_object_unref (GTK_OBJECT (tx_dial->adjustment));
172
173   if (GTK_OBJECT_CLASS (parent_class)->destroy)
174     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
175 }
176
177 GtkAdjustment*
178 gtk_tx_dial_get_adjustment (GtkTxDial *tx_dial)
179 {
180   g_return_val_if_fail (tx_dial != NULL, NULL);
181   g_return_val_if_fail (GTK_IS_TX_DIAL (tx_dial), NULL);
182
183   return tx_dial->adjustment;
184 }
185
186 void
187 gtk_tx_dial_set_update_policy (GtkTxDial         *tx_dial,
188                              GtkUpdateType  policy)
189 {
190   g_return_if_fail (tx_dial != NULL);
191   g_return_if_fail (GTK_IS_TX_DIAL (tx_dial));
192
193   tx_dial->policy = policy;
194 }
195
196 void
197 gtk_tx_dial_set_adjustment (GtkTxDial      *tx_dial,
198                           GtkAdjustment *adjustment)
199 {
200   g_return_if_fail (tx_dial != NULL);
201   g_return_if_fail (GTK_IS_TX_DIAL (tx_dial));
202
203   if (tx_dial->adjustment)
204     {
205       gtk_signal_disconnect_by_data (GTK_OBJECT (tx_dial->adjustment),
206                                      (gpointer) tx_dial);
207       gtk_object_unref (GTK_OBJECT (tx_dial->adjustment));
208     }
209
210   tx_dial->adjustment = adjustment;
211   gtk_object_ref (GTK_OBJECT (tx_dial->adjustment));
212
213   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
214                       (GtkSignalFunc) gtk_tx_dial_adjustment_changed,
215                       (gpointer) tx_dial);
216   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
217                       (GtkSignalFunc) gtk_tx_dial_adjustment_value_changed,
218                       (gpointer) tx_dial);
219
220   tx_dial->old_value = adjustment->value;
221   tx_dial->old_lower = adjustment->lower;
222   tx_dial->old_upper = adjustment->upper;
223   tx_dial->old_range = adjustment->upper - adjustment->lower;
224   
225   calc_image(adjustment->value,tx_dial->old_image);
226
227   gtk_tx_dial_update (tx_dial);
228 }
229
230 static void
231 gtk_tx_dial_realize (GtkWidget *widget)
232 {
233   GtkTxDial *tx_dial;
234   GdkWindowAttr attributes;
235   gint attributes_mask;
236
237   g_return_if_fail (widget != NULL);
238   g_return_if_fail (GTK_IS_TX_DIAL (widget));
239
240   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
241   tx_dial = GTK_TX_DIAL (widget);
242
243   attributes.x = widget->allocation.x;
244   attributes.y = widget->allocation.y;
245   attributes.width = widget->allocation.width;
246   attributes.height = widget->allocation.height;
247   attributes.wclass = GDK_INPUT_OUTPUT;
248   attributes.window_type = GDK_WINDOW_CHILD;
249   attributes.event_mask = gtk_widget_get_events (widget) | 
250     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
251     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
252     GDK_POINTER_MOTION_HINT_MASK;
253   attributes.visual = gtk_widget_get_visual (widget);
254   attributes.colormap = gtk_widget_get_colormap (widget);
255
256   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
257   widget->window = gdk_window_new (widget->parent->window,
258                                    &attributes,
259                                    attributes_mask);
260
261   gdk_window_set_user_data (widget->window, widget);
262   widget->style = gtk_style_attach (widget->style, widget->window);
263   gtk_widget_set_style(widget, gtk_widget_get_default_style());
264   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
265
266   gdk_window_set_background (widget->window, 
267                              &widget->style->base[GTK_STATE_NORMAL]); 
268   gtk_widget_shape_combine_mask (widget, knob_mask, 0,0);
269 }
270
271 static void 
272 gtk_tx_dial_size_request (GtkWidget      *widget,
273                        GtkRequisition *requisition)
274 {
275   requisition->width = KNOB_SIZE;
276   requisition->height = KNOB_SIZE;
277 }
278
279 static void
280 gtk_tx_dial_size_allocate (GtkWidget     *widget,
281                         GtkAllocation *allocation)
282 {
283   GtkTxDial *tx_dial;
284
285   g_return_if_fail (widget != NULL);
286   g_return_if_fail (GTK_IS_TX_DIAL (widget));
287   g_return_if_fail (allocation != NULL);
288
289   widget->allocation = *allocation;
290   tx_dial = GTK_TX_DIAL (widget);
291
292   if (GTK_WIDGET_REALIZED (widget))
293     {
294
295       gdk_window_move_resize (widget->window,
296                               allocation->x, allocation->y,
297                               allocation->width, allocation->height);
298  
299      tx_dial->xofs=(allocation->width-KNOB_SIZE)/2;
300      tx_dial->yofs=(allocation->height-KNOB_SIZE)/2;
301     }
302 }
303
304 inline void
305 gtk_tx_dial_draw (GtkTxDial *tx_dial, GtkWidget *widget)
306 {
307         if (GTK_WIDGET_DRAWABLE (widget)) {
308                 gdk_draw_pixmap(widget->window, widget->style->bg_gc[GTK_WIDGET_STATE(widget)],
309                          knob_pixmaps[tx_dial->old_image], 0, 0, tx_dial->xofs, tx_dial->yofs, KNOB_SIZE, KNOB_SIZE);
310         }                
311 }
312
313 static gint
314 gtk_tx_dial_expose (GtkWidget   *widget,
315                  GdkEventExpose *event)
316 {
317   GtkTxDial *tx_dial;
318
319   g_return_val_if_fail (widget != NULL, FALSE);
320   g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
321   g_return_val_if_fail (event != NULL, FALSE);
322
323   if (event->count > 0)
324     return FALSE;
325   
326   tx_dial = GTK_TX_DIAL (widget);
327
328   gtk_tx_dial_draw(tx_dial, widget);
329                   
330   return FALSE;
331 }
332
333 static gint
334 gtk_tx_dial_button_press (GtkWidget      *widget,
335                        GdkEventButton *event)
336 {
337   GtkTxDial *tx_dial;
338
339   g_return_val_if_fail (widget != NULL, FALSE);
340   g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
341   g_return_val_if_fail (event != NULL, FALSE);
342
343   tx_dial = GTK_TX_DIAL (widget);
344
345   tx_dial->x = event->x;
346   tx_dial->y = event->y;    
347   
348   if (!tx_dial->button)
349     {
350       gtk_grab_add (widget);
351
352       tx_dial->button = event->button;
353     }
354
355   return FALSE;
356 }
357
358 static gint
359 gtk_tx_dial_button_release (GtkWidget   *widget,
360                           GdkEventButton *event)
361 {
362   GtkTxDial *tx_dial;
363
364   g_return_val_if_fail (widget != NULL, FALSE);
365   g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
366   g_return_val_if_fail (event != NULL, FALSE);
367
368   tx_dial = GTK_TX_DIAL (widget);
369
370   if (tx_dial->button == event->button)
371     {
372       gtk_grab_remove (widget);
373
374       tx_dial->button = 0;
375
376       if (tx_dial->policy == GTK_UPDATE_DELAYED)
377         gtk_timeout_remove (tx_dial->timer);
378       
379       if ((tx_dial->policy != GTK_UPDATE_CONTINUOUS) &&
380           (tx_dial->old_value != tx_dial->adjustment->value))
381         gtk_signal_emit_by_name (GTK_OBJECT (tx_dial->adjustment),
382                                  "value_changed");
383     }
384
385   return FALSE;
386 }
387
388 static gint
389 gtk_tx_dial_motion_notify (GtkWidget      *widget,
390                          GdkEventMotion *event)
391 {
392   GtkTxDial *tx_dial;
393   GdkModifierType mods;
394   gint x, y, mask;
395
396   g_return_val_if_fail (widget != NULL, FALSE);
397   g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
398   g_return_val_if_fail (event != NULL, FALSE);
399
400   tx_dial = GTK_TX_DIAL (widget);
401
402   if (tx_dial->button != 0)
403     {
404       x = event->x;
405       y = event->y;
406
407       if (event->is_hint || (event->window != widget->window))
408         gdk_window_get_pointer (widget->window, &x, &y, &mods);
409
410       switch (tx_dial->button)
411         {
412         case 1:
413           mask = GDK_BUTTON1_MASK;
414           break;
415         case 2:
416           mask = GDK_BUTTON2_MASK;
417           break;
418         case 3:
419           mask = GDK_BUTTON3_MASK;
420           break;
421         default:
422           mask = 0;
423           break;
424         }
425
426       if (mods & mask)
427         gtk_tx_dial_update_mouse (tx_dial, x,y);
428     }
429
430   return FALSE;
431 }
432
433 static gint
434 gtk_tx_dial_timer (GtkTxDial *tx_dial)
435 {
436   g_return_val_if_fail (tx_dial != NULL, FALSE);
437   g_return_val_if_fail (GTK_IS_TX_DIAL (tx_dial), FALSE);
438
439   if (tx_dial->policy == GTK_UPDATE_DELAYED)
440     gtk_signal_emit_by_name (GTK_OBJECT (tx_dial->adjustment),
441                              "value_changed");
442
443   return FALSE;
444 }
445
446 static void
447 gtk_tx_dial_update_mouse (GtkTxDial *tx_dial, gint x, gint y)
448 {
449   gdouble dx, dy, d;
450   gfloat old_value;
451   gfloat new_value;
452   gint image;
453
454   g_return_if_fail (tx_dial != NULL);
455   g_return_if_fail (GTK_IS_TX_DIAL (tx_dial));
456
457   dx=x-tx_dial->x;
458   dy=tx_dial->y-y;
459
460   tx_dial->x=x;
461   tx_dial->y=y;
462
463   //if (fabs(dx) > fabs(dy)) d=dx; else d=dy;
464   d=dx+dy;
465   
466   d/=200.0;
467
468   old_value=tx_dial->adjustment->value;    
469     
470   new_value=old_value + d*tx_dial->old_range;
471   
472   if (new_value>tx_dial->old_upper) new_value=tx_dial->old_upper;
473   else if (new_value<tx_dial->old_lower) new_value=tx_dial->old_lower;
474  
475   tx_dial->adjustment->value=new_value;
476     
477   if (tx_dial->adjustment->value != old_value)
478     {
479       if (tx_dial->policy == GTK_UPDATE_CONTINUOUS)
480         {
481           gtk_signal_emit_by_name (GTK_OBJECT (tx_dial->adjustment),
482                                    "value_changed");
483         }
484       else
485         {
486           calc_image(tx_dial->adjustment->value, image);
487
488           if (image!=tx_dial->old_image)
489           {
490                  tx_dial->old_image=image;
491 //               gtk_widget_draw (GTK_WIDGET(tx_dial), NULL);
492                  gtk_tx_dial_draw(tx_dial, GTK_WIDGET(tx_dial));
493           }
494
495           if (tx_dial->policy == GTK_UPDATE_DELAYED)
496             {
497               if (tx_dial->timer)
498                 gtk_timeout_remove (tx_dial->timer);
499
500               tx_dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
501                                              (GtkFunction) gtk_tx_dial_timer,
502                                              (gpointer) tx_dial);
503             }
504         }
505     }
506 }
507
508 static void
509 gtk_tx_dial_update (GtkTxDial *tx_dial)
510 {
511   gfloat new_value;
512   gint image;
513   
514   g_return_if_fail (tx_dial != NULL);
515   g_return_if_fail (GTK_IS_TX_DIAL (tx_dial));
516
517   new_value = tx_dial->adjustment->value;
518   
519   if (new_value < tx_dial->adjustment->lower)
520     new_value = tx_dial->adjustment->lower;
521
522   if (new_value > tx_dial->adjustment->upper)
523     new_value = tx_dial->adjustment->upper;
524
525   if (new_value != tx_dial->adjustment->value)
526     {
527       tx_dial->adjustment->value = new_value;
528       gtk_signal_emit_by_name (GTK_OBJECT (tx_dial->adjustment), "value_changed");
529     }
530     
531      calc_image(new_value, image);
532      if (image!=tx_dial->old_image)
533      {
534                  tx_dial->old_image=image;
535                  gtk_tx_dial_draw(tx_dial, GTK_WIDGET(tx_dial));
536      }
537
538 //  gtk_widget_draw (GTK_WIDGET(tx_dial), NULL);
539 }
540
541 static void
542 gtk_tx_dial_adjustment_changed (GtkAdjustment *adjustment,
543                               gpointer       data)
544 {
545   GtkTxDial *tx_dial;
546
547   g_return_if_fail (adjustment != NULL);
548   g_return_if_fail (data != NULL);
549
550   tx_dial = GTK_TX_DIAL (data);
551
552   if ((tx_dial->old_value != adjustment->value) ||
553       (tx_dial->old_lower != adjustment->lower) ||
554       (tx_dial->old_upper != adjustment->upper))
555     {
556       tx_dial->old_value = adjustment->value;
557       tx_dial->old_lower = adjustment->lower;
558       tx_dial->old_upper = adjustment->upper;
559       tx_dial->old_range = adjustment->upper-adjustment->lower;
560       
561 //      calc_image(adjustment->value, tx_dial->old_image)
562 //               gtk_tx_dial_draw(tx_dial, GTK_WIDET(tx_dial));
563       gtk_tx_dial_update (tx_dial);
564       
565     }
566 }
567
568 static void
569 gtk_tx_dial_adjustment_value_changed (GtkAdjustment *adjustment,
570                                     gpointer       data)
571 {
572   GtkTxDial *tx_dial;
573
574   g_return_if_fail (adjustment != NULL);
575   g_return_if_fail (data != NULL);
576
577   tx_dial = GTK_TX_DIAL (data);
578
579   if (tx_dial->old_value != adjustment->value)
580     {
581       gtk_tx_dial_update (tx_dial);
582
583       tx_dial->old_value = adjustment->value;
584     }
585 }
586 /* example-end */
587 #endif