1 /* nekobee DSSI software synthesizer GUI
3 * Most of this code comes from gAlan 0.2.0, copyright (C) 1999
4 * Tony Garnock-Jones, with modifications by Sean Bolton,
5 * copyright (c) 2004. (gtkdial.c rolls over in its grave.)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be
13 * useful, but WITHOUT ANY WARRANTY; without even the implied
14 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 #include <gtk/gtkmain.h>
30 #include <gtk/gtksignal.h>
35 # define M_PI 3.14159265358979323846 /* pi */
38 #define SCROLL_DELAY_LENGTH 300
42 #define STATE_PRESSED 1
43 #define STATE_DRAGGING 2
45 static void gtk_knob_class_init(GtkKnobClass
*klass
);
46 static void gtk_knob_init(GtkKnob
*knob
);
47 static void gtk_knob_destroy(GtkObject
*object
);
48 static void gtk_knob_realize(GtkWidget
*widget
);
49 static void gtk_knob_size_request(GtkWidget
*widget
, GtkRequisition
*requisition
);
50 static void gtk_knob_size_allocate(GtkWidget
*widget
, GtkAllocation
*allocation
);
51 static gint
gtk_knob_expose(GtkWidget
*widget
, GdkEventExpose
*event
);
52 static gint
gtk_knob_button_press(GtkWidget
*widget
, GdkEventButton
*event
);
53 static gint
gtk_knob_button_release(GtkWidget
*widget
, GdkEventButton
*event
);
54 static gint
gtk_knob_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
);
55 static gint
gtk_knob_timer(GtkKnob
*knob
);
57 static void gtk_knob_update_mouse_update(GtkKnob
*knob
);
58 static void gtk_knob_update_mouse(GtkKnob
*knob
, gint x
, gint y
, gboolean absolute
);
59 static void gtk_knob_update(GtkKnob
*knob
);
60 static void gtk_knob_adjustment_changed(GtkAdjustment
*adjustment
, gpointer data
);
61 static void gtk_knob_adjustment_value_changed(GtkAdjustment
*adjustment
, gpointer data
);
67 static GtkWidgetClass
*parent_class
= NULL
;
69 guint
gtk_knob_get_type(void) {
70 static guint knob_type
= 0;
73 GtkTypeInfo knob_info
= {
76 sizeof (GtkKnobClass
),
77 (GtkClassInitFunc
) gtk_knob_class_init
,
78 (GtkObjectInitFunc
) gtk_knob_init
,
83 knob_type
= gtk_type_unique(gtk_widget_get_type(), &knob_info
);
89 static void gtk_knob_class_init (GtkKnobClass
*class) {
90 GtkObjectClass
*object_class
;
91 GtkWidgetClass
*widget_class
;
93 object_class
= (GtkObjectClass
*) class;
94 widget_class
= (GtkWidgetClass
*) class;
96 parent_class
= gtk_type_class(gtk_widget_get_type());
98 object_class
->destroy
= gtk_knob_destroy
;
100 widget_class
->realize
= gtk_knob_realize
;
101 widget_class
->expose_event
= gtk_knob_expose
;
102 widget_class
->size_request
= gtk_knob_size_request
;
103 widget_class
->size_allocate
= gtk_knob_size_allocate
;
104 widget_class
->button_press_event
= gtk_knob_button_press
;
105 widget_class
->button_release_event
= gtk_knob_button_release
;
106 widget_class
->motion_notify_event
= gtk_knob_motion_notify
;
109 static void gtk_knob_init (GtkKnob
*knob
) {
110 knob
->policy
= GTK_UPDATE_CONTINUOUS
;
111 knob
->state
= STATE_IDLE
;
112 knob
->saved_x
= knob
->saved_y
= 0;
115 knob
->old_value
= 0.0;
116 knob
->old_lower
= 0.0;
117 knob
->old_upper
= 0.0;
118 knob
->adjustment
= NULL
;
121 GtkWidget
*gtk_knob_new(GtkAdjustment
*adjustment
) {
124 knob
= gtk_type_new(gtk_knob_get_type());
127 adjustment
= (GtkAdjustment
*) gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
129 gtk_knob_set_adjustment(knob
, adjustment
);
131 return GTK_WIDGET(knob
);
134 static void gtk_knob_destroy(GtkObject
*object
) {
137 g_return_if_fail(object
!= NULL
);
138 g_return_if_fail(GTK_IS_KNOB(object
));
140 knob
= GTK_KNOB(object
);
142 if (knob
->adjustment
) {
143 gtk_object_unref(GTK_OBJECT(knob
->adjustment
));
144 knob
->adjustment
= NULL
;
148 gdk_pixbuf_unref(knob
->pixbuf
);
152 if (GTK_OBJECT_CLASS(parent_class
)->destroy
)
153 (*GTK_OBJECT_CLASS(parent_class
)->destroy
)(object
);
156 GtkAdjustment
* gtk_knob_get_adjustment(GtkKnob
*knob
) {
157 g_return_val_if_fail(knob
!= NULL
, NULL
);
158 g_return_val_if_fail(GTK_IS_KNOB(knob
), NULL
);
160 return knob
->adjustment
;
163 void gtk_knob_set_update_policy(GtkKnob
*knob
, GtkUpdateType policy
) {
164 g_return_if_fail (knob
!= NULL
);
165 g_return_if_fail (GTK_IS_KNOB (knob
));
167 knob
->policy
= policy
;
170 void gtk_knob_set_adjustment(GtkKnob
*knob
, GtkAdjustment
*adjustment
) {
171 g_return_if_fail (knob
!= NULL
);
172 g_return_if_fail (GTK_IS_KNOB (knob
));
174 if (knob
->adjustment
) {
175 gtk_signal_disconnect_by_data(GTK_OBJECT(knob
->adjustment
), (gpointer
)knob
);
176 gtk_object_unref(GTK_OBJECT(knob
->adjustment
));
179 knob
->adjustment
= adjustment
;
180 gtk_object_ref(GTK_OBJECT(knob
->adjustment
));
181 gtk_object_sink(GTK_OBJECT( knob
->adjustment
) );
183 gtk_signal_connect(GTK_OBJECT(adjustment
), "changed",
184 GTK_SIGNAL_FUNC(gtk_knob_adjustment_changed
), (gpointer
) knob
);
185 gtk_signal_connect(GTK_OBJECT(adjustment
), "value_changed",
186 GTK_SIGNAL_FUNC(gtk_knob_adjustment_value_changed
), (gpointer
) knob
);
188 knob
->old_value
= adjustment
->value
;
189 knob
->old_lower
= adjustment
->lower
;
190 knob
->old_upper
= adjustment
->upper
;
192 gtk_knob_update(knob
);
195 static void gtk_knob_realize(GtkWidget
*widget
) {
197 GdkWindowAttr attributes
;
198 gint attributes_mask
;
200 g_return_if_fail(widget
!= NULL
);
201 g_return_if_fail(GTK_IS_KNOB(widget
));
203 GTK_WIDGET_SET_FLAGS(widget
, GTK_REALIZED
);
204 knob
= GTK_KNOB(widget
);
206 attributes
.x
= widget
->allocation
.x
;
207 attributes
.y
= widget
->allocation
.y
;
208 attributes
.width
= widget
->allocation
.width
;
209 attributes
.height
= widget
->allocation
.height
;
210 attributes
.wclass
= GDK_INPUT_OUTPUT
;
211 attributes
.window_type
= GDK_WINDOW_CHILD
;
212 attributes
.event_mask
=
213 gtk_widget_get_events (widget
) |
214 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
|
215 GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
|
216 GDK_POINTER_MOTION_HINT_MASK
;
217 attributes
.visual
= gtk_widget_get_visual(widget
);
218 attributes
.colormap
= gtk_widget_get_colormap(widget
);
220 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
;
221 widget
->window
= gdk_window_new(widget
->parent
->window
, &attributes
, attributes_mask
);
223 widget
->style
= gtk_style_attach(widget
->parent
->style
, widget
->window
);
225 gdk_window_set_user_data(widget
->window
, widget
);
227 switch (knob
->knobtype
) {
229 knob
->pixbuf
= gdk_pixbuf_new_from_file(INSTALL_DIR
"/tuning.png",&gerror
);
233 knob
->pixbuf
= gdk_pixbuf_new_from_file(INSTALL_DIR
"/newknob.png",&gerror
);
236 gtk_style_set_background(widget
->style
, widget
->window
, GTK_STATE_NORMAL
);
238 // this is all it takes to make the widget take on the parent's background image
239 gdk_window_set_back_pixmap(widget
->window
, widget
->parent
->style
->bg_pixmap
[GTK_STATE_NORMAL
],GDK_PARENT_RELATIVE
);
243 static void gtk_knob_size_request (GtkWidget
*widget
, GtkRequisition
*requisition
) {
244 requisition
->width
= KNOB_SIZE
;
245 requisition
->height
= KNOB_SIZE
;
248 static void gtk_knob_size_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
) {
251 g_return_if_fail(widget
!= NULL
);
252 g_return_if_fail(GTK_IS_KNOB(widget
));
253 g_return_if_fail(allocation
!= NULL
);
255 widget
->allocation
= *allocation
;
256 knob
= GTK_KNOB(widget
);
258 if (GTK_WIDGET_REALIZED(widget
)) {
259 gdk_window_move_resize(widget
->window
,
260 allocation
->x
, allocation
->y
,
261 allocation
->width
, allocation
->height
);
265 static gint
gtk_knob_expose(GtkWidget
*widget
, GdkEventExpose
*event
) {
267 gfloat dx
, dy
, throw;
269 g_return_val_if_fail(widget
!= NULL
, FALSE
);
270 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
271 g_return_val_if_fail(event
!= NULL
, FALSE
);
273 if (event
->count
> 0)
276 knob
= GTK_KNOB(widget
);
278 // FIXME - somewhere in here, we need to read this from the knob size
280 // basically we need to work out if the step size is integer
281 // if it is, centre the knob about the vertical
283 dx
= knob
->adjustment
->value
- knob
->adjustment
->lower
; // value, from 0
284 dy
= knob
->adjustment
->upper
- knob
->adjustment
->lower
; // range
287 if (knob
->adjustment
->step_increment
!= 1.0f
) {
288 dx
=(int)(36*dx
/dy
)*50;
291 dx
=(int)(36*dx
/throw+(17-throw))*50;
296 gdk_draw_pixbuf(widget
->window
, NULL
, knob
->pixbuf
,
297 0, dx
, 0, 0, 45, KNOB_SIZE
,GDK_RGB_DITHER_NONE
,0,0);
303 static gint
gtk_knob_button_press(GtkWidget
*widget
, GdkEventButton
*event
) {
306 g_return_val_if_fail(widget
!= NULL
, FALSE
);
307 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
308 g_return_val_if_fail(event
!= NULL
, FALSE
);
310 knob
= GTK_KNOB(widget
);
312 switch (knob
->state
) {
314 switch (event
->button
) {
317 gtk_grab_add(widget
);
318 knob
->state
= STATE_PRESSED
;
319 knob
->saved_x
= event
->x
;
320 knob
->saved_y
= event
->y
;
335 static gint
gtk_knob_button_release(GtkWidget
*widget
, GdkEventButton
*event
) {
338 g_return_val_if_fail(widget
!= NULL
, FALSE
);
339 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
340 g_return_val_if_fail(event
!= NULL
, FALSE
);
342 knob
= GTK_KNOB(widget
);
344 switch (knob
->state
) {
346 gtk_grab_remove(widget
);
347 knob
->state
= STATE_IDLE
;
349 switch (event
->button
) {
351 knob
->adjustment
->value
-= knob
->adjustment
->page_increment
;
352 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
356 knob
->adjustment
->value
+= knob
->adjustment
->page_increment
;
357 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
366 gtk_grab_remove(widget
);
367 knob
->state
= STATE_IDLE
;
369 if (knob
->policy
!= GTK_UPDATE_CONTINUOUS
&& knob
->old_value
!= knob
->adjustment
->value
)
370 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
381 static gint
gtk_knob_motion_notify(GtkWidget
*widget
, GdkEventMotion
*event
) {
383 GdkModifierType mods
;
386 g_return_val_if_fail(widget
!= NULL
, FALSE
);
387 g_return_val_if_fail(GTK_IS_KNOB(widget
), FALSE
);
388 g_return_val_if_fail(event
!= NULL
, FALSE
);
390 knob
= GTK_KNOB(widget
);
395 if (event
->is_hint
|| (event
->window
!= widget
->window
))
396 gdk_window_get_pointer(widget
->window
, &x
, &y
, &mods
);
398 switch (knob
->state
) {
400 knob
->state
= STATE_DRAGGING
;
404 if (mods
& GDK_BUTTON1_MASK
) {
405 gtk_knob_update_mouse(knob
, x
, y
, TRUE
);
407 } else if (mods
& GDK_BUTTON3_MASK
) {
408 gtk_knob_update_mouse(knob
, x
, y
, FALSE
);
420 static gint
gtk_knob_timer(GtkKnob
*knob
) {
421 g_return_val_if_fail(knob
!= NULL
, FALSE
);
422 g_return_val_if_fail(GTK_IS_KNOB(knob
), FALSE
);
424 if (knob
->policy
== GTK_UPDATE_DELAYED
)
425 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
427 return FALSE
; /* don't keep running this timer */
430 static void gtk_knob_update_mouse_update(GtkKnob
*knob
) {
431 if (knob
->policy
== GTK_UPDATE_CONTINUOUS
)
432 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
434 gtk_widget_draw(GTK_WIDGET(knob
), NULL
);
436 if (knob
->policy
== GTK_UPDATE_DELAYED
) {
438 gtk_timeout_remove(knob
->timer
);
440 knob
->timer
= gtk_timeout_add (SCROLL_DELAY_LENGTH
, (GtkFunction
) gtk_knob_timer
,
446 static void gtk_knob_update_mouse(GtkKnob
*knob
, gint x
, gint y
,
449 gfloat old_value
, new_value
, dv
, dh
;
452 g_return_if_fail(knob
!= NULL
);
453 g_return_if_fail(GTK_IS_KNOB(knob
));
455 old_value
= knob
->adjustment
->value
;
457 angle
= atan2(-y
+ (KNOB_SIZE
>>1), x
- (KNOB_SIZE
>>1));
465 new_value
= -(2.0/3.0) * (angle
- 1.25); /* map [1.25pi, -0.25pi] onto [0, 1] */
466 new_value
*= knob
->adjustment
->upper
- knob
->adjustment
->lower
;
467 new_value
+= knob
->adjustment
->lower
;
471 dv
= knob
->saved_y
- y
; /* inverted cartesian graphics coordinate system */
472 dh
= x
- knob
->saved_x
;
476 if (x
>= 0 && x
<= KNOB_SIZE
)
477 dh
= 0; /* dead zone */
483 new_value
= knob
->adjustment
->value
+
484 dv
* knob
->adjustment
->step_increment
+
485 dh
* (knob
->adjustment
->upper
-
486 knob
->adjustment
->lower
) / 200.0f
;
489 new_value
= MAX(MIN(new_value
, knob
->adjustment
->upper
),
490 knob
->adjustment
->lower
);
492 knob
->adjustment
->value
= new_value
;
494 if (knob
->adjustment
->value
!= old_value
)
495 gtk_knob_update_mouse_update(knob
);
498 static void gtk_knob_update(GtkKnob
*knob
) {
501 g_return_if_fail(knob
!= NULL
);
502 g_return_if_fail(GTK_IS_KNOB (knob
));
506 new_value
= knob
->adjustment
->value
;
507 if (knob
->adjustment
->step_increment
== 1) new_value
= (int)(knob
->adjustment
->value
+0.5);
509 if (new_value
< knob
->adjustment
->lower
)
510 new_value
= knob
->adjustment
->lower
;
512 if (new_value
> knob
->adjustment
->upper
)
513 new_value
= knob
->adjustment
->upper
;
515 if (new_value
!= knob
->adjustment
->value
) {
516 knob
->adjustment
->value
= new_value
;
517 gtk_signal_emit_by_name(GTK_OBJECT(knob
->adjustment
), "value_changed");
520 gtk_widget_draw(GTK_WIDGET(knob
), NULL
);
523 static void gtk_knob_adjustment_changed(GtkAdjustment
*adjustment
, gpointer data
) {
526 g_return_if_fail(adjustment
!= NULL
);
527 g_return_if_fail(data
!= NULL
);
529 knob
= GTK_KNOB(data
);
531 if ((knob
->old_value
!= adjustment
->value
) ||
532 (knob
->old_lower
!= adjustment
->lower
) ||
533 (knob
->old_upper
!= adjustment
->upper
)) {
534 gtk_knob_update (knob
);
536 knob
->old_value
= adjustment
->value
;
537 knob
->old_lower
= adjustment
->lower
;
538 knob
->old_upper
= adjustment
->upper
;
542 static void gtk_knob_adjustment_value_changed (GtkAdjustment
*adjustment
, gpointer data
) {
545 g_return_if_fail(adjustment
!= NULL
);
546 g_return_if_fail(data
!= NULL
);
548 knob
= GTK_KNOB(data
);
550 if (knob
->old_value
!= adjustment
->value
) {
551 gtk_knob_update (knob
);
553 knob
->old_value
= adjustment
->value
;