1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2019 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "ags_dial.h"
21 
22 #include <atk/atk.h>
23 
24 #include <gdk/gdkkeysyms.h>
25 
26 #include <stdlib.h>
27 #include <math.h>
28 
29 static GType ags_accessible_dial_get_type(void);
30 void ags_dial_class_init(AgsDialClass *dial);
31 void ags_accessible_dial_class_init(AtkObject *object);
32 void ags_accessible_dial_value_interface_init(AtkValueIface *value);
33 void ags_accessible_dial_action_interface_init(AtkActionIface *action);
34 void ags_dial_init(AgsDial *dial);
35 void ags_dial_set_property(GObject *gobject,
36 			   guint prop_id,
37 			   const GValue *value,
38 			   GParamSpec *param_spec);
39 void ags_dial_get_property(GObject *gobject,
40 			   guint prop_id,
41 			   GValue *value,
42 			   GParamSpec *param_spec);
43 AtkObject* ags_dial_get_accessible(GtkWidget *widget);
44 void ags_dial_show(GtkWidget *widget);
45 
46 void ags_accessible_dial_get_value_and_text(AtkValue *value,
47 					    gdouble *current_value,
48 					    gchar **text);
49 #ifdef HAVE_ATK_2_12
50 AtkRange* ags_accessible_dial_get_range(AtkValue *value);
51 #endif
52 gdouble ags_accessible_dial_get_increment(AtkValue *value);
53 void ags_accessible_dial_set_value(AtkValue *value,
54 				   gdouble new_value);
55 
56 gboolean ags_accessible_dial_do_action(AtkAction *action,
57 				       gint i);
58 gint ags_accessible_dial_get_n_actions(AtkAction *action);
59 const gchar* ags_accessible_dial_get_description(AtkAction *action,
60 						 gint i);
61 const gchar* ags_accessible_dial_get_name(AtkAction *action,
62 					  gint i);
63 const gchar* ags_accessible_dial_get_keybinding(AtkAction *action,
64 						gint i);
65 gboolean ags_accessible_dial_set_description(AtkAction *action,
66 					     gint i);
67 gchar* ags_accessible_dial_get_localized_name(AtkAction *action,
68 					      gint i);
69 
70 void ags_dial_map(GtkWidget *widget);
71 void ags_dial_realize(GtkWidget *widget);
72 void ags_dial_get_preferred_width(GtkWidget *widget,
73 				  gint *minimal_width,
74 				  gint *natural_width);
75 void ags_dial_get_preferred_height(GtkWidget *widget,
76 				   gint *minimal_height,
77 				   gint *natural_height);
78 void ags_dial_size_allocate(GtkWidget *widget,
79 			    GtkAllocation *allocation);
80 gboolean ags_dial_button_press(GtkWidget *widget,
81 			       GdkEventButton *event);
82 gboolean ags_dial_button_release(GtkWidget *widget,
83 				 GdkEventButton *event);
84 gboolean ags_dial_key_press(GtkWidget *widget,
85 			    GdkEventKey *event);
86 gboolean ags_dial_key_release(GtkWidget *widget,
87 			      GdkEventKey *event);
88 gboolean ags_dial_motion_notify(GtkWidget *widget,
89 				GdkEventMotion *event);
90 
91 void ags_dial_send_configure(AgsDial *dial);
92 
93 gboolean ags_dial_draw(AgsDial *dial, cairo_t *cr);
94 
95 void ags_dial_adjustment_changed_callback(GtkAdjustment *adjustment,
96 					  AgsDial *dial);
97 
98 gboolean ags_dial_button_press_is_down_event(AgsDial *dial,
99 					     GdkEventButton *event,
100 					     gint padding_left, guint padding_top);
101 gboolean ags_dial_button_press_is_up_event(AgsDial *dial,
102 					   GdkEventButton *event,
103 					   gint padding_left, guint padding_top);
104 gboolean ags_dial_button_press_is_dial_event(AgsDial *dial,
105 					     GdkEventButton *event,
106 					     gint padding_left, guint padding_top,
107 					     gint dial_left_position);
108 
109 void ags_dial_motion_notify_do_dial(AgsDial *dial,
110 				    GdkEventMotion *event);
111 void ags_dial_motion_notify_do_seemless_dial(AgsDial *dial,
112 					     GdkEventMotion *event);
113 
114 /**
115  * SECTION:ags_dial
116  * @short_description: A dial widget
117  * @title: AgsDial
118  * @section_id:
119  * @include: ags/widget/ags_dial.h
120  *
121  * #AgsDial is a widget representing a #GtkAdjustment.
122  */
123 
124 enum{
125   VALUE_CHANGED,
126   LAST_SIGNAL,
127 };
128 
129 enum{
130   PROP_0,
131   PROP_RADIUS,
132   PROP_OUTLINE_STRENGTH,
133   PROP_FONT_SIZE,
134   PROP_BUTTON_WIDTH,
135   PROP_BUTTON_HEIGHT,
136   PROP_MARGIN_LEFT,
137   PROP_MARGIN_RIGHT,
138   PROP_ADJUSTMENT,
139   PROP_SCALE_PRECISION,
140 };
141 
142 static gpointer ags_dial_parent_class = NULL;
143 static guint dial_signals[LAST_SIGNAL];
144 
145 static GQuark quark_accessible_object = 0;
146 
147 GType
ags_dial_get_type(void)148 ags_dial_get_type(void)
149 {
150   static volatile gsize g_define_type_id__volatile = 0;
151 
152   if(g_once_init_enter (&g_define_type_id__volatile)){
153     GType ags_type_dial = 0;
154 
155     static const GTypeInfo ags_dial_info = {
156       sizeof(AgsDialClass),
157       NULL, /* base_init */
158       NULL, /* base_finalize */
159       (GClassInitFunc) ags_dial_class_init,
160       NULL, /* class_finalize */
161       NULL, /* class_data */
162       sizeof(AgsDial),
163       0,    /* n_preallocs */
164       (GInstanceInitFunc) ags_dial_init,
165     };
166 
167     ags_type_dial = g_type_register_static(GTK_TYPE_WIDGET,
168 					   "AgsDial", &ags_dial_info,
169 					   0);
170 
171     g_once_init_leave(&g_define_type_id__volatile, ags_type_dial);
172   }
173 
174   return g_define_type_id__volatile;
175 }
176 
177 static GType
ags_accessible_dial_get_type(void)178 ags_accessible_dial_get_type(void)
179 {
180   static GType ags_type_accessible_dial = 0;
181 
182   if(!ags_type_accessible_dial){
183     const GTypeInfo ags_accesssible_dial_info = {
184       sizeof(GtkAccessibleClass),
185       NULL,           /* base_init */
186       NULL,           /* base_finalize */
187       (GClassInitFunc) ags_accessible_dial_class_init,
188       NULL,           /* class_finalize */
189       NULL,           /* class_data */
190       sizeof(GtkAccessible),
191       0,             /* n_preallocs */
192       NULL, NULL
193     };
194 
195     static const GInterfaceInfo atk_value_interface_info = {
196       (GInterfaceInitFunc) ags_accessible_dial_value_interface_init,
197       NULL, /* interface_finalize */
198       NULL, /* interface_data */
199     };
200 
201     static const GInterfaceInfo atk_action_interface_info = {
202       (GInterfaceInitFunc) ags_accessible_dial_action_interface_init,
203       NULL, /* interface_finalize */
204       NULL, /* interface_data */
205     };
206 
207     ags_type_accessible_dial = g_type_register_static(GTK_TYPE_ACCESSIBLE,
208 						      "AgsAccessibleDial", &ags_accesssible_dial_info,
209 						      0);
210 
211     g_type_add_interface_static(ags_type_accessible_dial,
212 				ATK_TYPE_VALUE,
213 				&atk_value_interface_info);
214 
215     g_type_add_interface_static(ags_type_accessible_dial,
216 				ATK_TYPE_ACTION,
217 				&atk_action_interface_info);
218   }
219 
220   return(ags_type_accessible_dial);
221 }
222 
223 void
ags_dial_class_init(AgsDialClass * dial)224 ags_dial_class_init(AgsDialClass *dial)
225 {
226   GObjectClass *gobject;
227   GtkWidgetClass *widget;
228   GParamSpec *param_spec;
229 
230   ags_dial_parent_class = g_type_class_peek_parent(dial);
231 
232   quark_accessible_object = g_quark_from_static_string("ags-accessible-object");
233 
234   /* GObjectClass */
235   gobject = (GObjectClass *) dial;
236 
237   gobject->set_property = ags_dial_set_property;
238   gobject->get_property = ags_dial_get_property;
239 
240   /* properties */
241   /**
242    * AgsDial:radius:
243    *
244    * The radius of the knob.
245    *
246    * Since: 3.0.0
247    */
248   param_spec = g_param_spec_uint("radius",
249 				 "radius",
250 				 "The knob's radius",
251 				 0,
252 				 G_MAXUINT,
253 				 AGS_DIAL_DEFAULT_RADIUS,
254 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
255   g_object_class_install_property(gobject,
256 				  PROP_RADIUS,
257 				  param_spec);
258 
259   /**
260    * AgsDial:outline-strength:
261    *
262    * The outline strength of the knob.
263    *
264    * Since: 3.0.0
265    */
266   param_spec = g_param_spec_uint("outline-strength",
267 				 "outline strength",
268 				 "The knob's outline strength",
269 				 0,
270 				 G_MAXUINT,
271 				 AGS_DIAL_DEFAULT_OUTLINE_STRENGTH,
272 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
273   g_object_class_install_property(gobject,
274 				  PROP_OUTLINE_STRENGTH,
275 				  param_spec);
276 
277   /**
278    * AgsDial:font-size:
279    *
280    * The font size of the buttons.
281    *
282    * Since: 3.0.0
283    */
284   param_spec = g_param_spec_uint("font-size",
285 				 "font size",
286 				 "The buttons font-size",
287 				 0,
288 				 G_MAXUINT,
289 				 AGS_DIAL_DEFAULT_FONT_SIZE,
290 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
291   g_object_class_install_property(gobject,
292 				  PROP_FONT_SIZE,
293 				  param_spec);
294 
295   /**
296    * AgsDial:button-width:
297    *
298    * The buttons width.
299    *
300    * Since: 3.0.0
301    */
302   param_spec = g_param_spec_int("button-width",
303 				"buttons width",
304 				"The buttons width",
305 				-1,
306 				G_MAXINT,
307 				AGS_DIAL_DEFAULT_BUTTON_WIDTH,
308 				G_PARAM_READABLE | G_PARAM_WRITABLE);
309   g_object_class_install_property(gobject,
310 				  PROP_BUTTON_WIDTH,
311 				  param_spec);
312 
313   /**
314    * AgsDial:button-height:
315    *
316    * The buttons height.
317    *
318    * Since: 3.0.0
319    */
320   param_spec = g_param_spec_int("button-height",
321 				"buttons height",
322 				"The buttons height",
323 				-1,
324 				G_MAXINT,
325 				AGS_DIAL_DEFAULT_BUTTON_HEIGHT,
326 				G_PARAM_READABLE | G_PARAM_WRITABLE);
327   g_object_class_install_property(gobject,
328 				  PROP_BUTTON_HEIGHT,
329 				  param_spec);
330 
331 
332   /**
333    * AgsDial:margin-left:
334    *
335    * The button's margin left.
336    *
337    * Since: 3.0.0
338    */
339   param_spec = g_param_spec_int("margin-left",
340 				"button's margin left",
341 				"The button's margin left",
342 				-1,
343 				G_MAXINT,
344 				AGS_DIAL_DEFAULT_MARGIN_LEFT,
345 				G_PARAM_READABLE | G_PARAM_WRITABLE);
346   g_object_class_install_property(gobject,
347 				  PROP_MARGIN_LEFT,
348 				  param_spec);
349 
350   /**
351    * AgsDial:margin-right:
352    *
353    * The button's margin right.
354    *
355    * Since: 3.0.0
356    */
357   param_spec = g_param_spec_int("margin-right",
358 				"button's margin right",
359 				"The button's margin right",
360 				-1,
361 				G_MAXINT,
362 				AGS_DIAL_DEFAULT_MARGIN_RIGHT,
363 				G_PARAM_READABLE | G_PARAM_WRITABLE);
364   g_object_class_install_property(gobject,
365 				  PROP_MARGIN_RIGHT,
366 				  param_spec);
367 
368   /**
369    * AgsDial:adjustment:
370    *
371    * The adjustment storing current value and boundaries.
372    *
373    * Since: 3.0.0
374    */
375   param_spec = g_param_spec_object("adjustment",
376 				   "assigned adjustment",
377 				   "The adjustment it is assigned with",
378 				   G_TYPE_OBJECT,
379 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
380   g_object_class_install_property(gobject,
381 				  PROP_ADJUSTMENT,
382 				  param_spec);
383 
384   /**
385    * AgsDial:scale-precision:
386    *
387    * The precision of the scale.
388    *
389    * Since: 3.0.0
390    */
391   param_spec = g_param_spec_uint("scale-precision",
392 				 "scale precision",
393 				 "The precision of the scale",
394 				 0,
395 				 G_MAXUINT,
396 				 AGS_DIAL_DEFAULT_PRECISION,
397 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
398   g_object_class_install_property(gobject,
399 				  PROP_SCALE_PRECISION,
400 				  param_spec);
401 
402   /* GtkWidgetClass */
403   widget = (GtkWidgetClass *) dial;
404 
405   widget->get_accessible = ags_dial_get_accessible;
406   //  widget->map = ags_dial_map;
407   widget->realize = ags_dial_realize;
408   widget->size_allocate = ags_dial_size_allocate;
409   widget->get_preferred_width = ags_dial_get_preferred_width;
410   widget->get_preferred_height = ags_dial_get_preferred_height;
411   widget->button_press_event = ags_dial_button_press;
412   widget->button_release_event = ags_dial_button_release;
413   widget->key_press_event = ags_dial_key_press;
414   widget->key_release_event = ags_dial_key_release;
415   widget->motion_notify_event = ags_dial_motion_notify;
416   widget->show = ags_dial_show;
417   widget->draw = ags_dial_draw;
418 
419   /* AgsDialClass */
420   dial->value_changed = NULL;
421 
422   /* signals */
423   /**
424    * AgsDial::value-changed:
425    * @dial: the #AgsDial
426    *
427    * The ::value-changed signal notifies adjustment value changed.
428    *
429    * Since: 3.0.0
430    */
431   dial_signals[VALUE_CHANGED] =
432     g_signal_new("value-changed",
433 		 G_TYPE_FROM_CLASS(dial),
434 		 G_SIGNAL_RUN_LAST,
435 		 G_STRUCT_OFFSET(AgsDialClass, value_changed),
436 		 NULL, NULL,
437 		 g_cclosure_marshal_VOID__VOID,
438 		 G_TYPE_NONE, 0);
439 }
440 
441 void
ags_accessible_dial_class_init(AtkObject * object)442 ags_accessible_dial_class_init(AtkObject *object)
443 {
444   /* empty */
445 }
446 
447 void
ags_accessible_dial_value_interface_init(AtkValueIface * value)448 ags_accessible_dial_value_interface_init(AtkValueIface *value)
449 {
450   value->get_current_value = NULL;
451   value->get_maximum_value = NULL;
452   value->get_minimum_value = NULL;
453   value->set_current_value = NULL;
454   value->get_minimum_increment = NULL;
455 
456 #ifdef HAVE_ATK_2_12
457   value->get_value_and_text = ags_accessible_dial_get_value_and_text;
458   value->get_range = ags_accessible_dial_get_range;
459   value->get_increment = ags_accessible_dial_get_increment;
460   value->get_sub_ranges = NULL;
461   value->set_value = ags_accessible_dial_set_value;
462 #endif
463 }
464 
465 void
ags_accessible_dial_action_interface_init(AtkActionIface * action)466 ags_accessible_dial_action_interface_init(AtkActionIface *action)
467 {
468   action->do_action = ags_accessible_dial_do_action;
469   action->get_n_actions = ags_accessible_dial_get_n_actions;
470   action->get_description = ags_accessible_dial_get_description;
471   action->get_name = ags_accessible_dial_get_name;
472   action->get_keybinding = ags_accessible_dial_get_keybinding;
473   action->set_description = ags_accessible_dial_set_description;
474   action->get_localized_name = ags_accessible_dial_get_localized_name;
475 }
476 
477 void
ags_dial_init(AgsDial * dial)478 ags_dial_init(AgsDial *dial)
479 {
480   AtkObject *accessible;
481 
482   gtk_widget_set_can_focus((GtkWidget *) dial,
483 			   TRUE);
484 
485   accessible = gtk_widget_get_accessible((GtkWidget *) dial);
486 
487   g_object_set(accessible,
488 	       "accessible-name", "dial",
489 	       "accessible-description", "Adjust a value",
490 	       NULL);
491 
492   g_object_set(G_OBJECT(dial),
493   	       "app-paintable", TRUE,
494 	       "can-focus", TRUE,
495   	       NULL);
496 
497   dial->flags = (AGS_DIAL_WITH_BUTTONS |
498 		 AGS_DIAL_SEEMLESS_MODE |
499 		 AGS_DIAL_INVERSE_LIGHT);
500 
501   dial->radius = AGS_DIAL_DEFAULT_RADIUS;
502   dial->scale_precision = AGS_DIAL_DEFAULT_PRECISION;
503   dial->scale_max_precision = AGS_DIAL_DEFAULT_PRECISION;
504   dial->outline_strength = AGS_DIAL_DEFAULT_OUTLINE_STRENGTH;
505 
506   dial->font_size = AGS_DIAL_DEFAULT_FONT_SIZE;
507   dial->button_width = AGS_DIAL_DEFAULT_BUTTON_WIDTH;
508   dial->button_height = AGS_DIAL_DEFAULT_BUTTON_HEIGHT;
509   dial->margin_left = AGS_DIAL_DEFAULT_MARGIN_LEFT;
510   dial->margin_right = AGS_DIAL_DEFAULT_MARGIN_RIGHT;
511 
512   dial->tolerance = 0.9;
513   dial->negated_tolerance = 1.1;
514 
515   dial->adjustment = NULL;
516 
517   dial->gravity_x = 0.0;
518   dial->gravity_y = 0.0;
519   dial->current_x = 0.0;
520   dial->current_y = 0.0;
521 }
522 
523 void
ags_dial_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)524 ags_dial_set_property(GObject *gobject,
525 		      guint prop_id,
526 		      const GValue *value,
527 		      GParamSpec *param_spec)
528 {
529   AgsDial *dial;
530 
531   dial = AGS_DIAL(gobject);
532 
533   switch(prop_id){
534   case PROP_RADIUS:
535     {
536       dial->radius = g_value_get_uint(value);
537     }
538     break;
539   case PROP_OUTLINE_STRENGTH:
540     {
541       dial->outline_strength = g_value_get_uint(value);
542     }
543     break;
544   case PROP_FONT_SIZE:
545     {
546       dial->font_size = g_value_get_uint(value);
547     }
548     break;
549   case PROP_BUTTON_WIDTH:
550     {
551       dial->button_width = g_value_get_int(value);
552     }
553     break;
554   case PROP_BUTTON_HEIGHT:
555     {
556       dial->button_height = g_value_get_int(value);
557     }
558     break;
559   case PROP_MARGIN_LEFT:
560     {
561       dial->margin_left = g_value_get_int(value);
562     }
563     break;
564   case PROP_MARGIN_RIGHT:
565     {
566       dial->margin_right = g_value_get_int(value);
567     }
568     break;
569   case PROP_ADJUSTMENT:
570     {
571       GtkAdjustment *adjustment;
572 
573       adjustment = (GtkAdjustment *) g_value_get_object(value);
574 
575       if(dial->adjustment == adjustment){
576 	return;
577       }
578 
579       if(dial->adjustment != NULL){
580 	g_object_unref(G_OBJECT(dial->adjustment));
581       }
582 
583       if(adjustment != NULL){
584 	g_object_ref(G_OBJECT(adjustment));
585 	g_signal_connect(adjustment, "value-changed",
586 			 G_CALLBACK(ags_dial_adjustment_changed_callback), dial);
587       }
588 
589       dial->adjustment = adjustment;
590     }
591     break;
592   case PROP_SCALE_PRECISION:
593     {
594       guint scale_precision;
595 
596       scale_precision = g_value_get_uint(value);
597 
598       if(scale_precision > dial->scale_max_precision){
599 	dial->scale_precision = dial->scale_max_precision;
600       }else if(scale_precision == 0){
601 	dial->scale_precision = 1;
602       }else{
603 	dial->scale_precision = scale_precision;
604       }
605     }
606     break;
607   default:
608     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
609     break;
610   }
611 }
612 
613 void
ags_dial_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)614 ags_dial_get_property(GObject *gobject,
615 		      guint prop_id,
616 		      GValue *value,
617 		      GParamSpec *param_spec)
618 {
619   AgsDial *dial;
620 
621   dial = AGS_DIAL(gobject);
622 
623   switch(prop_id){
624   case PROP_RADIUS:
625     {
626       g_value_set_uint(value, dial->radius);
627     }
628     break;
629   case PROP_OUTLINE_STRENGTH:
630     {
631       g_value_set_uint(value, dial->outline_strength);
632     }
633     break;
634   case PROP_FONT_SIZE:
635     {
636       g_value_set_uint(value, dial->font_size);
637     }
638     break;
639   case PROP_BUTTON_WIDTH:
640     {
641       g_value_set_int(value, dial->button_width);
642     }
643     break;
644   case PROP_BUTTON_HEIGHT:
645     {
646       g_value_set_int(value, dial->button_height);
647     }
648     break;
649   case PROP_MARGIN_LEFT:
650     {
651       g_value_set_int(value, dial->margin_left);
652     }
653     break;
654   case PROP_MARGIN_RIGHT:
655     {
656       g_value_set_int(value, dial->margin_right);
657     }
658     break;
659   case PROP_ADJUSTMENT:
660   {
661     g_value_set_object(value, dial->adjustment);
662   }
663   break;
664   case PROP_SCALE_PRECISION:
665     {
666       g_value_set_uint(value, dial->scale_precision);
667     }
668     break;
669   default:
670     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
671     break;
672   }
673 }
674 
675 void
ags_accessible_dial_get_value_and_text(AtkValue * value,gdouble * current_value,gchar ** text)676 ags_accessible_dial_get_value_and_text(AtkValue *value,
677 				       gdouble *current_value,
678 				       gchar **text)
679 {
680   AgsDial *dial;
681 
682   dial = (AgsDial *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
683 
684   if(current_value != NULL){
685     *current_value = gtk_adjustment_get_value(dial->adjustment);
686   }
687 
688   if(text != NULL){
689     *text = g_strdup_printf("%f",
690 			    gtk_adjustment_get_value(dial->adjustment));
691   }
692 }
693 
694 #ifdef HAVE_ATK_2_12
695 AtkRange*
ags_accessible_dial_get_range(AtkValue * value)696 ags_accessible_dial_get_range(AtkValue *value)
697 {
698   AgsDial *dial;
699   AtkRange *range;
700 
701   dial = (AgsDial *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
702 
703   range = atk_range_new(gtk_adjustment_get_lower(dial->adjustment),
704 			gtk_adjustment_get_upper(dial->adjustment),
705 			"Valid lower and upper input range of this dial");
706 
707   return(range);
708 }
709 #endif
710 
711 gdouble
ags_accessible_dial_get_increment(AtkValue * value)712 ags_accessible_dial_get_increment(AtkValue *value)
713 {
714   AgsDial *dial;
715 
716   dial = (AgsDial *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
717 
718   return(gtk_adjustment_get_step_increment(dial->adjustment));
719 }
720 
721 void
ags_accessible_dial_set_value(AtkValue * value,gdouble new_value)722 ags_accessible_dial_set_value(AtkValue *value,
723 			      gdouble new_value)
724 {
725   AgsDial *dial;
726 
727   dial = (AgsDial *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
728   gtk_adjustment_set_value(dial->adjustment,
729 			   new_value);
730   gtk_widget_queue_draw((GtkWidget *) dial);
731 }
732 
733 gboolean
ags_accessible_dial_do_action(AtkAction * action,gint i)734 ags_accessible_dial_do_action(AtkAction *action,
735 			      gint i)
736 {
737   AgsDial *dial;
738 
739   GdkEventKey *key_press, *key_release;
740 
741   if(!(i >= 0 && i < 2)){
742     return(FALSE);
743   }
744 
745   dial = (AgsDial *) gtk_accessible_get_widget(GTK_ACCESSIBLE(action));
746 
747   key_press = gdk_event_new(GDK_KEY_PRESS);
748   key_release = gdk_event_new(GDK_KEY_RELEASE);
749 
750   switch(i){
751   case AGS_DIAL_INCREMENT:
752     {
753       key_press->keyval =
754 	key_release->keyval = GDK_KEY_Page_Up;
755 
756       /* send event */
757       gtk_widget_event((GtkWidget *) dial,
758 		       (GdkEvent *) key_press);
759       gtk_widget_event((GtkWidget *) dial,
760 		       (GdkEvent *) key_release);
761     }
762     break;
763   case AGS_DIAL_DECREMENT:
764     {
765       key_press->keyval =
766 	key_release->keyval = GDK_KEY_Page_Down;
767 
768       /* send event */
769       gtk_widget_event((GtkWidget *) dial,
770 		       (GdkEvent *) key_press);
771       gtk_widget_event((GtkWidget *) dial,
772 		       (GdkEvent *) key_release);
773     }
774     break;
775   }
776 
777   return(TRUE);
778 }
779 
780 gint
ags_accessible_dial_get_n_actions(AtkAction * action)781 ags_accessible_dial_get_n_actions(AtkAction *action)
782 {
783   return(2);
784 }
785 
786 const gchar*
ags_accessible_dial_get_description(AtkAction * action,gint i)787 ags_accessible_dial_get_description(AtkAction *action,
788 				    gint i)
789 {
790   static const gchar *actions[] = {
791     "increment dial value",
792     "decrement dial value",
793   };
794 
795   if(i >= 0 && i < 2){
796     return(actions[i]);
797   }else{
798     return(NULL);
799   }
800 }
801 
802 const gchar*
ags_accessible_dial_get_name(AtkAction * action,gint i)803 ags_accessible_dial_get_name(AtkAction *action,
804 			     gint i)
805 {
806   static const gchar *actions[] = {
807     "increment",
808     "decrement",
809   };
810 
811   if(i >= 0 && i < 2){
812     return(actions[i]);
813   }else{
814     return(NULL);
815   }
816 }
817 
818 const gchar*
ags_accessible_dial_get_keybinding(AtkAction * action,gint i)819 ags_accessible_dial_get_keybinding(AtkAction *action,
820 				   gint i)
821 {
822   static const gchar *actions[] = {
823     "up",
824     "down",
825   };
826 
827   if(i >= 0 && i < 2){
828     return(actions[i]);
829   }else{
830     return(NULL);
831   }
832 }
833 
834 gboolean
ags_accessible_dial_set_description(AtkAction * action,gint i)835 ags_accessible_dial_set_description(AtkAction *action,
836 				    gint i)
837 {
838   //TODO:JK: implement me
839 
840   return(FALSE);
841 }
842 
843 gchar*
ags_accessible_dial_get_localized_name(AtkAction * action,gint i)844 ags_accessible_dial_get_localized_name(AtkAction *action,
845 				       gint i)
846 {
847   //TODO:JK: implement me
848 
849   return(NULL);
850 }
851 
852 void
ags_dial_map(GtkWidget * widget)853 ags_dial_map(GtkWidget *widget)
854 {
855   if (gtk_widget_get_realized (widget) && !gtk_widget_get_mapped (widget)) {
856     GTK_WIDGET_CLASS (ags_dial_parent_class)->map(widget);
857 
858     gdk_window_show(gtk_widget_get_window(widget));
859   }
860 }
861 
862 void
ags_dial_realize(GtkWidget * widget)863 ags_dial_realize(GtkWidget *widget)
864 {
865   AgsDial *dial;
866 
867   GdkWindow *window;
868 
869   GtkAllocation allocation;
870   GdkWindowAttr attributes;
871 
872   gint attributes_mask;
873   gint buttons_width;
874   gint border_left, border_top;
875 
876   g_return_if_fail(widget != NULL);
877   g_return_if_fail(AGS_IS_DIAL (widget));
878 
879   dial = AGS_DIAL(widget);
880 
881   gtk_widget_set_realized(widget, TRUE);
882 
883   /* calculate some display dependend fields */
884   buttons_width = 0;
885 
886 #if 0
887   if((AGS_DIAL_WITH_BUTTONS & (dial->flags)) != 0){
888     cairo_t *cr;
889     cairo_text_extents_t te_up, te_down;
890 
891     cr = gdk_cairo_create(widget->parent->window);
892 
893     if(cr == NULL){
894       return;
895     }
896 
897     cairo_select_font_face (cr, "Georgia",
898 			    CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
899     cairo_set_font_size (cr, (gdouble) dial->font_size);
900     cairo_text_extents (cr, "-", &te_down);
901     cairo_text_extents (cr, "+", &te_up);
902 
903     if(te_down.width < te_up.width){
904       dial->button_width = te_up.width * 3;
905     }else{
906       dial->button_width = te_down.width * 3;
907     }
908 
909     buttons_width = 2 * dial->button_width;
910 
911     if(te_down.height < te_up.height){
912       dial->button_height = te_up.height * 2;
913     }else{
914       dial->button_height = te_down.height * 2;
915     }
916 
917     cairo_destroy(cr);
918   }
919 #endif
920 
921   gtk_widget_get_allocation(widget,
922 			    &allocation);
923 
924   /*  */
925   attributes.window_type = GDK_WINDOW_CHILD;
926 
927   attributes.x = allocation.x;
928   attributes.y = allocation.y;
929   attributes.width = allocation.width;
930   attributes.height = allocation.height;
931 
932   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
933 
934   attributes.wclass = GDK_INPUT_OUTPUT;
935   attributes.visual = gtk_widget_get_visual(widget);
936   attributes.event_mask = gtk_widget_get_events(widget);
937   attributes.event_mask |= (GDK_EXPOSURE_MASK |
938                             GDK_BUTTON_PRESS_MASK |
939                             GDK_BUTTON_RELEASE_MASK |
940 			    GDK_KEY_PRESS_MASK |
941 			    GDK_KEY_RELEASE_MASK |
942                             GDK_BUTTON1_MOTION_MASK |
943                             GDK_BUTTON3_MOTION_MASK |
944                             GDK_POINTER_MOTION_HINT_MASK |
945                             GDK_POINTER_MOTION_MASK |
946                             GDK_ENTER_NOTIFY_MASK |
947                             GDK_LEAVE_NOTIFY_MASK);
948 
949   window = gdk_window_new(gtk_widget_get_parent_window(widget),
950 			  &attributes, attributes_mask);
951 
952   gtk_widget_register_window(widget, window);
953   gtk_widget_set_window(widget, window);
954 
955   ags_dial_send_configure(dial);
956 }
957 
958 void
ags_dial_size_allocate(GtkWidget * widget,GtkAllocation * allocation)959 ags_dial_size_allocate(GtkWidget *widget,
960 		       GtkAllocation *allocation)
961 {
962   AgsDial *dial;
963 
964   guint min_width;
965 
966   g_return_if_fail(AGS_IS_DIAL(widget));
967   g_return_if_fail(allocation != NULL);
968 
969   dial = AGS_DIAL(widget);
970 
971   min_width = 2 * (dial->button_width + dial->radius + dial->outline_strength + 2) + (dial->margin_left + dial->margin_right);
972 
973   if(allocation->width < min_width){
974     allocation->width = min_width;
975   }
976 
977   allocation->height = 2 * (dial->radius + dial->outline_strength + 1);
978 
979   //TODO:JK: improve me
980   gtk_widget_set_allocation(widget, allocation);
981 
982   if(gtk_widget_get_realized(widget)){
983     gdk_window_move_resize(gtk_widget_get_window(widget),
984 			   allocation->x, allocation->y,
985 			   allocation->width, allocation->height);
986 
987     ags_dial_send_configure(dial);
988   }
989 }
990 
991 void
ags_dial_send_configure(AgsDial * dial)992 ags_dial_send_configure(AgsDial *dial)
993 {
994   GtkAllocation allocation;
995   GtkWidget *widget;
996   GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
997 
998   widget = GTK_WIDGET(dial);
999   gtk_widget_get_allocation(widget, &allocation);
1000 
1001   event->configure.window = g_object_ref(gtk_widget_get_window (widget));
1002   event->configure.send_event = TRUE;
1003   event->configure.x = allocation.x;
1004   event->configure.y = allocation.y;
1005   event->configure.width = allocation.width;
1006   event->configure.height = allocation.height;
1007 
1008   gtk_widget_event(widget, event);
1009   gdk_event_free(event);
1010 }
1011 
1012 void
ags_dial_get_preferred_width(GtkWidget * widget,gint * minimal_width,gint * natural_width)1013 ags_dial_get_preferred_width(GtkWidget *widget,
1014 			     gint *minimal_width,
1015 			     gint *natural_width)
1016 {
1017   AgsDial *dial;
1018 
1019   dial = AGS_DIAL(widget);
1020 
1021   minimal_width[0] =
1022     natural_width[0] = 2 * (dial->button_width + dial->radius + dial->outline_strength + 2) + (dial->margin_left + dial->margin_right);
1023 }
1024 
1025 void
ags_dial_get_preferred_height(GtkWidget * widget,gint * minimal_height,gint * natural_height)1026 ags_dial_get_preferred_height(GtkWidget *widget,
1027 			      gint *minimal_height,
1028 			      gint *natural_height)
1029 {
1030   AgsDial *dial;
1031 
1032   dial = AGS_DIAL(widget);
1033 
1034   minimal_height[0] =
1035     natural_height[0] = 2 * (dial->radius + dial->outline_strength + 1);
1036 }
1037 
1038 AtkObject*
ags_dial_get_accessible(GtkWidget * widget)1039 ags_dial_get_accessible(GtkWidget *widget)
1040 {
1041   AtkObject* accessible;
1042 
1043   accessible = g_object_get_qdata(G_OBJECT(widget),
1044 				  quark_accessible_object);
1045 
1046   if(!accessible){
1047     accessible = g_object_new(ags_accessible_dial_get_type(),
1048 			      NULL);
1049 
1050     g_object_set_qdata(G_OBJECT(widget),
1051 		       quark_accessible_object,
1052 		       accessible);
1053     gtk_accessible_set_widget(GTK_ACCESSIBLE(accessible),
1054 			      widget);
1055   }
1056 
1057   return(accessible);
1058 }
1059 
1060 void
ags_dial_show(GtkWidget * widget)1061 ags_dial_show(GtkWidget *widget)
1062 {
1063   GTK_WIDGET_CLASS(ags_dial_parent_class)->show(widget);
1064 }
1065 
1066 gboolean
ags_dial_button_press_is_down_event(AgsDial * dial,GdkEventButton * event,gint padding_left,guint padding_top)1067 ags_dial_button_press_is_down_event(AgsDial *dial,
1068 				    GdkEventButton *event,
1069 				    gint padding_left, guint padding_top)
1070 {
1071   if(event->x >= padding_left &&
1072      event->x <= padding_left + dial->button_width &&
1073      event->y >= padding_top + 2 * dial->radius + 2 * dial->outline_strength - dial->button_height &&
1074      event->y <= padding_top + 2 * dial->radius + 2 * dial->outline_strength){
1075     return(TRUE);
1076   }else{
1077     return(FALSE);
1078   }
1079 }
1080 
1081 gboolean
ags_dial_button_press_is_up_event(AgsDial * dial,GdkEventButton * event,gint padding_left,guint padding_top)1082 ags_dial_button_press_is_up_event(AgsDial *dial,
1083 				  GdkEventButton *event,
1084 				  gint padding_left, guint padding_top)
1085 {
1086   gint offset;
1087 
1088   offset = padding_left + dial->button_width + 2 * dial->radius + dial->margin_left + dial->margin_right;
1089 
1090   if(event->x >= offset &&
1091      event->x <= offset + dial->button_width &&
1092      event->y >= padding_top + 2 * dial->radius + 2 * dial->outline_strength - dial->button_height &&
1093      event->y <= padding_top + 2 * dial->radius + 2 * dial->outline_strength){
1094     return(TRUE);
1095   }else{
1096     return(FALSE);
1097   }
1098 }
1099 
1100 gboolean
ags_dial_button_press_is_dial_event(AgsDial * dial,GdkEventButton * event,gint padding_left,guint padding_top,gint dial_left_position)1101 ags_dial_button_press_is_dial_event(AgsDial *dial,
1102 				    GdkEventButton *event,
1103 				    gint padding_left, guint padding_top,
1104 				    gint dial_left_position)
1105 {
1106   if(event->x >= dial_left_position &&
1107      event->x <= dial_left_position + 2 * dial->radius + 2 * dial->outline_strength){
1108     if((cos(event->y) < 0.0 && cos(event->y) >= -1.0) ||
1109        (sin(event->y) > 0.0 && sin(event->y) <= 1.0) ||
1110        (cos(event->y) < 0.0 && sin(event->y) >= -1.0) ||
1111        (sin(event->y) < 0.0 && cos(event->y) >= -1.0)){
1112       return(TRUE);
1113     }else{
1114       return(FALSE);
1115     }
1116   }else{
1117     return(FALSE);
1118   }
1119 }
1120 
1121 gboolean
ags_dial_button_press(GtkWidget * widget,GdkEventButton * event)1122 ags_dial_button_press(GtkWidget *widget,
1123 		      GdkEventButton *event)
1124 {
1125   AgsDial *dial;
1126 
1127   GtkAllocation allocation;
1128 
1129   gdouble button_width, button_height, margin_left, margin_right;
1130   gdouble radius, outline_strength;
1131   guint width, height;
1132   gint padding_left, padding_top;
1133   gint dial_left_position;
1134 
1135   //  GTK_WIDGET_CLASS(ags_dial_parent_class)->button_press_event(widget, event);
1136 
1137   dial = AGS_DIAL(widget);
1138   dial->flags |= AGS_DIAL_MOUSE_BUTTON_PRESSED;
1139 
1140   gtk_widget_get_allocation(widget,
1141 			    &allocation);
1142 
1143   button_width = dial->button_width;
1144   button_height = dial->button_height;
1145 
1146   margin_left = (gdouble) dial->margin_left;
1147   margin_right = (gdouble) dial->margin_right;
1148 
1149   radius = (gdouble) dial->radius;
1150   outline_strength = (gdouble) dial->outline_strength;
1151 
1152   width = 2 * (button_height + radius + outline_strength + 2) + (margin_left + margin_right);
1153   height = 2 * (radius + outline_strength + 1);
1154 
1155   padding_top = (allocation.height - height) / 2;
1156   padding_left = (allocation.width - width) / 2;
1157 
1158   if((AGS_DIAL_WITH_BUTTONS & (dial->flags)) != 0){
1159     if(ags_dial_button_press_is_down_event(dial,
1160 					   event,
1161 					   padding_left, padding_top)){
1162       dial->flags |= AGS_DIAL_BUTTON_DOWN_PRESSED;
1163     }else if(ags_dial_button_press_is_up_event(dial,
1164 					       event,
1165 					       padding_left, padding_top)){
1166       dial->flags |= AGS_DIAL_BUTTON_UP_PRESSED;
1167     }else{
1168       dial_left_position = padding_left + dial->button_width;
1169 
1170       if(ags_dial_button_press_is_dial_event(dial,
1171 					     event,
1172 					     padding_left, padding_top,
1173 					     dial_left_position)){
1174 	dial->flags |= AGS_DIAL_MOTION_CAPTURING;
1175       }
1176     }
1177   }else{
1178     dial_left_position = padding_left;
1179 
1180     if(ags_dial_button_press_is_dial_event(dial,
1181 					   event,
1182 					   padding_left, padding_top,
1183 					   dial_left_position)){
1184       dial->gravity_x = event->x;
1185       dial->gravity_y = event->y;
1186       dial->current_x = event->x;
1187       dial->current_y = event->y;
1188 
1189       dial->flags |= AGS_DIAL_MOTION_CAPTURING_INIT;
1190       dial->flags |= AGS_DIAL_MOTION_CAPTURING;
1191     }
1192   }
1193 
1194   return(FALSE);
1195 }
1196 
1197 gboolean
ags_dial_button_release(GtkWidget * widget,GdkEventButton * event)1198 ags_dial_button_release(GtkWidget *widget,
1199 			GdkEventButton *event)
1200 {
1201   AgsDial *dial;
1202 
1203   //  GTK_WIDGET_CLASS(ags_dial_parent_class)->button_release_event(widget, event);
1204 
1205   gtk_widget_grab_focus(widget);
1206 
1207   dial = AGS_DIAL(widget);
1208   dial->flags &= (~AGS_DIAL_MOUSE_BUTTON_PRESSED);
1209 
1210   if((AGS_DIAL_BUTTON_DOWN_PRESSED & (dial->flags)) != 0){
1211     GtkAdjustment *adjustment;
1212 
1213     adjustment = dial->adjustment;
1214 
1215     if(gtk_adjustment_get_value(adjustment) > gtk_adjustment_get_lower(adjustment)){
1216       gtk_adjustment_set_value(adjustment,
1217 			       gtk_adjustment_get_value(adjustment) - gtk_adjustment_get_page_increment(adjustment));
1218 
1219       gtk_widget_queue_draw(dial);
1220     }
1221 
1222     dial->flags &= (~AGS_DIAL_BUTTON_DOWN_PRESSED);
1223   }else if((AGS_DIAL_BUTTON_UP_PRESSED & (dial->flags)) != 0){
1224     GtkAdjustment *adjustment;
1225 
1226     adjustment = dial->adjustment;
1227 
1228     if(gtk_adjustment_get_value(adjustment) < gtk_adjustment_get_upper(adjustment)){
1229       gtk_adjustment_set_value(adjustment,
1230 			       gtk_adjustment_get_value(adjustment) + gtk_adjustment_get_page_increment(adjustment));
1231 
1232       gtk_widget_queue_draw(dial);
1233     }
1234 
1235     dial->flags &= (~AGS_DIAL_BUTTON_UP_PRESSED);
1236   }else if((AGS_DIAL_MOTION_CAPTURING & (dial->flags)) != 0){
1237     dial->flags &= (~AGS_DIAL_MOTION_CAPTURING);
1238   }
1239 
1240   return(FALSE);
1241 }
1242 
1243 gboolean
ags_dial_key_press(GtkWidget * widget,GdkEventKey * event)1244 ags_dial_key_press(GtkWidget *widget,
1245 		   GdkEventKey *event)
1246 {
1247   if(event->keyval == GDK_KEY_Tab ||
1248      event->keyval == GDK_KEY_ISO_Left_Tab ||
1249      event->keyval == GDK_KEY_Shift_L ||
1250      event->keyval == GDK_KEY_Shift_R ||
1251      event->keyval == GDK_KEY_Alt_L ||
1252      event->keyval == GDK_KEY_Alt_R ||
1253      event->keyval == GDK_KEY_Control_L ||
1254      event->keyval == GDK_KEY_Control_R ){
1255     return(GTK_WIDGET_CLASS(ags_dial_parent_class)->key_press_event(widget, event));
1256   }
1257 
1258   return(TRUE);
1259 }
1260 
1261 gboolean
ags_dial_key_release(GtkWidget * widget,GdkEventKey * event)1262 ags_dial_key_release(GtkWidget *widget,
1263 		     GdkEventKey *event)
1264 {
1265   AgsDial *dial;
1266 
1267   if(event->keyval == GDK_KEY_Tab ||
1268      event->keyval == GDK_KEY_ISO_Left_Tab ||
1269      event->keyval == GDK_KEY_Shift_L ||
1270      event->keyval == GDK_KEY_Shift_R ||
1271      event->keyval == GDK_KEY_Alt_L ||
1272      event->keyval == GDK_KEY_Alt_R ||
1273      event->keyval == GDK_KEY_Control_L ||
1274      event->keyval == GDK_KEY_Control_R ){
1275     return(GTK_WIDGET_CLASS(ags_dial_parent_class)->key_release_event(widget, event));
1276   }
1277 
1278   dial = AGS_DIAL(widget);
1279 
1280   switch(event->keyval){
1281   case GDK_KEY_Up:
1282   case GDK_KEY_uparrow:
1283     {
1284       gdouble value, step, upper;
1285 
1286       value = gtk_adjustment_get_value(dial->adjustment);
1287       step = gtk_adjustment_get_step_increment(dial->adjustment);
1288       upper = gtk_adjustment_get_upper(dial->adjustment);
1289 
1290       if(value + step > upper){
1291 	gtk_adjustment_set_value(dial->adjustment,
1292 				 upper);
1293       }else{
1294 	gtk_adjustment_set_value(dial->adjustment,
1295 				 value + step);
1296       }
1297 
1298       gtk_widget_queue_draw(widget);
1299     }
1300     break;
1301   case GDK_KEY_Down:
1302   case GDK_KEY_downarrow:
1303   {
1304     gdouble value, step, lower;
1305 
1306     value = gtk_adjustment_get_value(dial->adjustment);
1307     step = gtk_adjustment_get_step_increment(dial->adjustment);
1308     lower = gtk_adjustment_get_lower(dial->adjustment);
1309 
1310     if(value - step < lower){
1311       gtk_adjustment_set_value(dial->adjustment,
1312 			       lower);
1313     }else{
1314       gtk_adjustment_set_value(dial->adjustment,
1315 			       value - step);
1316     }
1317 
1318     gtk_widget_queue_draw(widget);
1319   }
1320   break;
1321   case GDK_KEY_Page_Up:
1322   case GDK_KEY_KP_Page_Up:
1323     {
1324       gdouble value, page, upper;
1325 
1326       value = gtk_adjustment_get_value(dial->adjustment);
1327       page = gtk_adjustment_get_page_increment(dial->adjustment);
1328       upper = gtk_adjustment_get_upper(dial->adjustment);
1329 
1330       if(value + page > upper){
1331 	gtk_adjustment_set_value(dial->adjustment,
1332 				 upper);
1333       }else{
1334 	gtk_adjustment_set_value(dial->adjustment,
1335 				 value + page);
1336       }
1337 
1338       gtk_widget_queue_draw(widget);
1339     }
1340     break;
1341   case GDK_KEY_Page_Down:
1342   case GDK_KEY_KP_Page_Down:
1343   {
1344     gdouble value, page, lower;
1345 
1346     value = gtk_adjustment_get_value(dial->adjustment);
1347     page = gtk_adjustment_get_page_increment(dial->adjustment);
1348     lower = gtk_adjustment_get_lower(dial->adjustment);
1349 
1350     if(value - page < lower){
1351       gtk_adjustment_set_value(dial->adjustment,
1352 			       lower);
1353     }else{
1354       gtk_adjustment_set_value(dial->adjustment,
1355 			       value - page);
1356     }
1357 
1358     gtk_widget_queue_draw(widget);
1359   }
1360   break;
1361   }
1362 
1363   return(TRUE);
1364 }
1365 
1366 void
ags_dial_motion_notify_do_dial(AgsDial * dial,GdkEventMotion * event)1367 ags_dial_motion_notify_do_dial(AgsDial *dial,
1368 			       GdkEventMotion *event)
1369 {
1370   GtkAdjustment *adjustment;
1371 
1372   guint i;
1373   gint sign_one;
1374   gboolean gravity_up;
1375 
1376   static const gboolean movement_matrix[] = {
1377     FALSE,
1378     TRUE,
1379     FALSE,
1380     FALSE,
1381     TRUE,
1382     FALSE,
1383     TRUE,
1384     TRUE,
1385   };
1386 
1387   adjustment = dial->adjustment;
1388 
1389   gravity_up = FALSE;
1390 
1391   for(i = 0; i < 8 ; i++){
1392     if(!movement_matrix[i]){
1393       sign_one = -1;
1394     }else{
1395       sign_one = 1;
1396     }
1397 
1398     if((movement_matrix[i] &&
1399 	(sign_one * (dial->gravity_x - dial->current_x) < sign_one * (dial->gravity_y - dial->current_y))) ||
1400        (!movement_matrix[i] &&
1401 	(sign_one * (dial->gravity_x - dial->current_x) > sign_one * (dial->gravity_y - dial->current_y)))){
1402       gravity_up = TRUE;
1403       break;
1404     }
1405   }
1406 
1407   if(!gravity_up){
1408     if(gtk_adjustment_get_value(adjustment) > gtk_adjustment_get_lower(adjustment)){
1409       gtk_adjustment_set_value(adjustment,
1410 			       gtk_adjustment_get_value(adjustment) - gtk_adjustment_get_step_increment(adjustment));
1411 
1412       gtk_widget_queue_draw(dial);
1413     }
1414   }else{
1415     if(gtk_adjustment_get_value(adjustment) < gtk_adjustment_get_lower(adjustment)){
1416       gtk_adjustment_set_value(adjustment,
1417 			       gtk_adjustment_get_value(adjustment) + gtk_adjustment_get_step_increment(adjustment));
1418 
1419       gtk_widget_queue_draw(dial);
1420     }
1421   }
1422 }
1423 
1424 void
ags_dial_motion_notify_do_seemless_dial(AgsDial * dial,GdkEventMotion * event)1425 ags_dial_motion_notify_do_seemless_dial(AgsDial *dial,
1426 					GdkEventMotion *event)
1427 {
1428   GtkAdjustment *adjustment;
1429 
1430   GtkAllocation allocation;
1431 
1432   cairo_t *cr;
1433 
1434   gdouble button_width, button_height, margin_left, margin_right;
1435   gdouble radius, outline_strength;
1436   guint width, height;
1437   gdouble padding_left, padding_top;
1438   gdouble range;
1439   gdouble a0, quarter;
1440   gdouble x0, y0, x1, y1;
1441   gdouble translated_x;
1442   gboolean x_toggled, y_toggled;
1443 
1444   //TODO:JK: optimize me
1445   adjustment = dial->adjustment;
1446 
1447   range = (gtk_adjustment_get_upper(dial->adjustment) - gtk_adjustment_get_lower(dial->adjustment));
1448 
1449   if(range == 0.0){
1450     return;
1451   }
1452 
1453   gtk_widget_get_allocation(dial,
1454 			    &allocation);
1455 
1456   button_width = dial->button_width;
1457   button_height = dial->button_height;
1458 
1459   margin_left = (gdouble) dial->margin_left;
1460   margin_right = (gdouble) dial->margin_right;
1461 
1462   radius = (gdouble) dial->radius;
1463   outline_strength = (gdouble) dial->outline_strength;
1464 
1465   width = 2 * (button_height + radius + outline_strength + 2) + (margin_left + margin_right);
1466   height = 2 * (radius + outline_strength + 1);
1467 
1468   padding_top = (allocation.height - height) / 2;
1469   padding_left = (allocation.width - width) / 2;
1470 
1471   x1 = event->x - (1.0 + dial->button_width + dial->margin_left + radius + padding_left);
1472   y1 = event->y - (dial->outline_strength + radius + padding_top);
1473   y1 *= -1.0;
1474 
1475   x_toggled = FALSE;
1476   y_toggled = FALSE;
1477 
1478   if(x1 < 0.0){
1479     x_toggled = TRUE;
1480   }
1481 
1482   if(y1 < 0.0){
1483     y_toggled = TRUE;
1484   }
1485 
1486   if(radius == 0.0){
1487     return;
1488   }
1489 
1490   //FIXME:JK: ugly hack
1491   x1 = round(x1 + 1.0);
1492   y1 = round(y1 - 1.0);
1493 
1494   if(x1 == 0.0 &&
1495      y1 == 0.0){
1496     return;
1497   }else if(x1 == 0.0){
1498     a0 = 1.0;
1499 
1500 #if 0
1501     x0 = 0.0;
1502     y0 = 1.0 * radius;
1503 #endif
1504   }else if(y1 == 0.0){
1505     a0 = 0.0;
1506 
1507 #if 0
1508     x0 = 1.0 * radius;
1509     y0 = 0.0;
1510 #endif
1511   }else{
1512     a0 = y1 / x1;
1513 #if 0
1514     x0 = cos(a0) * radius;
1515     y0 = sin(a0) * radius;
1516 #endif
1517   }
1518 
1519   /* origin correction */
1520 #if 0
1521   if(x_toggled && y_toggled){
1522     if(x0 > 0.0){
1523       x0 *= -1.0;
1524     }
1525 
1526     if(y0 > 0.0){
1527       y0 *= -1.0;
1528     }
1529   }else if(y_toggled){
1530     if(x0 < 0.0){
1531       x0 *= -1.0;
1532     }
1533 
1534     if(y0 > 0.0){
1535       y0 *= -1.0;
1536     }
1537   }else if(x_toggled){
1538     if(y0 < 0.0){
1539       y0 *= -1.0;
1540     }
1541 
1542     if(x0 > 0.0){
1543       x0 *= -1.0;
1544     }
1545   }else{
1546     if(x0 < 0.0){
1547       x0 *= -1.0;
1548     }
1549 
1550     if(y0 < 0.0){
1551       y0 *= -1.0;
1552     }
1553   }
1554 #endif
1555 
1556   if(a0 > 2.0 * M_PI / 4.0){
1557     a0 = (2.0 * M_PI / 4.0);
1558   }else if(a0 < -2.0 * M_PI / 4.0){
1559     a0 = (-2.0 * M_PI / 4.0);
1560   }
1561 
1562   /* translated_x */
1563   translated_x = a0 * radius;
1564 
1565   quarter =  (2.0 * M_PI / 4.0) * radius;
1566 
1567   if(x_toggled && y_toggled){
1568     if(translated_x < 0.0){
1569       translated_x = quarter + translated_x;
1570     }else{
1571       translated_x = quarter - translated_x;
1572     }
1573   }else if(y_toggled){
1574     if(translated_x < 0.0){
1575       translated_x *= -1.0;
1576     }
1577 
1578     translated_x += 3.0 * quarter;
1579   }else if(x_toggled){
1580     if(translated_x < 0.0){
1581       translated_x *= -1.0;
1582     }
1583 
1584     translated_x += quarter;
1585   }else{
1586     if(translated_x < 0.0){
1587       translated_x = quarter + translated_x;
1588     }else{
1589       translated_x = quarter - translated_x;
1590     }
1591 
1592     translated_x += 2.0 * quarter;
1593   }
1594 
1595   translated_x = ((4.0 / 3.0) * range) / (4.0 * quarter) * translated_x;
1596   translated_x -= (range / 3.0 / 2.0);
1597   translated_x = gtk_adjustment_get_lower(adjustment) + translated_x;
1598 
1599   if(translated_x < gtk_adjustment_get_lower(adjustment)){
1600     translated_x = gtk_adjustment_get_lower(adjustment);
1601   }else if(translated_x > gtk_adjustment_get_upper(adjustment)){
1602     translated_x = gtk_adjustment_get_upper(adjustment);
1603   }
1604 
1605   gtk_adjustment_set_value(adjustment,
1606 			   translated_x);
1607   gtk_widget_queue_draw(dial);
1608 }
1609 
1610 gboolean
ags_dial_motion_notify(GtkWidget * widget,GdkEventMotion * event)1611 ags_dial_motion_notify(GtkWidget *widget,
1612 		       GdkEventMotion *event)
1613 {
1614   AgsDial *dial;
1615 
1616   GtkAllocation allocation;
1617 
1618   //  GTK_WIDGET_CLASS(ags_dial_parent_class)->motion_notify_event(widget, event);
1619   dial = AGS_DIAL(widget);
1620 
1621   gtk_widget_get_allocation(widget,
1622 			    &allocation);
1623 
1624   if((AGS_DIAL_MOTION_CAPTURING & (dial->flags)) != 0){
1625     if((AGS_DIAL_SEEMLESS_MODE & (dial->flags)) != 0){
1626       if((AGS_DIAL_MOTION_CAPTURING_INIT & (dial->flags)) != 0){
1627 	dial->current_x = event->x;
1628 	dial->current_y = event->y;
1629       }else{
1630 	dial->gravity_x = dial->current_x;
1631 	dial->gravity_y = dial->current_y;
1632 	dial->current_x = event->x;
1633 	dial->current_y = event->y;
1634       }
1635 
1636       ags_dial_motion_notify_do_seemless_dial(dial,
1637 					      event);
1638     }else{
1639       if((AGS_DIAL_MOTION_CAPTURING_INIT & (dial->flags)) != 0){
1640 	dial->current_x = event->x;
1641 	dial->current_y = event->y;
1642 
1643 	dial->flags &= (~AGS_DIAL_MOTION_CAPTURING_INIT);
1644 
1645 	ags_dial_motion_notify_do_dial(dial,
1646 				       event);
1647       }else{
1648 	dial->gravity_x = dial->current_x;
1649 	dial->gravity_y = dial->current_y;
1650 	dial->current_x = event->x;
1651 	dial->current_y = event->y;
1652 
1653 	ags_dial_motion_notify_do_dial(dial,
1654 				       event);
1655       }
1656     }
1657   }
1658 
1659   return(FALSE);
1660 }
1661 
1662 /**
1663  * ags_dial_draw:
1664  * @dial: an #AgsDial
1665  *
1666  * draws the widget
1667  *
1668  * Since: 3.0.0
1669  */
1670 gboolean
ags_dial_draw(AgsDial * dial,cairo_t * cr)1671 ags_dial_draw(AgsDial *dial, cairo_t *cr)
1672 {
1673   GtkWidget *widget;
1674 
1675   GtkStyleContext *dial_style_context;
1676 
1677   cairo_text_extents_t te_up, te_down;
1678 
1679   GtkAllocation allocation;
1680 
1681   GdkRGBA *fg_color;
1682   GdkRGBA *bg_color;
1683   GdkRGBA *border_color;
1684   GdkRGBA *font_color;
1685 
1686   gdouble button_width, button_height, margin_left, margin_right;
1687   gdouble radius, outline_strength;
1688   guint width, height;
1689   guint padding_top, padding_left;
1690   gdouble unused;
1691   gdouble scale_area, scale_width, scale_inverted_width;
1692   gdouble starter_angle;
1693   gdouble translated_value;
1694   gdouble range;
1695   guint scale_precision;
1696   guint i;
1697 
1698   GValue value = {0,};
1699 
1700   widget = GTK_WIDGET(dial);
1701 
1702   gtk_widget_get_allocation(GTK_WIDGET(dial),
1703 			    &allocation);
1704 
1705   /* style context */
1706   dial_style_context = gtk_widget_get_style_context(GTK_WIDGET(dial));
1707 
1708   gtk_style_context_get_property(dial_style_context,
1709 				 "color",
1710 				 GTK_STATE_FLAG_NORMAL,
1711 				 &value);
1712 
1713   fg_color = g_value_dup_boxed(&value);
1714   g_value_unset(&value);
1715 
1716   gtk_style_context_get_property(dial_style_context,
1717 				 "background-color",
1718 				 GTK_STATE_FLAG_NORMAL,
1719 				 &value);
1720 
1721   bg_color = g_value_dup_boxed(&value);
1722   g_value_unset(&value);
1723 
1724   gtk_style_context_get_property(dial_style_context,
1725 				 "border-color",
1726 				 GTK_STATE_FLAG_NORMAL,
1727 				 &value);
1728 
1729   border_color = g_value_dup_boxed(&value);
1730   g_value_unset(&value);
1731 
1732   gtk_style_context_get_property(dial_style_context,
1733 				 "font",
1734 				 GTK_STATE_FLAG_NORMAL,
1735 				 &value);
1736 
1737   font_color = g_value_dup_boxed(&value);
1738   g_value_unset(&value);
1739 
1740   /* dimension */
1741   button_width = dial->button_width;
1742   button_height = dial->button_height;
1743 
1744   margin_left = (gdouble) dial->margin_left;
1745   margin_right = (gdouble) dial->margin_right;
1746 
1747   radius = (gdouble) dial->radius;
1748   outline_strength = (gdouble) dial->outline_strength;
1749 
1750   width = 2 * (button_width + radius + outline_strength + 1);
1751   height = 2 * (radius + outline_strength + 1);
1752 
1753   padding_top = (allocation.height - height) / 2;
1754   padding_left = (allocation.width - width) / 2;
1755 
1756   /*  */
1757 //  cairo_surface_flush(cairo_get_target(cr));
1758   cairo_push_group(cr);
1759 
1760   /* clear bg */
1761 #if 0
1762   cairo_set_source_rgba(cr,
1763 			bg_color->red,
1764 			bg_color->green,
1765 			bg_color->blue,
1766 			bg_color->alpha);
1767 
1768   cairo_rectangle(cr,
1769 		  0.0, 0.0,
1770 		  (gdouble) allocation.width, (gdouble) allocation.height);
1771   cairo_fill(cr);
1772 #else
1773   gtk_render_background(dial_style_context,
1774 			cr,
1775 			0.0, 0.0,
1776 			(gdouble) allocation.width, (gdouble) allocation.height);
1777 #endif
1778 
1779   if((AGS_DIAL_WITH_BUTTONS & (dial->flags)) != 0){
1780     PangoLayout *layout;
1781     PangoFontDescription *desc;
1782 
1783     PangoRectangle ink_rect, logical_rect;
1784 
1785     gchar *font_name;
1786 
1787     static const gchar *text = "-";
1788 
1789     g_object_get(gtk_settings_get_default(),
1790 		 "gtk-font-name", &font_name,
1791 		 NULL);
1792 
1793     /* draw controller button down */
1794     cairo_set_source_rgba(cr,
1795 			  border_color->red,
1796 			  border_color->green,
1797 			  border_color->blue,
1798 			  border_color->alpha);
1799 
1800     cairo_set_line_width(cr, 2.0);
1801 
1802     cairo_rectangle(cr,
1803 		    (gdouble) padding_left + 1.0, (gdouble) padding_top + (2.0 * radius) - button_height + outline_strength,
1804 		    (gdouble) button_width, (gdouble) button_height);
1805     cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1806     cairo_stroke(cr);
1807 
1808     /* text */
1809 #if 0
1810     cairo_set_source_rgba(cr,
1811 			  font_color->red,
1812 			  font_color->green,
1813 			  font_color->blue,
1814 			  font_color->alpha);
1815 #else
1816     cairo_set_source_rgba(cr,
1817 			  fg_color->red,
1818 			  fg_color->green,
1819 			  fg_color->blue,
1820 			  fg_color->alpha);
1821 #endif
1822 
1823     layout = pango_cairo_create_layout(cr);
1824     pango_layout_set_text(layout,
1825 			  text,
1826 			  -1);
1827     desc = pango_font_description_from_string(font_name);
1828     pango_font_description_set_size(desc,
1829 				    dial->font_size * PANGO_SCALE);
1830     pango_layout_set_font_description(layout,
1831 				      desc);
1832     pango_font_description_free(desc);
1833 
1834     pango_layout_get_extents(layout,
1835 			      &ink_rect,
1836 			      &logical_rect);
1837 
1838     cairo_move_to(cr,
1839 		  padding_left + 1.0 + 0.5 - (logical_rect.width / PANGO_SCALE) / 2.0 + button_width / 2.25,
1840 		  padding_top + 0.5 - (logical_rect.height / PANGO_SCALE) / 2.0 + (radius * 2.0) - button_height / 2.0 + outline_strength - 1.0);
1841 
1842     pango_cairo_show_layout(cr,
1843 			    layout);
1844 
1845     g_object_unref(layout);
1846 
1847     g_free(font_name);
1848   }
1849 
1850   if((AGS_DIAL_WITH_BUTTONS & (dial->flags)) != 0){
1851     PangoLayout *layout;
1852     PangoFontDescription *desc;
1853 
1854     PangoRectangle ink_rect, logical_rect;
1855 
1856     gchar *font_name;
1857 
1858     static const gchar *text = "+";
1859 
1860     g_object_get(gtk_settings_get_default(),
1861 		 "gtk-font-name", &font_name,
1862 		 NULL);
1863 
1864     /* draw controller button up */
1865     cairo_set_source_rgba(cr,
1866 			  border_color->red,
1867 			  border_color->green,
1868 			  border_color->blue,
1869 			  border_color->alpha);
1870 
1871     cairo_set_line_width(cr, 2.0);
1872 
1873     cairo_rectangle(cr,
1874 		    padding_left + 1.0 + (2.0 * radius) + button_width + margin_left + margin_right, padding_top + (2.0 * radius) - button_height + outline_strength,
1875 		    button_width, button_height);
1876     cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1877     cairo_stroke(cr);
1878 
1879     /* text */
1880 #if 0
1881     cairo_set_source_rgba(cr,
1882 			  font_color->red,
1883 			  font_color->green,
1884 			  font_color->blue,
1885 			  font_color->alpha);
1886 #else
1887     cairo_set_source_rgba(cr,
1888 			  fg_color->red,
1889 			  fg_color->green,
1890 			  fg_color->blue,
1891 			  fg_color->alpha);
1892 #endif
1893 
1894     layout = pango_cairo_create_layout(cr);
1895     pango_layout_set_text(layout,
1896 			  text,
1897 			  -1);
1898     desc = pango_font_description_from_string(font_name);
1899     pango_font_description_set_size(desc,
1900 				    dial->font_size * PANGO_SCALE);
1901     pango_layout_set_font_description(layout,
1902 				      desc);
1903     pango_font_description_free(desc);
1904 
1905     pango_layout_get_extents(layout,
1906 			      &ink_rect,
1907 			      &logical_rect);
1908 
1909     cairo_move_to(cr,
1910 		  padding_left + 1.0 + 0.5 - (logical_rect.width / PANGO_SCALE) / 2.0 + (radius * 2.0) + margin_left + margin_right + button_width + button_width / 2.25,
1911 		  padding_top + 0.5 - (logical_rect.height / PANGO_SCALE) / 2.0 + (radius * 2.0) - button_height / 2.0 + outline_strength - 1.0);
1912 
1913     pango_cairo_show_layout(cr,
1914 			    layout);
1915 
1916     g_object_unref(layout);
1917 
1918     g_free(font_name);
1919   }
1920 
1921   /* border fill * /
1922   cairo_set_source_rgb(cr,
1923 		       dial_style->fg[0].red / white_gc,
1924 		       dial_style->fg[0].green / white_gc,
1925 		       dial_style->fg[0].blue / white_gc);
1926   cairo_arc(cr,
1927 	    1.0 + button_width + margin_left + radius,
1928 	    radius + outline_strength,
1929 	    radius + 2.0,
1930 	    -1.0 * M_PI,
1931 	    1.0 * M_PI);
1932   cairo_stroke(cr);
1933   */
1934 
1935   /* dial disk */
1936   cairo_set_source_rgba(cr,
1937 			bg_color->red,
1938 			bg_color->green,
1939 			bg_color->blue,
1940 			bg_color->alpha);
1941 
1942   cairo_arc(cr,
1943 	    padding_left + 1.0 + button_width + margin_left + radius,
1944 	    padding_top + radius + outline_strength,
1945 	    radius + outline_strength - 1.25,
1946 	    -1.0 * M_PI,
1947 	    1.0 * M_PI);
1948   cairo_fill(cr);
1949 
1950   /* dial disk border */
1951   cairo_set_source_rgba(cr,
1952 			border_color->red,
1953 			border_color->green,
1954 			border_color->blue,
1955 			border_color->alpha);
1956 
1957   cairo_arc(cr,
1958 	    padding_left + 1.0 + button_width + margin_left + radius,
1959 	    padding_top + radius + outline_strength,
1960 	    radius,
1961 	    -1.0 * M_PI,
1962 	    1.0 * M_PI);
1963   cairo_stroke(cr);
1964 
1965   /* light effect */
1966   if((AGS_DIAL_INVERSE_LIGHT & (dial->flags)) != 0){
1967     cairo_set_source_rgba(cr,
1968 			  0.0,
1969 			  0.0,
1970 			  0.0,
1971 			  1.0 / 3.0);
1972   }else{
1973     cairo_set_source_rgba(cr,
1974 			  1.0,
1975 			  1.0,
1976 			  1.0,
1977 			  1.0 / 3.0);
1978   }
1979 
1980   cairo_line_to(cr,
1981 		padding_left + 1.0 + button_width + margin_left + radius,
1982 		padding_top + radius + 2.0 * outline_strength - 2.0 - outline_strength);
1983   cairo_line_to(cr,
1984 		padding_left + 1.0 + sin(-1 * (0.35 * M_PI) / (0.65 * M_PI)) + button_width + margin_left + radius,
1985 		padding_top + cos((0.65 * M_PI) / (0.35 * M_PI)) + radius + 2.0 * outline_strength - 1.0);
1986   cairo_line_to(cr,
1987 		padding_left + 1.0 + sin((0.65 * M_PI) / (0.35 * M_PI)) + button_width + margin_left + radius,
1988 		padding_top + -1 * cos((0.35 * M_PI) / (0.65 * M_PI)) + radius + 2.0 * outline_strength - 1.0);
1989   cairo_close_path(cr);
1990 
1991   cairo_arc(cr,
1992 	    padding_left + 1.0 + button_width + margin_left + radius,
1993 	    padding_top + radius + outline_strength,
1994 	    radius,
1995 	    0.35 * M_PI,
1996 	    0.65 * M_PI);
1997   cairo_fill(cr);
1998 
1999   cairo_line_to(cr,
2000 		padding_left + 1.0 + cos((0.65 * M_PI) / (0.35 * M_PI)) + button_width + margin_left + radius,
2001 		padding_top + -1 * sin((0.35 * M_PI) / (0.65 * M_PI)) + radius + 2.0 * outline_strength - 1.0);
2002   cairo_line_to(cr,
2003 		padding_left + 1.0 + -1 * cos((0.35 * M_PI) / (0.65 * M_PI)) + button_width + margin_left + radius,
2004 		padding_top + sin((0.65 * M_PI) / (0.35 * M_PI)) + radius + 2.0 * outline_strength - 1.0);
2005   cairo_line_to(cr,
2006 		padding_left + 1.0 + button_width + margin_left + radius,
2007 		padding_top + radius + 2.0 * outline_strength - 1.0);
2008   cairo_close_path(cr);
2009 
2010   cairo_arc(cr,
2011 	    padding_left + 1.0 + button_width + margin_left + radius,
2012 	    padding_top + radius + outline_strength,
2013 	    radius,
2014 	    -0.65 * M_PI,
2015 	    -0.35 * M_PI);
2016   cairo_fill(cr);
2017 
2018   /* outline */
2019   cairo_set_source_rgba(cr,
2020 			0.0,
2021 			0.0,
2022 			0.0,
2023 			1.0);
2024 
2025   //  cairo_set_line_width(cr, 1.0 - (2.0 / M_PI));
2026   cairo_set_line_width(cr, 1.0);
2027   cairo_arc(cr,
2028 	    padding_left + 1.0 + button_width + margin_left + radius,
2029 	    padding_top + radius + outline_strength,
2030 	    radius,
2031 	    -1.0 * M_PI,
2032 	    1.0 * M_PI);
2033   cairo_stroke(cr);
2034 
2035   /* scale */
2036   cairo_set_source_rgba(cr,
2037 			fg_color->red,
2038 			fg_color->green,
2039 			fg_color->blue,
2040 			fg_color->alpha);
2041 
2042   cairo_set_line_width(cr, 3.0);
2043 
2044   unused = 0.25 * 2.0 * M_PI;
2045   starter_angle = (2.0 * M_PI - unused) * 0.5;
2046 
2047   scale_precision = (gdouble) dial->scale_precision;
2048   scale_inverted_width = (2.0 * (radius + outline_strength) * M_PI - ((radius + outline_strength) * unused)) / scale_precision - 4.0;
2049   scale_width = (2.0 * (radius + outline_strength) * M_PI - ((radius + outline_strength) * unused)) / scale_precision - scale_inverted_width;
2050 
2051   scale_inverted_width /= (radius + outline_strength);
2052   scale_width /= (radius + outline_strength);
2053 
2054   for(i = 0; i <= scale_precision; i++){
2055     cairo_arc(cr,
2056 	      padding_left + 1.0 + button_width + margin_left + radius,
2057 	      padding_top + radius + outline_strength,
2058 	      radius + outline_strength / M_PI,
2059 	      starter_angle + ((gdouble) i * scale_inverted_width) + ((gdouble) i * scale_width),
2060 	      starter_angle + ((gdouble) i * scale_inverted_width) + ((gdouble) i * scale_width) + scale_width);
2061     cairo_stroke(cr);
2062   }
2063 
2064   /* draw value */
2065   range = (gtk_adjustment_get_upper(dial->adjustment) - gtk_adjustment_get_lower(dial->adjustment));
2066 
2067   if(range != 0.0 &&
2068      gtk_adjustment_get_upper(dial->adjustment) > gtk_adjustment_get_lower(dial->adjustment)){
2069     /* this is odd */
2070     translated_value = (gtk_adjustment_get_value(dial->adjustment) - gtk_adjustment_get_lower(dial->adjustment));
2071     translated_value = (gdouble) scale_precision * (translated_value / range);
2072 
2073     //  g_message("value: %f\nupper: %f\ntranslated_value: %f\n", GTK_RANGE(dial)->adjustment->value, GTK_RANGE(dial)->adjustment->upper, translated_value);
2074     cairo_set_line_width(cr, 4.0);
2075     cairo_set_source_rgba(cr,
2076 			  fg_color->red,
2077 			  fg_color->green,
2078 			  fg_color->blue,
2079 			  fg_color->alpha);
2080 
2081     cairo_arc(cr,
2082 	      padding_left + 1.0 + button_width + margin_left + radius,
2083 	      padding_top + radius + outline_strength,
2084 	      radius - (outline_strength + 4.0) / M_PI,
2085 	      starter_angle + (translated_value * scale_inverted_width) + (translated_value * scale_width),
2086 	      starter_angle + (translated_value * scale_inverted_width) + (translated_value * scale_width) + scale_width);
2087     cairo_stroke(cr);
2088   }else{
2089     g_warning("ags_dial.c - invalid range");
2090   }
2091 
2092   cairo_pop_group_to_source(cr);
2093   cairo_paint(cr);
2094 
2095   g_boxed_free(GDK_TYPE_RGBA, fg_color);
2096   g_boxed_free(GDK_TYPE_RGBA, bg_color);
2097   g_boxed_free(GDK_TYPE_RGBA, border_color);
2098   g_boxed_free(GDK_TYPE_RGBA, font_color);
2099 //  cairo_surface_mark_dirty(cairo_get_target(cr));
2100 
2101   return(FALSE);
2102 }
2103 
2104 /**
2105  * ags_dial_set_radius:
2106  * @dial: the #AgsDial
2107  * @radius: the radius
2108  *
2109  * Set radius of @dial.
2110  *
2111  * Since: 3.2.0
2112  */
2113 void
ags_dial_set_radius(AgsDial * dial,guint radius)2114 ags_dial_set_radius(AgsDial *dial,
2115 		    guint radius)
2116 {
2117   if(!AGS_IS_DIAL(dial)){
2118     return;
2119   }
2120 
2121   g_object_set(dial,
2122 	       "radius", radius,
2123 	       NULL);
2124 }
2125 
2126 /**
2127  * ags_dial_get_radius:
2128  * @dial: the #AgsDial
2129  *
2130  * Get radius of @dial.
2131  *
2132  * Returns: the radius
2133  *
2134  * Since: 3.2.0
2135  */
2136 guint
ags_dial_get_radius(AgsDial * dial)2137 ags_dial_get_radius(AgsDial *dial)
2138 {
2139   guint radius;
2140 
2141   if(!AGS_IS_DIAL(dial)){
2142     return(0);
2143   }
2144 
2145   g_object_get(dial,
2146 	       "radius", &radius,
2147 	       NULL);
2148 
2149   return(radius);
2150 }
2151 
2152 /**
2153  * ags_dial_set_outline_strength:
2154  * @dial: the #AgsDial
2155  * @outline_strength: the outline strength
2156  *
2157  * Set outline strength of @dial.
2158  *
2159  * Since: 3.2.0
2160  */
2161 void
ags_dial_set_outline_strength(AgsDial * dial,guint outline_strength)2162 ags_dial_set_outline_strength(AgsDial *dial,
2163 			      guint outline_strength)
2164 {
2165   if(!AGS_IS_DIAL(dial)){
2166     return;
2167   }
2168 
2169   g_object_set(dial,
2170 	       "outline-strength", outline_strength,
2171 	       NULL);
2172 }
2173 
2174 /**
2175  * ags_dial_get_outline_strength:
2176  * @dial: the #AgsDial
2177  *
2178  * Get outline strength of @dial.
2179  *
2180  * Returns: the outline _strength
2181  *
2182  * Since: 3.2.0
2183  */
2184 guint
ags_dial_get_outline_strength(AgsDial * dial)2185 ags_dial_get_outline_strength(AgsDial *dial)
2186 {
2187   guint outline_strength;
2188 
2189   if(!AGS_IS_DIAL(dial)){
2190     return(0);
2191   }
2192 
2193   g_object_get(dial,
2194 	       "outline-strength", &outline_strength,
2195 	       NULL);
2196 
2197   return(outline_strength);
2198 }
2199 
2200 /**
2201  * ags_dial_set_scale_precision:
2202  * @dial: the #AgsDial
2203  * @scale_precision: the scale precision
2204  *
2205  * Set scale precision of @dial.
2206  *
2207  * Since: 3.2.0
2208  */
2209 void
ags_dial_set_scale_precision(AgsDial * dial,guint scale_precision)2210 ags_dial_set_scale_precision(AgsDial *dial,
2211 			     guint scale_precision)
2212 {
2213   if(!AGS_IS_DIAL(dial)){
2214     return;
2215   }
2216 
2217   g_object_set(dial,
2218 	       "scale-precision", scale_precision,
2219 	       NULL);
2220 }
2221 
2222 /**
2223  * ags_dial_get_scale_precision:
2224  * @dial: the #AgsDial
2225  *
2226  * Get scale precision of @dial.
2227  *
2228  * Returns: the scale precision
2229  *
2230  * Since: 3.2.0
2231  */
2232 guint
ags_dial_get_scale_precision(AgsDial * dial)2233 ags_dial_get_scale_precision(AgsDial *dial)
2234 {
2235   guint scale_precision;
2236 
2237   if(!AGS_IS_DIAL(dial)){
2238     return(0);
2239   }
2240 
2241   g_object_get(dial,
2242 	       "scale-precision", &scale_precision,
2243 	       NULL);
2244 
2245   return(scale_precision);
2246 }
2247 
2248 /**
2249  * ags_dial_set_font_size:
2250  * @dial: the #AgsDial
2251  * @font_size: the font size
2252  *
2253  * Set font size of @dial.
2254  *
2255  * Since: 3.2.0
2256  */
2257 void
ags_dial_set_font_size(AgsDial * dial,guint font_size)2258 ags_dial_set_font_size(AgsDial *dial,
2259 		       guint font_size)
2260 {
2261   if(!AGS_IS_DIAL(dial)){
2262     return;
2263   }
2264 
2265   g_object_set(dial,
2266 	       "font-size", font_size,
2267 	       NULL);
2268 }
2269 
2270 /**
2271  * ags_dial_get_font_size:
2272  * @dial: the #AgsDial
2273  *
2274  * Get font size of @dial.
2275  *
2276  * Returns: the font size
2277  *
2278  * Since: 3.2.0
2279  */
2280 guint
ags_dial_get_font_size(AgsDial * dial)2281 ags_dial_get_font_size(AgsDial *dial)
2282 {
2283   guint font_size;
2284 
2285   if(!AGS_IS_DIAL(dial)){
2286     return(0);
2287   }
2288 
2289   g_object_get(dial,
2290 	       "font-size", &font_size,
2291 	       NULL);
2292 
2293   return(font_size);
2294 }
2295 
2296 /**
2297  * ags_dial_set_button_width:
2298  * @dial: the #AgsDial
2299  * @button_width: the button width
2300  *
2301  * Set button width of @dial.
2302  *
2303  * Since: 3.2.0
2304  */
2305 void
ags_dial_set_button_width(AgsDial * dial,gint button_width)2306 ags_dial_set_button_width(AgsDial *dial,
2307 			  gint button_width)
2308 {
2309   if(!AGS_IS_DIAL(dial)){
2310     return;
2311   }
2312 
2313   g_object_set(dial,
2314 	       "button-width", button_width,
2315 	       NULL);
2316 }
2317 
2318 /**
2319  * ags_dial_get_button_width:
2320  * @dial: the #AgsDial
2321  *
2322  * Get button width of @dial.
2323  *
2324  * Returns: the button width
2325  *
2326  * Since: 3.2.0
2327  */
2328 gint
ags_dial_get_button_width(AgsDial * dial)2329 ags_dial_get_button_width(AgsDial *dial)
2330 {
2331   gint button_width;
2332 
2333   if(!AGS_IS_DIAL(dial)){
2334     return(-1);
2335   }
2336 
2337   g_object_get(dial,
2338 	       "button-width", &button_width,
2339 	       NULL);
2340 
2341   return(button_width);
2342 }
2343 
2344 /**
2345  * ags_dial_set_button_height:
2346  * @dial: the #AgsDial
2347  * @button_height: the button height
2348  *
2349  * Set button height of @dial.
2350  *
2351  * Since: 3.2.0
2352  */
2353 void
ags_dial_set_button_height(AgsDial * dial,gint button_height)2354 ags_dial_set_button_height(AgsDial *dial,
2355 			   gint button_height)
2356 {
2357   if(!AGS_IS_DIAL(dial)){
2358     return;
2359   }
2360 
2361   g_object_set(dial,
2362 	       "button-height", button_height,
2363 	       NULL);
2364 }
2365 
2366 /**
2367  * ags_dial_get_button_height:
2368  * @dial: the #AgsDial
2369  *
2370  * Get button height of @dial.
2371  *
2372  * Returns: the button height
2373  *
2374  * Since: 3.2.0
2375  */
2376 gint
ags_dial_get_button_height(AgsDial * dial)2377 ags_dial_get_button_height(AgsDial *dial)
2378 {
2379   gint button_height;
2380 
2381   if(!AGS_IS_DIAL(dial)){
2382     return(-1);
2383   }
2384 
2385   g_object_get(dial,
2386 	       "button-height", &button_height,
2387 	       NULL);
2388 
2389   return(button_height);
2390 }
2391 
2392 /**
2393  * ags_dial_set_margin_left:
2394  * @dial: the #AgsDial
2395  * @margin_left: the margin left
2396  *
2397  * Set margin left of @dial.
2398  *
2399  * Since: 3.2.0
2400  */
2401 void
ags_dial_set_margin_left(AgsDial * dial,gint margin_left)2402 ags_dial_set_margin_left(AgsDial *dial,
2403 			 gint margin_left)
2404 {
2405   if(!AGS_IS_DIAL(dial)){
2406     return;
2407   }
2408 
2409   g_object_set(dial,
2410 	       "margin-left", margin_left,
2411 	       NULL);
2412 }
2413 
2414 /**
2415  * ags_dial_get_margin_left:
2416  * @dial: the #AgsDial
2417  *
2418  * Get margin_left of @dial.
2419  *
2420  * Returns: the margin left
2421  *
2422  * Since: 3.2.0
2423  */
2424 gint
ags_dial_get_margin_left(AgsDial * dial)2425 ags_dial_get_margin_left(AgsDial *dial)
2426 {
2427   gint margin_left;
2428 
2429   if(!AGS_IS_DIAL(dial)){
2430     return(-1);
2431   }
2432 
2433   g_object_set(dial,
2434 	       "margin-left", &margin_left,
2435 	       NULL);
2436 
2437   return(margin_left);
2438 }
2439 
2440 /**
2441  * ags_dial_set_margin_right:
2442  * @dial: the #AgsDial
2443  * @margin_right: the margin right
2444  *
2445  * Set margin right of @dial.
2446  *
2447  * Since: 3.2.0
2448  */
2449 void
ags_dial_set_margin_right(AgsDial * dial,gint margin_right)2450 ags_dial_set_margin_right(AgsDial *dial,
2451 			  gint margin_right)
2452 {
2453   if(!AGS_IS_DIAL(dial)){
2454     return;
2455   }
2456 
2457   g_object_set(dial,
2458 	       "margin-right", margin_right,
2459 	       NULL);
2460 }
2461 
2462 /**
2463  * ags_dial_get_margin_right:
2464  * @dial: the #AgsDial
2465  *
2466  * Get margin right of @dial.
2467  *
2468  * Returns: the margin right
2469  *
2470  * Since: 3.2.0
2471  */
2472 gint
ags_dial_get_margin_right(AgsDial * dial)2473 ags_dial_get_margin_right(AgsDial *dial)
2474 {
2475   gint margin_right;
2476 
2477   if(!AGS_IS_DIAL(dial)){
2478     return(-1);
2479   }
2480 
2481   g_object_get(dial,
2482 	       "margin-right", &margin_right,
2483 	       NULL);
2484 
2485   return(margin_right);
2486 }
2487 
2488 /**
2489  * ags_dial_set_adjustment:
2490  * @dial: the #AgsDial
2491  * @adjustment: (transfer none): the #GtkAdjustment
2492  *
2493  * Set adjustment of @dial.
2494  *
2495  * Since: 3.2.0
2496  */
2497 void
ags_dial_set_adjustment(AgsDial * dial,GtkAdjustment * adjustment)2498 ags_dial_set_adjustment(AgsDial *dial,
2499 			GtkAdjustment *adjustment)
2500 {
2501   if(!AGS_IS_DIAL(dial)){
2502     return;
2503   }
2504 
2505   g_object_set(dial,
2506 	       "adjustment", adjustment,
2507 	       NULL);
2508 }
2509 
2510 /**
2511  * ags_dial_get_adjustment:
2512  * @dial: the #AgsDial
2513  *
2514  * Get adjustment of @dial.
2515  *
2516  * Returns: (transfer full): the #GtkAdjustment
2517  *
2518  * Since: 3.2.0
2519  */
2520 GtkAdjustment*
ags_dial_get_adjustment(AgsDial * dial)2521 ags_dial_get_adjustment(AgsDial *dial)
2522 {
2523   GtkAdjustment *adjustment;
2524 
2525   if(!AGS_IS_DIAL(dial)){
2526     return(NULL);
2527   }
2528 
2529   g_object_get(dial,
2530 	       "adjustment", &adjustment,
2531 	       NULL);
2532 
2533   return(adjustment);
2534 }
2535 
2536 /**
2537  * ags_dial_value_changed:
2538  * @dial: an #AgsDial
2539  *
2540  * draws the widget
2541  *
2542  * Since: 3.0.0
2543  */
2544 void
ags_dial_value_changed(AgsDial * dial)2545 ags_dial_value_changed(AgsDial *dial)
2546 {
2547   g_return_if_fail(AGS_IS_DIAL(dial));
2548 
2549   g_object_ref((GObject *) dial);
2550   g_signal_emit(G_OBJECT(dial),
2551 		dial_signals[VALUE_CHANGED], 0);
2552   g_object_unref((GObject *) dial);
2553 }
2554 
2555 void
ags_dial_adjustment_changed_callback(GtkAdjustment * adjustment,AgsDial * dial)2556 ags_dial_adjustment_changed_callback(GtkAdjustment *adjustment,
2557 				     AgsDial *dial)
2558 {
2559   ags_dial_value_changed(dial);
2560 }
2561 
2562 /**
2563  * ags_dial_set_value:
2564  * @dial: an #AgsDial
2565  * @value: the value to set
2566  *
2567  * Set value
2568  *
2569  * Since: 3.0.0
2570  */
2571 void
ags_dial_set_value(AgsDial * dial,gdouble value)2572 ags_dial_set_value(AgsDial *dial,
2573 		   gdouble value)
2574 {
2575   if(!AGS_IS_DIAL(dial)){
2576     return;
2577   }
2578 
2579   gtk_adjustment_set_value(dial->adjustment,
2580 			   value);
2581   gtk_widget_queue_draw((GtkWidget *) dial);
2582 }
2583 
2584 /**
2585  * ags_dial_new:
2586  *
2587  * Creates an #AgsDial
2588  *
2589  * Returns: a new #AgsDial
2590  *
2591  * Since: 3.0.0
2592  */
2593 AgsDial*
ags_dial_new()2594 ags_dial_new()
2595 {
2596   AgsDial *dial;
2597   GtkAdjustment *adjustment;
2598 
2599   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
2600 
2601   dial = (AgsDial *) g_object_new(AGS_TYPE_DIAL,
2602 				  "adjustment", adjustment,
2603 				  NULL);
2604 
2605   return(dial);
2606 }
2607