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
21 #include <gtk/gtkmain.h>
22 #include <gtk/gtksignal.h>
24 #include <gdk-pixbuf/gdk-pixbuf.h>
29 # define M_PI 3.14159265358979323846 /* pi */
32 #define SCROLL_DELAY_LENGTH 300
36 #define STATE_PRESSED 1
37 #define STATE_DRAGGING 2
40 /* Forward declarations */
42 static void gtk_knob_class_init(GtkKnobClass
*klass
);
43 static void gtk_knob_init(GtkKnob
*knob
);
44 static void gtk_knob_destroy(GtkObject
*object
);
45 static void gtk_knob_realize(GtkWidget
*widget
);
46 static void gtk_knob_size_request(GtkWidget
*widget
, GtkRequisition
*requisition
);
47 static void gtk_knob_size_allocate(GtkWidget
*widget
, GtkAllocation
*allocation
);
48 static gint
gtk_knob_expose(GtkWidget
*widget
, GdkEventExpose
*event
);
49 static gint
gtk_knob_button_press(GtkWidget
*widget
, GdkEventButton
*event
);
50 static gint
gtk_knob_button_release(GtkWidget
*widget
, GdkEventButton
*event
);
51 static gint
gtk_knob_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
);
52 static gint
gtk_knob_timer(GtkKnob
*knob
);
54 static void gtk_knob_update_mouse_update(GtkKnob
*knob
);
55 static void gtk_knob_update_mouse(GtkKnob
*knob
, gint x
, gint y
);
56 static void gtk_knob_update_mouse_abs(GtkKnob
*knob
, gint x
, gint y
);
57 static void gtk_knob_update(GtkKnob
*knob
);
58 static void gtk_knob_adjustment_changed(GtkAdjustment
*adjustment
, gpointer data
);
59 static void gtk_knob_adjustment_value_changed(GtkAdjustment
*adjustment
, gpointer data
);
63 static GtkWidgetClass
*parent_class
= NULL
;
64 static GList
*animation
= NULL
;
67 // Old gif loading code... will be removed soon...
69 static GList
*get_anim_list( char *name
) {
73 GdkPixbufAnimation
*animation
;
74 GdkPixbufAnimationIter
*iter
;
77 animation
= gdk_pixbuf_animation_new_from_file( name
, &err
);
78 g_get_current_time( &time
);
79 iter
= gdk_pixbuf_animation_get_iter( animation
, &time
);
82 GdkPixbuf
*pixbuf
= gdk_pixbuf_animation_iter_get_pixbuf(iter
);
83 int delay
= gdk_pixbuf_animation_iter_get_delay_time( iter
);
85 retval
= g_list_append( retval
, gdk_pixbuf_copy( pixbuf
) );
87 if( gdk_pixbuf_animation_iter_on_currently_loading_frame( iter
) )
92 if( g_list_length( retval
) > 300 )
95 g_time_val_add( &time
, delay
*1000 );
96 gdk_pixbuf_animation_iter_advance( iter
, &time
);
102 static GList
*get_anim_list( char *name
) {
105 GdkPixbuf
*animation
;
106 GList
*retval
= NULL
;
109 animation
= gdk_pixbuf_new_from_file( name
, &err
);
111 w
= gdk_pixbuf_get_width( animation
);
113 for(x
=0; x
<w
; x
+=KNOB_SIZE
) {
114 GdkPixbuf
*pixbuf
= gdk_pixbuf_new_subpixbuf( animation
, x
, 0, KNOB_SIZE
, KNOB_SIZE
);
115 retval
= g_list_append( retval
, pixbuf
);
119 // Create empty GdkPixBuf...
124 void free_anim_list( GList
*anim_list
)
126 // g_list_foreach( anim_list, gdk_pixbuf_unref );
130 guint
gtk_knob_get_type(void) {
131 static guint knob_type
= 0;
134 GtkTypeInfo knob_info
= {
137 sizeof (GtkKnobClass
),
138 (GtkClassInitFunc
) gtk_knob_class_init
,
139 (GtkObjectInitFunc
) gtk_knob_init
,
144 knob_type
= gtk_type_unique(gtk_widget_get_type(), &knob_info
);
150 static void gtk_knob_class_init (GtkKnobClass
*class) {
151 GtkObjectClass
*object_class
;
152 GtkWidgetClass
*widget_class
;
154 //animation = get_anim_list( PIXMAPDIRIFY("knob.gif") );
155 animation
= get_anim_list( PIXMAPDIRIFY("new-knob02.png") );
156 object_class
= (GtkObjectClass
*) class;
157 widget_class
= (GtkWidgetClass
*) class;
159 parent_class
= gtk_type_class(gtk_widget_get_type());
161 object_class
->destroy
= gtk_knob_destroy
;
163 widget_class
->realize
= gtk_knob_realize
;
164 widget_class
->expose_event
= gtk_knob_expose
;
165 widget_class
->size_request
= gtk_knob_size_request
;
166 widget_class
->size_allocate
= gtk_knob_size_allocate
;
167 widget_class
->button_press_event
= gtk_knob_button_press
;
168 widget_class
->button_release_event
= gtk_knob_button_release
;
169 widget_class
->motion_notify_event
= gtk_knob_motion_notify
;
172 static void gtk_knob_init (GtkKnob
*knob
) {
173 knob
->policy
= GTK_UPDATE_CONTINUOUS
;
174 knob
->state
= STATE_IDLE
;
175 knob
->saved_x
= knob
->saved_y
= 0;
178 knob
->anim_list
= animation
;
179 knob
->old_value
= 0.0;
180 knob
->old_lower
= 0.0;
181 knob
->old_upper
= 0.0;
182 knob
->adjustment
= NULL
;
189 GtkWidget
*gtk_knob_new(GtkAdjustment
*adjustment
) {
192 knob
= gtk_type_new(gtk_knob_get_type());
195 adjustment
= (GtkAdjustment
*) gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
197 gtk_knob_set_adjustment(knob
, adjustment
);
199 return GTK_WIDGET(knob
);
202 static void gtk_knob_destroy(GtkObject
*object
) {
205 g_return_if_fail(object
!= NULL
);
206 g_return_if_fail(GTK_IS_KNOB(object
));
208 knob
= GTK_KNOB(object
);
210 if (knob
->adjustment
) {
211 gtk_object_unref(GTK_OBJECT(knob
->adjustment
));
212 knob
->adjustment
= NULL
;
216 gdk_pixbuf_unref(knob
->pixbuf
);
220 if (GTK_OBJECT_CLASS(parent_class
)->destroy
)
221 (*GTK_OBJECT_CLASS(parent_class
)->destroy
)(object
);
224 GtkAdjustment
* gtk_knob_get_adjustment(GtkKnob
*knob
) {
225 g_return_val_if_fail(knob
!= NULL
, NULL
);
226 g_return_val_if_fail(GTK_IS_KNOB(knob
), NULL
);
228 return knob
->adjustment
;
231 void gtk_knob_set_update_policy(GtkKnob
*knob
, GtkUpdateType policy
) {
232 g_return_if_fail (knob
!= NULL
);
233 g_return_if_fail (GTK_IS_KNOB (knob
));
235 knob
->policy
= policy
;
238 void gtk_knob_set_adjustment(GtkKnob
*knob
, GtkAdjustment
*adjustment
) {
239 g_return_if_fail (knob
!= NULL
);
240 g_return_if_fail (GTK_IS_KNOB (knob
));
242 if (knob
->adjustment
) {
243 gtk_signal_disconnect_by_data(GTK_OBJECT(knob
->adjustment
), (gpointer
)knob
);
244 gtk_object_unref(GTK_OBJECT(knob
->adjustment
));
247 knob
->adjustment
= adjustment
;
248 gtk_object_ref(GTK_OBJECT(knob
->adjustment
));
249 gtk_object_sink(GTK_OBJECT( knob
->adjustment
) );
251 gtk_signal_connect(GTK_OBJECT(adjustment
), "changed",
252 GTK_SIGNAL_FUNC(gtk_knob_adjustment_changed
), (gpointer
) knob
);
253 gtk_signal_connect(GTK_OBJECT(adjustment
), "value_changed",
254 GTK_SIGNAL_FUNC(gtk_knob_adjustment_value_changed
), (gpointer
) knob
);
256 knob
->old_value
= adjustment
->value
;
257 knob
->old_lower
= adjustment
->lower
;
258 knob
->old_upper
= adjustment
->upper
;
260 gtk_knob_update(knob
);
263 static void gtk_knob_realize(GtkWidget
*widget
) {
265 GdkWindowAttr attributes
;
266 gint attributes_mask
;
268 g_return_if_fail(widget
!= NULL
);
269 g_return_if_fail(GTK_IS_KNOB(widget
));
271 GTK_WIDGET_SET_FLAGS(widget
, GTK_REALIZED
);
272 knob
= GTK_KNOB(widget
);
274 attributes
.x
= widget
->allocation
.x
;
275 attributes
.y
= widget
->allocation
.y
;
276 attributes
.width
= widget
->allocation
.width
;
277 attributes
.height
= widget
->allocation
.height
;
278 attributes
.wclass
= GDK_INPUT_OUTPUT
;
279 attributes
.window_type
= GDK_WINDOW_CHILD
;
280 attributes
.event_mask
=
281 gtk_widget_get_events (widget
) |
282 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
283 GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
|
284 GDK_POINTER_MOTION_HINT_MASK
;
285 attributes
.visual
= gtk_widget_get_visual(widget
);
286 attributes
.colormap
= gtk_widget_get_colormap(widget
);
288 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
;
289 widget
->window
= gdk_window_new(widget
->parent
->window
, &attributes
, attributes_mask
);
291 widget
->style
= gtk_style_attach(widget
->parent
->style
, widget
->window
);
293 gdk_window_set_user_data(widget
->window
, widget
);
296 gtk_style_set_background(widget
->style
, widget
->window
, GTK_STATE_NORMAL
);
299 static void gtk_knob_size_request (GtkWidget
*widget
, GtkRequisition
*requisition
) {
300 requisition
->width
= KNOB_SIZE
;
301 requisition
->height
= KNOB_SIZE
;
304 static void gtk_knob_size_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
) {
307 g_return_if_fail(widget
!= NULL
);
308 g_return_if_fail(GTK_IS_KNOB(widget
));
309 g_return_if_fail(allocation
!= NULL
);
311 widget
->allocation
= *allocation
;
312 knob
= GTK_KNOB(widget
);
314 if (GTK_WIDGET_REALIZED(widget
)) {
315 gdk_window_move_resize(widget
->window
,
316 allocation
->x
, allocation
->y
,
317 allocation
->width
, allocation
->height
);
321 static gint
gtk_knob_expose(GtkWidget
*widget
, GdkEventExpose
*event
) {
326 g_return_val_if_fail(widget
!= NULL
, FALSE
);
327 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
328 g_return_val_if_fail(event
!= NULL
, FALSE
);
330 if (event
->count
> 0)
333 knob
= GTK_KNOB(widget
);
335 gdk_window_clear_area(widget
->window
, 0, 0, widget
->allocation
.width
, widget
->allocation
.height
);
337 dx
= knob
->adjustment
->value
- knob
->adjustment
->lower
;
338 dy
= knob
->adjustment
->upper
- knob
->adjustment
->lower
;
339 framelist
= knob
->anim_list
;
344 dx
= MIN(MAX(dx
/ dy
, 0), 1);
345 //dx = (1-dx) * (g_list_length( framelist )-0.5) * 0.75 + 0.125 * g_list_length( framelist );
346 dx
= (dx
) * (g_list_length( framelist
) - 1 );
348 pixbuf
= g_list_nth_data( framelist
, (int) dx
);
350 gdk_pixbuf_render_to_drawable_alpha( pixbuf
, widget
->window
,
351 0, 0, 0, 0, gdk_pixbuf_get_width( pixbuf
), gdk_pixbuf_get_height( pixbuf
), GDK_PIXBUF_ALPHA_FULL
, 0, 0,0,0 );
360 static gint
gtk_knob_button_press(GtkWidget
*widget
, GdkEventButton
*event
) {
363 g_return_val_if_fail(widget
!= NULL
, FALSE
);
364 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
365 g_return_val_if_fail(event
!= NULL
, FALSE
);
367 knob
= GTK_KNOB(widget
);
369 switch (knob
->state
) {
371 switch (event
->button
) {
374 gtk_knob_update_mouse_abs(knob
, event
->x
, event
->y
);
380 gtk_grab_add(widget
);
381 knob
->state
= STATE_PRESSED
;
382 knob
->saved_x
= event
->x
;
383 knob
->saved_y
= event
->y
;
398 static gint
gtk_knob_button_release(GtkWidget
*widget
, GdkEventButton
*event
) {
401 g_return_val_if_fail(widget
!= NULL
, FALSE
);
402 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
403 g_return_val_if_fail(event
!= NULL
, FALSE
);
405 knob
= GTK_KNOB(widget
);
407 switch (knob
->state
) {
409 gtk_grab_remove(widget
);
410 knob
->state
= STATE_IDLE
;
412 switch (event
->button
) {
414 knob
->adjustment
->value
-= knob
->adjustment
->page_increment
;
415 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
419 knob
->adjustment
->value
+= knob
->adjustment
->page_increment
;
420 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
429 gtk_grab_remove(widget
);
430 knob
->state
= STATE_IDLE
;
432 if (knob
->policy
!= GTK_UPDATE_CONTINUOUS
&& knob
->old_value
!= knob
->adjustment
->value
)
433 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
444 static gint
gtk_knob_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
) {
446 GdkModifierType mods
;
449 g_return_val_if_fail(widget
!= NULL
, FALSE
);
450 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
451 g_return_val_if_fail(event
!= NULL
, FALSE
);
453 knob
= GTK_KNOB(widget
);
458 if (event
->is_hint
|| (event
->window
!= widget
->window
))
459 gdk_window_get_pointer(widget
->window
, &x
, &y
, &mods
);
461 switch (knob
->state
) {
463 knob
->state
= STATE_DRAGGING
;
467 if (mods
& GDK_BUTTON1_MASK
) {
468 gtk_knob_update_mouse(knob
, x
, y
);
470 } else if (mods
& GDK_BUTTON3_MASK
) {
471 gtk_knob_update_mouse_abs(knob
, x
, y
);
483 static gint
gtk_knob_timer(GtkKnob
*knob
) {
484 g_return_val_if_fail(knob
!= NULL
, FALSE
);
485 g_return_val_if_fail(GTK_IS_KNOB(knob
), FALSE
);
487 if (knob
->policy
== GTK_UPDATE_DELAYED
)
488 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
490 return FALSE
; /* don't keep running this timer */
493 static void gtk_knob_update_mouse_update(GtkKnob
*knob
) {
494 if (knob
->policy
== GTK_UPDATE_CONTINUOUS
)
495 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
497 gtk_widget_draw(GTK_WIDGET(knob
), NULL
);
499 if (knob
->policy
== GTK_UPDATE_DELAYED
) {
501 gtk_timeout_remove(knob
->timer
);
503 knob
->timer
= gtk_timeout_add (SCROLL_DELAY_LENGTH
, (GtkFunction
) gtk_knob_timer
,
509 static void gtk_knob_update_mouse(GtkKnob
*knob
, gint x
, gint y
) {
513 g_return_if_fail(knob
!= NULL
);
514 g_return_if_fail(GTK_IS_KNOB(knob
));
516 old_value
= knob
->adjustment
->value
;
518 dv
= (knob
->saved_y
- y
) * knob
->adjustment
->step_increment
;
522 knob
->adjustment
->value
+= dv
;
524 if (knob
->adjustment
->value
!= old_value
)
525 gtk_knob_update_mouse_update(knob
);
528 static void gtk_knob_update_mouse_abs(GtkKnob
*knob
, gint x
, gint y
) {
532 g_return_if_fail(knob
!= NULL
);
533 g_return_if_fail(GTK_IS_KNOB(knob
));
535 old_value
= knob
->adjustment
->value
;
539 y
= -y
; /* inverted cartesian graphics coordinate system */
541 angle
= atan2(y
, x
) / M_PI
;
545 angle
= -(2.0/3.0) * (angle
- 1.25); /* map [1.25pi, -0.25pi] onto [0, 1] */
546 angle
*= knob
->adjustment
->upper
- knob
->adjustment
->lower
;
547 angle
+= knob
->adjustment
->lower
;
549 knob
->adjustment
->value
= angle
;
551 if (knob
->adjustment
->value
!= old_value
)
552 gtk_knob_update_mouse_update(knob
);
555 static void gtk_knob_update(GtkKnob
*knob
) {
558 g_return_if_fail(knob
!= NULL
);
559 g_return_if_fail(GTK_IS_KNOB (knob
));
561 new_value
= knob
->adjustment
->value
;
563 if (new_value
< knob
->adjustment
->lower
)
564 new_value
= knob
->adjustment
->lower
;
566 if (new_value
> knob
->adjustment
->upper
)
567 new_value
= knob
->adjustment
->upper
;
569 if (new_value
!= knob
->adjustment
->value
) {
570 knob
->adjustment
->value
= new_value
;
571 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
574 gtk_widget_draw(GTK_WIDGET(knob
), NULL
);
577 static void gtk_knob_adjustment_changed(GtkAdjustment
*adjustment
, gpointer data
) {
580 g_return_if_fail(adjustment
!= NULL
);
581 g_return_if_fail(data
!= NULL
);
583 knob
= GTK_KNOB(data
);
585 if ((knob
->old_value
!= adjustment
->value
) ||
586 (knob
->old_lower
!= adjustment
->lower
) ||
587 (knob
->old_upper
!= adjustment
->upper
)) {
588 gtk_knob_update (knob
);
590 knob
->old_value
= adjustment
->value
;
591 knob
->old_lower
= adjustment
->lower
;
592 knob
->old_upper
= adjustment
->upper
;
596 static void gtk_knob_adjustment_value_changed (GtkAdjustment
*adjustment
, gpointer data
) {
599 g_return_if_fail(adjustment
!= NULL
);
600 g_return_if_fail(data
!= NULL
);
602 knob
= GTK_KNOB(data
);
604 if (knob
->old_value
!= adjustment
->value
) {
605 gtk_knob_update (knob
);
607 knob
->old_value
= adjustment
->value
;