2 terminatorX - realtime audio scratching software
3 Copyright (C) 1999-2014 Alexander König
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Description: Implements the dial widget - this widget is based on the
21 gtk_dial example from the gtk+ tutorial which is
22 Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
32 #include "tX_knobloader.h"
36 #define SCROLL_DELAY_LENGTH 300
37 #define TX_DIAL_DEFAULT_SIZE 100
39 /* Forward declarations */
41 static void gtk_tx_dial_class_init (GtkTxDialClass *klass);
42 static void gtk_tx_dial_init (GtkTxDial *tx_dial);
43 static void gtk_tx_dial_destroy (GtkWidget *widget);
44 static void gtk_tx_dial_realize (GtkWidget *widget);
46 static void gtk_tx_dial_get_preferred_width (GtkWidget *widget, gint *minimal_height, gint *natural_height);
47 static void gtk_tx_dial_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height);
48 static void gtk_tx_dial_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
49 static gboolean gtk_tx_dial_draw (GtkWidget *widget, cairo_t* cairo);
50 static gint gtk_tx_dial_button_press (GtkWidget *widget, GdkEventButton *event);
51 static gint gtk_tx_dial_button_release (GtkWidget *widget, GdkEventButton *event);
52 static gint gtk_tx_dial_motion_notify (GtkWidget *widget, GdkEventMotion *event);
53 static void gtk_tx_dial_update_mouse (GtkTxDial *tx_dial, gint x, gint y);
54 static void gtk_tx_dial_update (GtkTxDial *tx_dial);
55 static void gtk_tx_dial_adjustment_changed (GtkAdjustment *adjustment, gpointer data);
56 static void gtk_tx_dial_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data);
60 static GtkWidgetClass *parent_class = NULL;
62 #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;
64 GType gtk_tx_dial_get_type ()
66 static GType tx_dial_type = 0;
69 static const GTypeInfo tx_dial_info = {
70 sizeof (GtkTxDialClass),
73 (GClassInitFunc) gtk_tx_dial_class_init,
78 (GInstanceInitFunc) gtk_tx_dial_init,
81 tx_dial_type = g_type_register_static(GTK_TYPE_WIDGET, "GtkTxDial", &tx_dial_info, 0);
87 static void gtk_tx_dial_class_init (GtkTxDialClass *class)
89 GtkWidgetClass *widget_class;
91 widget_class = (GtkWidgetClass*) class;
93 parent_class = (GtkWidgetClass*) g_type_class_peek (gtk_widget_get_type ());
95 widget_class->destroy = gtk_tx_dial_destroy;
97 widget_class->realize = gtk_tx_dial_realize;
98 widget_class->draw = gtk_tx_dial_draw;
99 widget_class->get_preferred_height = gtk_tx_dial_get_preferred_height;
100 widget_class->get_preferred_width = gtk_tx_dial_get_preferred_width;
101 widget_class->size_allocate = gtk_tx_dial_size_allocate;
102 widget_class->button_press_event = gtk_tx_dial_button_press;
103 widget_class->button_release_event = gtk_tx_dial_button_release;
104 widget_class->motion_notify_event = gtk_tx_dial_motion_notify;
107 static void gtk_tx_dial_init (GtkTxDial *tx_dial)
111 tx_dial->old_value = 0.0;
112 tx_dial->old_lower = 0.0;
113 tx_dial->old_upper = 0.0;
114 tx_dial->old_range = 0.0; // Dangerous!
116 tx_dial->old_image = 0;
121 tx_dial->adjustment = NULL;
124 GtkWidget* gtk_tx_dial_new (GtkAdjustment *adjustment)
128 tx_dial = (GtkTxDial *) g_object_new(gtk_tx_dial_get_type(), NULL);
131 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0,
135 gtk_tx_dial_set_adjustment (tx_dial, adjustment);
136 g_object_ref (G_OBJECT (tx_dial->adjustment));
138 return GTK_WIDGET (tx_dial);
141 static void gtk_tx_dial_destroy (GtkWidget *widget)
145 g_return_if_fail (widget != NULL);
146 g_return_if_fail (GTK_IS_TX_DIAL (widget));
148 tx_dial = GTK_TX_DIAL (widget);
150 if (tx_dial->adjustment)
151 g_object_unref (G_OBJECT (tx_dial->adjustment));
153 if (GTK_WIDGET_CLASS (parent_class)->destroy)
154 (*GTK_WIDGET_CLASS (parent_class)->destroy) (widget);
157 GtkAdjustment* gtk_tx_dial_get_adjustment (GtkTxDial *tx_dial)
159 g_return_val_if_fail (tx_dial != NULL, NULL);
160 g_return_val_if_fail (GTK_IS_TX_DIAL (tx_dial), NULL);
162 return tx_dial->adjustment;
165 void gtk_tx_dial_set_adjustment (GtkTxDial *tx_dial, GtkAdjustment *adjustment)
167 g_return_if_fail (tx_dial != NULL);
168 g_return_if_fail (GTK_IS_TX_DIAL (tx_dial));
170 if (tx_dial->adjustment) {
171 g_signal_handlers_disconnect_matched(G_OBJECT(tx_dial->adjustment),
172 G_SIGNAL_MATCH_DATA, 0, 0, 0, 0,
174 g_object_unref (G_OBJECT (tx_dial->adjustment));
177 tx_dial->adjustment = adjustment;
178 g_object_ref (G_OBJECT (tx_dial->adjustment));
180 g_signal_connect (G_OBJECT (adjustment), "changed",
181 (GCallback) gtk_tx_dial_adjustment_changed,
183 g_signal_connect (G_OBJECT (adjustment), "value_changed",
184 (GCallback) gtk_tx_dial_adjustment_value_changed,
187 tx_dial->old_value = gtk_adjustment_get_value(adjustment);
188 tx_dial->old_lower = gtk_adjustment_get_lower(adjustment);
189 tx_dial->old_upper = gtk_adjustment_get_upper(adjustment);
190 tx_dial->old_range = gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_lower(adjustment);
192 calc_image(gtk_adjustment_get_value(adjustment),tx_dial->old_image);
194 gtk_tx_dial_update (tx_dial);
197 static void gtk_tx_dial_realize (GtkWidget *widget)
199 GdkWindowAttr attributes;
200 gint attributes_mask;
202 g_return_if_fail (widget != NULL);
203 g_return_if_fail (GTK_IS_TX_DIAL (widget));
205 gtk_widget_set_realized(widget, TRUE);
207 GtkAllocation allocation;
208 gtk_widget_get_allocation(widget, &allocation);
209 attributes.x = allocation.x;
210 attributes.y = allocation.y;
211 attributes.width = allocation.width;
212 attributes.height = allocation.height;
213 attributes.wclass = GDK_INPUT_OUTPUT;
214 attributes.window_type = GDK_WINDOW_CHILD;
215 attributes.event_mask = gtk_widget_get_events (widget) |
216 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
217 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
218 GDK_POINTER_MOTION_HINT_MASK;
219 attributes.visual = gtk_widget_get_visual (widget);
221 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
222 gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask));
224 gdk_window_set_user_data (gtk_widget_get_window(widget), widget);
225 gtk_style_context_set_background(gtk_widget_get_style_context(widget), gtk_widget_get_window(widget));
228 static void gtk_tx_dial_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width) {
229 *minimal_width = *natural_width = KNOB_SIZE;
231 static void gtk_tx_dial_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height) {
232 *minimal_height = *natural_height = KNOB_SIZE;
235 static void gtk_tx_dial_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
239 g_return_if_fail (widget != NULL);
240 g_return_if_fail (GTK_IS_TX_DIAL (widget));
241 g_return_if_fail (allocation != NULL);
243 gtk_widget_set_allocation(widget, allocation);
244 tx_dial = GTK_TX_DIAL (widget);
246 if (gtk_widget_get_realized (widget)) {
247 gdk_window_move_resize (gtk_widget_get_window(widget),
248 allocation->x, allocation->y,
249 allocation->width, allocation->height);
251 tx_dial->xofs=(allocation->width-KNOB_SIZE)/2;
252 tx_dial->yofs=(allocation->height-KNOB_SIZE)/2;
256 inline void gtk_tx_dial_do_draw (GtkTxDial *tx_dial, GtkWidget *widget, cairo_t *cr)
258 if (gtk_widget_is_drawable (widget)) {
259 // gdk_draw_pixbuf(gtk_widget_is_drawable (widget),
260 // //gtk_widget_get_stlye(widget)->bg_gc[GTK_WIDGET_STATE(widget)],
261 // NULL, //TODO: this needs to be ported to cairo!
262 // knob_pixmaps[tx_dial->old_image],
263 // 0, 0, tx_dial->xofs, tx_dial->yofs,
264 // KNOB_SIZE, KNOB_SIZE, GDK_RGB_DITHER_NORMAL, 0, 0);
266 gdk_cairo_set_source_pixbuf (cr, knob_pixmaps[tx_dial->old_image], 0, 0);
271 gboolean gtk_tx_dial_draw (GtkWidget *widget, cairo_t *cr)
275 g_return_val_if_fail (widget != NULL, FALSE);
276 g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
278 tx_dial = GTK_TX_DIAL (widget);
280 gtk_tx_dial_do_draw(tx_dial, widget, cr);
285 static gint gtk_tx_dial_button_press (GtkWidget *widget, GdkEventButton *event)
289 g_return_val_if_fail (widget != NULL, FALSE);
290 g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
291 g_return_val_if_fail (event != NULL, FALSE);
293 tx_dial = GTK_TX_DIAL (widget);
295 tx_dial->x = event->x;
296 tx_dial->y = event->y;
298 if (!tx_dial->button) {
299 gtk_grab_add (widget);
300 tx_dial->button = event->button;
306 static gint gtk_tx_dial_button_release (GtkWidget *widget, GdkEventButton *event)
310 g_return_val_if_fail (widget != NULL, FALSE);
311 g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
312 g_return_val_if_fail (event != NULL, FALSE);
314 tx_dial = GTK_TX_DIAL (widget);
316 if (tx_dial->button == event->button) {
317 gtk_grab_remove (widget);
324 static gint gtk_tx_dial_motion_notify (GtkWidget *widget, GdkEventMotion *event)
327 GdkModifierType mods;
330 g_return_val_if_fail (widget != NULL, FALSE);
331 g_return_val_if_fail (GTK_IS_TX_DIAL (widget), FALSE);
332 g_return_val_if_fail (event != NULL, FALSE);
334 tx_dial = GTK_TX_DIAL (widget);
336 if (tx_dial->button != 0) {
340 if (event->is_hint || (event->window != gtk_widget_get_window(widget)))
341 gdk_window_get_device_position(gtk_widget_get_window(widget), event->device, &x, &y, &mods);
343 switch (tx_dial->button) {
345 mask = GDK_BUTTON1_MASK;
348 mask = GDK_BUTTON2_MASK;
351 mask = GDK_BUTTON3_MASK;
358 gtk_tx_dial_update_mouse (tx_dial, x,y);
364 static void gtk_tx_dial_update_mouse (GtkTxDial *tx_dial, gint x, gint y)
367 gfloat old_value, new_value;
369 g_return_if_fail (tx_dial != NULL);
370 g_return_if_fail (GTK_IS_TX_DIAL (tx_dial));
380 old_value=gtk_adjustment_get_value(tx_dial->adjustment);
381 new_value=old_value + d*tx_dial->old_range;
383 if (new_value>tx_dial->old_upper)
384 new_value=tx_dial->old_upper;
385 else if (new_value<tx_dial->old_lower)
386 new_value=tx_dial->old_lower;
388 gtk_adjustment_set_value(tx_dial->adjustment, new_value);
391 static void gtk_tx_dial_update (GtkTxDial *tx_dial)
396 g_return_if_fail (tx_dial != NULL);
397 g_return_if_fail (GTK_IS_TX_DIAL (tx_dial));
399 new_value = gtk_adjustment_get_value(tx_dial->adjustment);
401 if (new_value < gtk_adjustment_get_lower(tx_dial->adjustment))
402 new_value = gtk_adjustment_get_lower(tx_dial->adjustment);
404 if (new_value > gtk_adjustment_get_upper(tx_dial->adjustment))
405 new_value = gtk_adjustment_get_upper(tx_dial->adjustment);
407 if (new_value != gtk_adjustment_get_value(tx_dial->adjustment)) {
408 gtk_adjustment_set_value(tx_dial->adjustment, new_value);
411 calc_image(new_value, image);
413 if (image!=tx_dial->old_image) {
414 tx_dial->old_image=image;
415 gtk_widget_queue_draw(GTK_WIDGET(tx_dial));
419 static void gtk_tx_dial_adjustment_changed (GtkAdjustment *adjustment,
424 g_return_if_fail (adjustment != NULL);
425 g_return_if_fail (data != NULL);
427 tx_dial = GTK_TX_DIAL (data);
429 if ((tx_dial->old_value != gtk_adjustment_get_value(adjustment)) ||
430 (tx_dial->old_lower != gtk_adjustment_get_lower(adjustment)) ||
431 (tx_dial->old_upper != gtk_adjustment_get_upper(adjustment))) {
432 tx_dial->old_value = gtk_adjustment_get_value(adjustment);
433 tx_dial->old_lower = gtk_adjustment_get_lower(adjustment);
434 tx_dial->old_upper = gtk_adjustment_get_upper(adjustment);
435 tx_dial->old_range = gtk_adjustment_get_upper(adjustment)-gtk_adjustment_get_lower(adjustment);
437 gtk_tx_dial_update (tx_dial);
441 static void gtk_tx_dial_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data)
445 g_return_if_fail (adjustment != NULL);
446 g_return_if_fail (data != NULL);
448 tx_dial = GTK_TX_DIAL (data);
450 if (tx_dial->old_value != gtk_adjustment_get_value(adjustment)) {
451 gtk_tx_dial_update (tx_dial);
452 tx_dial->old_value = gtk_adjustment_get_value(adjustment);