6 /******************************************************************************
7 *******************************************************************************
12 *******************************************************************************
13 *******************************************************************************/
22 #include <gdk/gdkkeysyms.h>
27 #define max(x,y) (((x)>(y)) ? (x) : (y))
28 #define min(x,y) (((x)<(y)) ? (x) : (y))
38 //------------ calculate needed precision
39 static int precision(double n
)
41 if (n
< 0.009999) return 3;
42 else if (n
< 0.099999) return 2;
43 else if (n
< 0.999999) return 1;
53 double start_x
, start_y
, max_value
;
59 GtkWidget
*gtk_knob_new_with_adjustment(GtkAdjustment
*_adjustment
);
63 #define GTK_TYPE_KNOB (gtk_knob_get_type())
64 #define GTK_KNOB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_KNOB, GtkKnob))
65 #define GTK_IS_KNOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_KNOB))
66 #define GTK_KNOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_KNOB, GtkKnobClass))
67 #define GTK_IS_KNOB_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_KNOB))
70 // GtkKnob constructor
77 // Nothing specific to do...
81 GtkRangeClass parent_class
;
89 //------forward declaration
90 GType
gtk_knob_get_type ();
92 /****************************************************************
93 ** calculate the knop pointer with dead zone
96 const double scale_zero
= 20 * (M_PI
/180); // defines "dead zone" for knobs
98 static void knob_expose(GtkWidget
*widget
, int knob_x
, int knob_y
, GdkEventExpose
*event
, int arc_offset
)
102 if(widget
->allocation
.width
> widget
->allocation
.height
) {
103 grow
= widget
->allocation
.height
;
105 grow
= widget
->allocation
.width
;
109 /** get values for the knob **/
110 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(widget
));
111 int knobx
= (widget
->allocation
.x
+2 + (widget
->allocation
.width
-4 - knob_x
) * 0.5);
112 int knoby
= (widget
->allocation
.y
+2 + (widget
->allocation
.height
-4 - knob_y
) * 0.5);
113 int knobx1
= (widget
->allocation
.x
+2 + (widget
->allocation
.width
-4)* 0.5);
114 int knoby1
= (widget
->allocation
.y
+2 + (widget
->allocation
.height
-4) * 0.5);
115 double knobstate
= (adj
->value
- adj
->lower
) / (adj
->upper
- adj
->lower
);
116 double angle
= scale_zero
+ knobstate
* 2 * (M_PI
- scale_zero
);
117 double knobstate1
= (0. - adj
->lower
) / (adj
->upper
- adj
->lower
);
118 double pointer_off
= knob_x
/6;
119 double radius
= min(knob_x
-pointer_off
, knob_y
-pointer_off
) / 2;
120 double lengh_x
= (knobx
+radius
+pointer_off
/2) - radius
* sin(angle
);
121 double lengh_y
= (knoby
+radius
+pointer_off
/2) + radius
* cos(angle
);
122 double radius1
= min(knob_x
, knob_y
) / 2 ;
124 /** get widget forground color convert to cairo **/
125 GtkStyle
*style
= gtk_widget_get_style (widget
);
126 double r
= min(0.6,style
->fg
[gtk_widget_get_state(widget
)].red
/65535.0),
127 g
= min(0.6,style
->fg
[gtk_widget_get_state(widget
)].green
/65535.0),
128 b
= min(0.6,style
->fg
[gtk_widget_get_state(widget
)].blue
/65535.0);
131 if (GTK_WIDGET_HAS_FOCUS(widget
)== TRUE
) {
132 gtk_paint_focus(widget
->style
, widget
->window
, GTK_STATE_NORMAL
, NULL
, widget
, NULL
,
133 knobx
-2, knoby
-2, knob_x
+4, knob_y
+4);
135 /** create clowing knobs with cairo **/
136 cairo_t
*cr
= gdk_cairo_create(GDK_DRAWABLE(widget
->window
));
138 region
= gdk_region_rectangle (&widget
->allocation
);
139 gdk_region_intersect (region
, event
->region
);
140 gdk_cairo_region (cr
, region
);
143 cairo_arc(cr
,knobx1
+arc_offset
, knoby1
+arc_offset
, knob_x
/2.1, 0, 2 * M_PI
);
144 cairo_pattern_t
*pat
=
145 cairo_pattern_create_radial (knobx1
+arc_offset
-knob_x
/6,knoby1
+arc_offset
-knob_x
/6, 1,knobx1
+arc_offset
,knoby1
+arc_offset
,knob_x
/2.1 );
146 if(adj
->lower
<0 && adj
->value
>0.) {
147 cairo_pattern_add_color_stop_rgb (pat
, 0, r
+0.4, g
+0.4 + knobstate
-knobstate1
, b
+0.4);
148 cairo_pattern_add_color_stop_rgb (pat
, 0.7, r
+0.15, g
+0.15 + (knobstate
-knobstate1
)*0.5, b
+0.15);
149 cairo_pattern_add_color_stop_rgb (pat
, 1, r
, g
, b
);
150 } else if(adj
->lower
<0 && adj
->value
<=0.) {
151 cairo_pattern_add_color_stop_rgb (pat
, 0, r
+0.4 +knobstate1
- knobstate
, g
+0.4, b
+0.4);
152 cairo_pattern_add_color_stop_rgb (pat
, 0.7, r
+0.15 +(knobstate1
- knobstate
)*0.5, g
+0.15, b
+0.15);
153 cairo_pattern_add_color_stop_rgb (pat
, 1, r
, g
, b
);
155 cairo_pattern_add_color_stop_rgb (pat
, 0, r
+0.4, g
+0.4 +knobstate
, b
+0.4);
156 cairo_pattern_add_color_stop_rgb (pat
, 0.7, r
+0.15, g
+0.15 + knobstate
*0.5, b
+0.15);
157 cairo_pattern_add_color_stop_rgb (pat
, 1, r
, g
, b
);
159 cairo_set_source (cr
, pat
);
160 cairo_fill_preserve (cr
);
161 gdk_cairo_set_source_color(cr
, gtk_widget_get_style (widget
)->fg
);
162 cairo_set_line_width(cr
, 2.0);
165 /** create a rotating pointer on the kob**/
166 cairo_set_source_rgb(cr
, 0.1, 0.1, 0.1);
167 cairo_set_line_width(cr
,max(3, min(7, knob_x
/15)));
168 cairo_set_line_cap(cr
, CAIRO_LINE_CAP_ROUND
);
169 cairo_set_line_join(cr
, CAIRO_LINE_JOIN_BEVEL
);
170 cairo_move_to(cr
, knobx
+radius1
, knoby
+radius1
);
171 cairo_line_to(cr
,lengh_x
,lengh_y
);
173 cairo_set_source_rgb(cr
, 0.9, 0.9, 0.9);
174 cairo_set_line_width(cr
,min(5, max(1,knob_x
/30)));
175 cairo_move_to(cr
, knobx
+radius1
, knoby
+radius1
);
176 cairo_line_to(cr
,lengh_x
,lengh_y
);
178 cairo_pattern_destroy (pat
);
179 gdk_region_destroy (region
);
183 /****************************************************************
184 ** general expose events for all "knob" controllers
187 //----------- draw the Knob when moved
188 static gboolean
gtk_knob_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
190 g_assert(GTK_IS_KNOB(widget
));
191 GtkKnobClass
*klass
= GTK_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget
));
192 knob_expose(widget
, klass
->knob_x
, klass
->knob_y
, event
, 0);
196 /****************************************************************
197 ** set initial size for GdkDrawable per type
200 static void gtk_knob_size_request (GtkWidget
*widget
, GtkRequisition
*requisition
)
202 g_assert(GTK_IS_KNOB(widget
));
203 GtkKnobClass
*klass
= GTK_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget
));
204 requisition
->width
= klass
->knob_x
;
205 requisition
->height
= klass
->knob_y
;
208 /****************************************************************
209 ** set value from key bindings
212 static void gtk_knob_set_value (GtkWidget
*widget
, int dir_down
)
214 g_assert(GTK_IS_KNOB(widget
));
216 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(widget
));
218 int oldstep
= (int)(0.5f
+ (adj
->value
- adj
->lower
) / adj
->step_increment
);
220 int nsteps
= (int)(0.5f
+ (adj
->upper
- adj
->lower
) / adj
->step_increment
);
225 float value
= adj
->lower
+ step
* double(adj
->upper
- adj
->lower
) / nsteps
;
226 gtk_widget_grab_focus(widget
);
227 gtk_range_set_value(GTK_RANGE(widget
), value
);
230 /****************************************************************
234 static gboolean
gtk_knob_key_press (GtkWidget
*widget
, GdkEventKey
*event
)
236 g_assert(GTK_IS_KNOB(widget
));
238 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(widget
));
239 switch (event
->keyval
) {
241 gtk_range_set_value(GTK_RANGE(widget
), adj
->lower
);
244 gtk_range_set_value(GTK_RANGE(widget
), adj
->upper
);
247 gtk_knob_set_value(widget
, 0);
250 gtk_knob_set_value(widget
, 0);
253 gtk_knob_set_value(widget
, 1);
256 gtk_knob_set_value(widget
, 1);
263 /****************************************************************
264 ** alternative (radial) knob motion mode (ctrl + mouse pressed)
267 static void knob_pointer_event(GtkWidget
*widget
, gdouble x
, gdouble y
, int knob_x
, int knob_y
,
268 bool drag
, int state
)
270 static double last_y
= 2e20
;
271 GtkKnob
*knob
= GTK_KNOB(widget
);
272 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(widget
));
273 double radius
= min(knob_x
, knob_y
) / 2;
274 int knobx
= (widget
->allocation
.width
- knob_x
) / 2;
275 int knoby
= (widget
->allocation
.height
- knob_y
) / 2;
276 double posx
= (knobx
+ radius
) - x
; // x axis right -> left
277 double posy
= (knoby
+ radius
) - y
; // y axis top -> bottom
280 if (state
& GDK_CONTROL_MASK
) {
287 if (last_y
< 1e20
) { // in drag started with Control Key
288 const double scaling
= 0.005;
289 double scal
= (state
& GDK_SHIFT_MASK
? scaling
*0.1 : scaling
);
290 value
= (last_y
- posy
) * scal
;
292 gtk_range_set_value(GTK_RANGE(widget
), adj
->value
- value
* (adj
->upper
- adj
->lower
));
296 double angle
= atan2(-posx
, posy
) + M_PI
; // clockwise, zero at 6 o'clock, 0 .. 2*M_PI
298 // block "forbidden zone" and direct moves between quadrant 1 and 4
299 int quadrant
= 1 + int(angle
/M_PI_2
);
300 if (knob
->last_quadrant
== 1 && (quadrant
== 3 || quadrant
== 4)) {
302 } else if (knob
->last_quadrant
== 4 && (quadrant
== 1 || quadrant
== 2)) {
303 angle
= 2*M_PI
- scale_zero
;
305 if (angle
< scale_zero
) {
307 } else if (angle
> 2*M_PI
- scale_zero
) {
308 angle
= 2*M_PI
- scale_zero
;
310 knob
->last_quadrant
= quadrant
;
313 if (angle
< scale_zero
) {
315 } else if (angle
> 2*M_PI
- scale_zero
) {
316 angle
= 2*M_PI
- scale_zero
;
318 knob
->last_quadrant
= 0;
320 angle
= (angle
- scale_zero
) / (2 * (M_PI
-scale_zero
)); // normalize to 0..1
321 gtk_range_set_value(GTK_RANGE(widget
), adj
->lower
+ angle
* (adj
->upper
- adj
->lower
));
324 /****************************************************************
325 ** mouse button pressed set value
328 static gboolean
gtk_knob_button_press (GtkWidget
*widget
, GdkEventButton
*event
)
330 g_assert(GTK_IS_KNOB(widget
));
332 GtkKnobClass
*klass
= GTK_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget
));
335 switch (event
->button
) {
336 case 1: // left button
337 gtk_widget_grab_focus(widget
);
338 gtk_widget_grab_default (widget
);
339 gtk_grab_add(widget
);
340 klass
->button_is
= 1;
341 knob_pointer_event(widget
, event
->x
, event
->y
, klass
->knob_x
, klass
->knob_y
,
342 false, event
->state
);
345 klass
->button_is
= 2;
347 case 3: // right button
348 klass
->button_is
= 3;
350 default: // do nothing
356 /****************************************************************
357 ** mouse button release
360 static gboolean
gtk_knob_button_release (GtkWidget
*widget
, GdkEventButton
*event
)
362 g_assert(GTK_IS_KNOB(widget
));
363 GTK_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget
))->button_is
= 0;
364 if (GTK_WIDGET_HAS_GRAB(widget
))
365 gtk_grab_remove(widget
);
369 /****************************************************************
370 ** set the value from mouse movement
373 static gboolean
gtk_knob_pointer_motion (GtkWidget
*widget
, GdkEventMotion
*event
)
375 g_assert(GTK_IS_KNOB(widget
));
376 GtkKnobClass
*klass
= GTK_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget
));
378 gdk_event_request_motions (event
);
380 if (GTK_WIDGET_HAS_GRAB(widget
)) {
381 knob_pointer_event(widget
, event
->x
, event
->y
, klass
->knob_x
, klass
->knob_y
,
387 /****************************************************************
388 ** set value from mouseweel
391 static gboolean
gtk_knob_scroll (GtkWidget
*widget
, GdkEventScroll
*event
)
394 gtk_knob_set_value(widget
, event
->direction
);
398 /****************************************************************
399 ** init the GtkKnobClass
402 static void gtk_knob_class_init (GtkKnobClass
*klass
)
404 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
406 /** set here the sizes and steps for the used knob **/
407 //--------- small knob size and steps
411 klass
->knob_step
= 86;
413 //--------- event button
414 klass
->button_is
= 0;
416 //--------- connect the events with funktions
417 widget_class
->expose_event
= gtk_knob_expose
;
418 widget_class
->size_request
= gtk_knob_size_request
;
419 widget_class
->button_press_event
= gtk_knob_button_press
;
420 widget_class
->button_release_event
= gtk_knob_button_release
;
421 widget_class
->motion_notify_event
= gtk_knob_pointer_motion
;
422 widget_class
->key_press_event
= gtk_knob_key_press
;
423 widget_class
->scroll_event
= gtk_knob_scroll
;
426 /****************************************************************
427 ** init the Knob type/size
430 static void gtk_knob_init (GtkKnob
*knob
)
432 GtkWidget
*widget
= GTK_WIDGET(knob
);
433 GtkKnobClass
*klass
= GTK_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget
));
435 GTK_WIDGET_SET_FLAGS (GTK_WIDGET(knob
), GTK_CAN_FOCUS
);
436 GTK_WIDGET_SET_FLAGS (GTK_WIDGET(knob
), GTK_CAN_DEFAULT
);
438 widget
->requisition
.width
= klass
->knob_x
;
439 widget
->requisition
.height
= klass
->knob_y
;
443 /****************************************************************
444 ** redraw when value changed
447 static gboolean
gtk_knob_value_changed(gpointer obj
)
449 GtkWidget
*widget
= (GtkWidget
*)obj
;
450 gtk_widget_queue_draw(widget
);
454 /****************************************************************
458 GtkWidget
*GtkKnob::gtk_knob_new_with_adjustment(GtkAdjustment
*_adjustment
)
460 GtkWidget
*widget
= GTK_WIDGET( g_object_new (GTK_TYPE_KNOB
, NULL
));
461 GtkKnob
*knob
= GTK_KNOB(widget
);
462 knob
->last_quadrant
= 0;
464 gtk_range_set_adjustment(GTK_RANGE(widget
), _adjustment
);
465 g_signal_connect(GTK_OBJECT(widget
), "value-changed",
466 G_CALLBACK(gtk_knob_value_changed
), widget
);
471 /****************************************************************
475 GType
gtk_knob_get_type (void)
477 static GType kn_type
= 0;
479 static const GTypeInfo kn_info
= {
480 sizeof(GtkKnobClass
), NULL
, NULL
, (GClassInitFunc
)gtk_knob_class_init
, NULL
, NULL
, sizeof (GtkKnob
), 0, (GInstanceInitFunc
)gtk_knob_init
482 kn_type
= g_type_register_static(GTK_TYPE_RANGE
, "GtkKnob", &kn_info
, (GTypeFlags
)0);
486 }/* end of gtk_knob namespace */
488 gtk_knob::GtkKnob myGtkKnob
;
491 * rmWhiteSpaces(): Remove the leading and trailing white spaces of a string
492 * (but not those in the middle of the string)
494 static string
rmWhiteSpaces(const string
& s
)
496 size_t i
= s
.find_first_not_of(" \t");
497 size_t j
= s
.find_last_not_of(" \t");
499 if (i
!= string::npos
& j
!= string::npos
) {
500 return s
.substr(i
, 1+j
-i
);
508 * Extracts metdata from a label : 'vol [unit: dB]' -> 'vol' + metadata
510 static void extractMetadata(const string
& fulllabel
, string
& label
, map
<string
, string
>& metadata
)
512 enum {kLabel
, kEscape1
, kEscape2
, kEscape3
, kKey
, kValue
};
513 int state
= kLabel
; int deep
= 0;
516 for (unsigned int i
=0; i
< fulllabel
.size(); i
++) {
517 char c
= fulllabel
[i
];
522 case '\\' : state
= kEscape1
; break;
523 case '[' : state
= kKey
; deep
++; break;
524 default : label
+= c
;
546 case '\\' : state
= kEscape2
;
553 case ':' : if (deep
== 1) {
561 metadata
[rmWhiteSpaces(key
)] = "";
576 case '\\' : state
= kEscape3
;
585 metadata
[rmWhiteSpaces(key
)]=rmWhiteSpaces(value
);
593 default : value
+= c
;
598 cerr
<< "ERROR unrecognized state " << state
<< endl
;
601 label
= rmWhiteSpaces(label
);
605 class GTKUI
: public GUI
608 static bool fInitialized
;
609 static map
<float*, float> fGuiSize
; // map widget zone with widget size coef
610 static map
<float*, string
> fTooltip
; // map widget zone with tooltip strings
611 static set
<float*> fKnobSet
; // set of widget zone to be knobs
612 string gGroupTooltip
;
614 bool isKnob(float* zone
){return fKnobSet
.count(zone
) > 0;}
619 GtkWidget
* fBox
[stackSize
];
620 int fMode
[stackSize
];
623 GtkWidget
* addWidget(const char* label
, GtkWidget
* w
);
624 virtual void pushBox(int mode
, GtkWidget
* w
);
628 static const gboolean expand
= TRUE
;
629 static const gboolean fill
= TRUE
;
630 static const gboolean homogene
= FALSE
;
632 GTKUI(char * name
, int* pargc
, char*** pargv
);
634 // -- Labels and metadata
636 virtual void declare (float* zone
, const char* key
, const char* value
);
637 virtual int checkLabelOptions (GtkWidget
* widget
, const string
& fullLabel
, string
& simplifiedLabel
);
638 virtual void checkForTooltip (float* zone
, GtkWidget
* widget
);
642 virtual void openFrameBox(const char* label
);
643 virtual void openTabBox(const char* label
= "");
644 virtual void openHorizontalBox(const char* label
= "");
645 virtual void openVerticalBox(const char* label
= "");
647 // -- extra widget's layouts
649 virtual void openDialogBox(const char* label
, float* zone
);
650 virtual void openEventBox(const char* label
= "");
651 virtual void openHandleBox(const char* label
= "");
652 virtual void openExpanderBox(const char* label
, float* zone
);
654 virtual void closeBox();
655 virtual void adjustStack(int n
);
659 virtual void addButton(const char* label
, float* zone
);
660 virtual void addToggleButton(const char* label
, float* zone
);
661 virtual void addCheckButton(const char* label
, float* zone
);
662 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
663 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
664 virtual void addKnob(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
665 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
667 // -- passive display widgets
669 virtual void addNumDisplay(const char* label
, float* zone
, int precision
);
670 virtual void addTextDisplay(const char* label
, float* zone
, const char* names
[], float min
, float max
);
671 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
);
672 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
);
681 /******************************************************************************
682 *******************************************************************************
684 GRAPHIC USER INTERFACE (v2)
687 *******************************************************************************
688 *******************************************************************************/
690 // global static fields
692 bool GTKUI::fInitialized
= false;
693 map
<float*, float> GTKUI::fGuiSize
;
694 map
<float*, string
> GTKUI::fTooltip
;
695 set
<float*> GTKUI::fKnobSet
; // set of widget zone to be knobs
698 * Format tooltip string by replacing some white spaces by
699 * return characters so that line width doesn't exceed n.
700 * Limitation : long words exceeding n are not cut
702 static string
formatTooltip(int n
, const string
& tt
)
704 string ss
= tt
; // ss string we are going to format
705 int lws
= 0; // last white space encountered
706 int lri
= 0; // last return inserted
707 for (int i
=0; i
<tt
.size(); i
++) {
708 if (tt
[i
] == ' ') lws
= i
;
709 if (((i
-lri
) >= n
) && (lws
> lri
)) {
710 // insert return here
721 static gint
delete_event( GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
726 static void destroy_event( GtkWidget
*widget
, gpointer data
)
732 GTKUI::GTKUI(char * name
, int* pargc
, char*** pargv
)
735 gtk_init(pargc
, pargv
);
739 fWindow
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
740 //gtk_container_set_border_width (GTK_CONTAINER (fWindow), 10);
741 gtk_window_set_title (GTK_WINDOW (fWindow
), name
);
742 gtk_signal_connect (GTK_OBJECT (fWindow
), "delete_event", GTK_SIGNAL_FUNC (delete_event
), NULL
);
743 gtk_signal_connect (GTK_OBJECT (fWindow
), "destroy", GTK_SIGNAL_FUNC (destroy_event
), NULL
);
746 fBox
[fTop
] = gtk_vbox_new (homogene
, 4);
747 fMode
[fTop
] = kBoxMode
;
748 gtk_container_add (GTK_CONTAINER (fWindow
), fBox
[fTop
]);
752 // empilement des boites
754 void GTKUI::pushBox(int mode
, GtkWidget
* w
)
757 assert(fTop
< stackSize
);
764 * Remove n levels from the stack S before the top level
765 * adjustStack(n): S -> S' with S' = S(0),S(n+1),S(n+2),...
767 void GTKUI::adjustStack(int n
)
773 fMode
[fTop
] = fMode
[fTop
+n
];
774 fBox
[fTop
] = fBox
[fTop
+n
];
778 void GTKUI::closeBox()
786 * Analyses the widget zone metadata declarations and takes
787 * appropriate actions
789 void GTKUI::declare(float* zone
, const char* key
, const char* value
)
792 // special zone 0 means group metadata
793 if (strcmp(key
,"tooltip")==0) {
794 // only group tooltip are currently implemented
795 gGroupTooltip
= formatTooltip(30, value
);
798 if (strcmp(key
,"size")==0) {
799 fGuiSize
[zone
]=atof(value
);
801 else if (strcmp(key
,"tooltip")==0) {
802 fTooltip
[zone
] = formatTooltip(30,value
) ;
804 else if (strcmp(key
,"style")==0) {
805 if (strcmp(value
,"knob") == 0) {
806 fKnobSet
.insert(zone
);
815 * Analyses a full label and activates the relevant options. returns a simplified
816 * label (without options) and an amount of stack adjustement (in case additional
817 * containers were pushed on the stack).
820 int GTKUI::checkLabelOptions(GtkWidget
* widget
, const string
& fullLabel
, string
& simplifiedLabel
)
822 map
<string
, string
> metadata
;
823 extractMetadata(fullLabel
, simplifiedLabel
, metadata
);
825 if (metadata
.count("tooltip")) {
826 gtk_tooltips_set_tip (gtk_tooltips_new (), widget
, metadata
["tooltip"].c_str(), NULL
);
828 if (metadata
["option"] == "detachable") {
829 openHandleBox(simplifiedLabel
.c_str());
833 //---------------------
834 if (gGroupTooltip
!= string()) {
835 gtk_tooltips_set_tip (gtk_tooltips_new (), widget
, gGroupTooltip
.c_str(), NULL
);
836 gGroupTooltip
= string();
839 //----------------------
841 // no adjustement of the stack needed
846 * Check if a tooltip is associated to a zone and add it to the corresponding widget
848 void GTKUI::checkForTooltip(float* zone
, GtkWidget
* widget
)
850 if (fTooltip
.count(zone
)) {
851 gtk_tooltips_set_tip (gtk_tooltips_new (), widget
, fTooltip
[zone
].c_str(), NULL
);
856 // les differentes boites
858 void GTKUI::openFrameBox(const char* label
)
860 GtkWidget
* box
= gtk_frame_new (label
);
861 //gtk_container_set_border_width (GTK_CONTAINER (box), 10);
863 pushBox(kSingleMode
, addWidget(label
, box
));
867 void GTKUI::openTabBox(const char* fullLabel
)
870 GtkWidget
* widget
= gtk_notebook_new();
872 int adjust
= checkLabelOptions(widget
, fullLabel
, label
);
874 pushBox(kTabMode
, addWidget(label
.c_str(), widget
));
876 // adjust stack because otherwise Handlebox will remain open
881 void GTKUI::openHorizontalBox(const char* fullLabel
)
884 GtkWidget
* box
= gtk_hbox_new (homogene
, 4);
885 int adjust
= checkLabelOptions(box
, fullLabel
, label
);
887 gtk_container_set_border_width (GTK_CONTAINER (box
), 10);
889 if (fMode
[fTop
] != kTabMode
&& label
[0] != 0) {
890 GtkWidget
* frame
= addWidget(label
.c_str(), gtk_frame_new (label
.c_str()));
891 gtk_container_add (GTK_CONTAINER(frame
), box
);
892 gtk_widget_show(box
);
893 pushBox(kBoxMode
, box
);
895 pushBox(kBoxMode
, addWidget(label
.c_str(), box
));
898 // adjust stack because otherwise Handlebox will remain open
903 void GTKUI::openVerticalBox(const char* fullLabel
)
906 GtkWidget
* box
= gtk_vbox_new (homogene
, 4);
907 int adjust
= checkLabelOptions(box
, fullLabel
, label
);
909 gtk_container_set_border_width (GTK_CONTAINER (box
), 10);
911 if (fMode
[fTop
] != kTabMode
&& label
[0] != 0) {
912 GtkWidget
* frame
= addWidget(label
.c_str(), gtk_frame_new (label
.c_str()));
913 gtk_container_add (GTK_CONTAINER(frame
), box
);
914 gtk_widget_show(box
);
915 pushBox(kBoxMode
, box
);
917 pushBox(kBoxMode
, addWidget(label
.c_str(), box
));
920 // adjust stack because otherwise Handlebox will remain open
925 void GTKUI::openHandleBox(const char* label
)
927 GtkWidget
* box
= gtk_hbox_new (homogene
, 4);
928 gtk_container_set_border_width (GTK_CONTAINER (box
), 2);
929 if (fMode
[fTop
] != kTabMode
&& label
[0] != 0)
931 GtkWidget
* frame
= addWidget(label
, gtk_handle_box_new ());
932 gtk_container_add (GTK_CONTAINER(frame
), box
);
933 gtk_widget_show(box
);
934 pushBox(kBoxMode
, box
);
938 pushBox(kBoxMode
, addWidget(label
, box
));
943 void GTKUI::openEventBox(const char* label
)
945 GtkWidget
* box
= gtk_hbox_new (homogene
, 4);
946 gtk_container_set_border_width (GTK_CONTAINER (box
), 2);
947 if (fMode
[fTop
] != kTabMode
&& label
[0] != 0)
949 GtkWidget
* frame
= addWidget(label
, gtk_event_box_new ());
950 gtk_container_add (GTK_CONTAINER(frame
), box
);
951 gtk_widget_show(box
);
952 pushBox(kBoxMode
, box
);
956 pushBox(kBoxMode
, addWidget(label
, box
));
961 struct uiExpanderBox
: public uiItem
963 GtkExpander
* fButton
;
964 uiExpanderBox(GUI
* ui
, float* zone
, GtkExpander
* b
) : uiItem(ui
, zone
), fButton(b
) {}
965 static void expanded (GtkWidget
*widget
, gpointer data
)
967 float v
= gtk_expander_get_expanded (GTK_EXPANDER(widget
));
973 ((uiItem
*)data
)->modifyZone(v
);
976 virtual void reflectZone()
980 gtk_expander_set_expanded(GTK_EXPANDER(fButton
), v
);
984 void GTKUI::openExpanderBox(const char* label
, float* zone
)
987 GtkWidget
* box
= gtk_hbox_new (homogene
, 4);
988 gtk_container_set_border_width (GTK_CONTAINER (box
), 2);
989 if (fMode
[fTop
] != kTabMode
&& label
[0] != 0)
991 GtkWidget
* frame
= addWidget(label
, gtk_expander_new (label
));
992 gtk_container_add (GTK_CONTAINER(frame
), box
);
993 uiExpanderBox
* c
= new uiExpanderBox(this, zone
, GTK_EXPANDER(frame
));
994 gtk_signal_connect (GTK_OBJECT (frame
), "activate", GTK_SIGNAL_FUNC (uiExpanderBox::expanded
), (gpointer
)c
);
995 gtk_widget_show(box
);
996 pushBox(kBoxMode
, box
);
1000 pushBox(kBoxMode
, addWidget(label
, box
));
1006 GtkWidget
* GTKUI::addWidget(const char* label
, GtkWidget
* w
)
1008 switch (fMode
[fTop
]) {
1009 case kSingleMode
: gtk_container_add (GTK_CONTAINER(fBox
[fTop
]), w
); break;
1010 case kBoxMode
: gtk_box_pack_start (GTK_BOX(fBox
[fTop
]), w
, expand
, fill
, 0); break;
1011 case kTabMode
: gtk_notebook_append_page (GTK_NOTEBOOK(fBox
[fTop
]), w
, gtk_label_new(label
)); break;
1013 gtk_widget_show (w
);
1017 // --------------------------- Press button ---------------------------
1019 struct uiButton
: public uiItem
1023 uiButton (GUI
* ui
, float* zone
, GtkButton
* b
) : uiItem(ui
, zone
), fButton(b
) {}
1025 static void pressed( GtkWidget
*widget
, gpointer data
)
1027 uiItem
* c
= (uiItem
*) data
;
1031 static void released( GtkWidget
*widget
, gpointer data
)
1033 uiItem
* c
= (uiItem
*) data
;
1037 virtual void reflectZone()
1041 if (v
> 0.0) gtk_button_pressed(fButton
); else gtk_button_released(fButton
);
1045 void GTKUI::addButton(const char* label
, float* zone
)
1048 GtkWidget
* button
= gtk_button_new_with_label (label
);
1049 addWidget(label
, button
);
1051 uiButton
* c
= new uiButton(this, zone
, GTK_BUTTON(button
));
1053 gtk_signal_connect (GTK_OBJECT (button
), "pressed", GTK_SIGNAL_FUNC (uiButton::pressed
), (gpointer
) c
);
1054 gtk_signal_connect (GTK_OBJECT (button
), "released", GTK_SIGNAL_FUNC (uiButton::released
), (gpointer
) c
);
1056 checkForTooltip(zone
, button
);
1059 // --------------------------- Toggle Buttons ---------------------------
1061 struct uiToggleButton
: public uiItem
1063 GtkToggleButton
* fButton
;
1065 uiToggleButton(GUI
* ui
, float* zone
, GtkToggleButton
* b
) : uiItem(ui
, zone
), fButton(b
) {}
1067 static void toggled (GtkWidget
*widget
, gpointer data
)
1069 float v
= (GTK_TOGGLE_BUTTON (widget
)->active
) ? 1.0 : 0.0;
1070 ((uiItem
*)data
)->modifyZone(v
);
1073 virtual void reflectZone()
1077 gtk_toggle_button_set_active(fButton
, v
> 0.0);
1081 void GTKUI::addToggleButton(const char* label
, float* zone
)
1084 GtkWidget
* button
= gtk_toggle_button_new_with_label (label
);
1085 addWidget(label
, button
);
1087 uiToggleButton
* c
= new uiToggleButton(this, zone
, GTK_TOGGLE_BUTTON(button
));
1088 gtk_signal_connect (GTK_OBJECT (button
), "toggled", GTK_SIGNAL_FUNC (uiToggleButton::toggled
), (gpointer
) c
);
1090 checkForTooltip(zone
, button
);
1095 void show_dialog(GtkWidget
*widget
, gpointer data
)
1097 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget
)) == TRUE
)
1099 gtk_widget_show(GTK_WIDGET(data
));
1100 gint root_x
, root_y
;
1101 gtk_window_get_position (GTK_WINDOW(data
), &root_x
, &root_y
);
1103 gtk_window_move(GTK_WINDOW(data
), root_x
, root_y
);
1105 else gtk_widget_hide(GTK_WIDGET(data
));
1108 static gboolean
deleteevent( GtkWidget
*widget
, gpointer data
)
1113 void GTKUI::openDialogBox(const char* label
, float* zone
)
1115 // create toplevel window and set properties
1116 GtkWidget
* dialog
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1117 gtk_window_set_decorated(GTK_WINDOW(dialog
), TRUE
);
1118 gtk_window_set_deletable(GTK_WINDOW(dialog
), FALSE
);
1119 gtk_window_set_resizable(GTK_WINDOW(dialog
), FALSE
);
1120 gtk_window_set_gravity(GTK_WINDOW(dialog
), GDK_GRAVITY_SOUTH
);
1121 gtk_window_set_transient_for (GTK_WINDOW(dialog
), GTK_WINDOW(fWindow
));
1122 gtk_window_set_position (GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
1123 gtk_window_set_keep_below (GTK_WINDOW(dialog
), FALSE
);
1124 gtk_window_set_title (GTK_WINDOW (dialog
), label
);
1125 g_signal_connect (G_OBJECT (dialog
), "delete_event", G_CALLBACK (deleteevent
), NULL
);
1126 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog
), TRUE
);
1128 GtkWidget
* box
= gtk_hbox_new (homogene
, 4);
1131 GtkWidget
* button
= gtk_toggle_button_new ();
1132 gtk_signal_connect (GTK_OBJECT (button
), "toggled", GTK_SIGNAL_FUNC (show_dialog
), (gpointer
) dialog
);
1134 gtk_container_add (GTK_CONTAINER(fBox
[fTop
]), button
);
1135 gtk_container_add (GTK_CONTAINER(dialog
), box
);
1136 gtk_widget_show (button
);
1137 gtk_widget_show(box
);
1138 pushBox(kBoxMode
, box
);
1144 // --------------------------- Check Button ---------------------------
1146 struct uiCheckButton
: public uiItem
1148 GtkToggleButton
* fButton
;
1150 uiCheckButton(GUI
* ui
, float* zone
, GtkToggleButton
* b
) : uiItem(ui
, zone
), fButton(b
) {}
1152 static void toggled (GtkWidget
*widget
, gpointer data
)
1154 float v
= (GTK_TOGGLE_BUTTON (widget
)->active
) ? 1.0 : 0.0;
1155 ((uiItem
*)data
)->modifyZone(v
);
1158 virtual void reflectZone()
1162 gtk_toggle_button_set_active(fButton
, v
> 0.0);
1166 void GTKUI::addCheckButton(const char* label
, float* zone
)
1169 GtkWidget
* button
= gtk_check_button_new_with_label (label
);
1170 addWidget(label
, button
);
1172 uiCheckButton
* c
= new uiCheckButton(this, zone
, GTK_TOGGLE_BUTTON(button
));
1173 gtk_signal_connect (GTK_OBJECT (button
), "toggled", GTK_SIGNAL_FUNC(uiCheckButton::toggled
), (gpointer
) c
);
1175 checkForTooltip(zone
, button
);
1179 // --------------------------- Adjustmenty based widgets ---------------------------
1181 struct uiAdjustment
: public uiItem
1183 GtkAdjustment
* fAdj
;
1185 uiAdjustment(GUI
* ui
, float* zone
, GtkAdjustment
* adj
) : uiItem(ui
, zone
), fAdj(adj
) {}
1187 static void changed (GtkWidget
*widget
, gpointer data
)
1189 float v
= GTK_ADJUSTMENT (widget
)->value
;
1190 ((uiItem
*)data
)->modifyZone(v
);
1193 virtual void reflectZone()
1197 gtk_adjustment_set_value(fAdj
, v
);
1201 // --------------------------- format knob value display ---------------------------
1203 struct uiValueDisplay
: public uiItem
1208 uiValueDisplay(GUI
* ui
, float* zone
, GtkLabel
* label
, int precision
)
1209 : uiItem(ui
, zone
), fLabel(label
), fPrecision(precision
) {}
1211 virtual void reflectZone()
1216 if (fPrecision
<= 0)
1217 snprintf(s
, 63, "%d", int(v
));
1219 else if (fPrecision
> 3)
1220 snprintf(s
, 63, "%f", v
);
1222 else if (fPrecision
== 1)
1224 const char* format
[] = {"%.1f", "%.2f", "%.3f"};
1225 snprintf(s
, 63, format
[1-1], v
);
1227 else if (fPrecision
== 2)
1229 const char* format
[] = {"%.1f", "%.2f", "%.3f"};
1230 snprintf(s
, 63, format
[2-1], v
);
1234 const char* format
[] = {"%.1f", "%.2f", "%.3f"};
1235 snprintf(s
, 63, format
[3-1], v
);
1237 gtk_label_set_text(fLabel
, s
);
1241 // ------------------------------- Knob -----------------------------------------
1243 void GTKUI::addKnob(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1246 GtkObject
* adj
= gtk_adjustment_new(init
, min
, max
, step
, 10*step
, 0);
1248 uiAdjustment
* c
= new uiAdjustment(this, zone
, GTK_ADJUSTMENT(adj
));
1250 gtk_signal_connect (GTK_OBJECT (adj
), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed
), (gpointer
) c
);
1252 GtkWidget
* slider
= gtk_vbox_new (FALSE
, 0);
1253 GtkWidget
* fil
= gtk_vbox_new (FALSE
, 0);
1254 GtkWidget
* rei
= gtk_vbox_new (FALSE
, 0);
1255 GtkWidget
* re
=myGtkKnob
.gtk_knob_new_with_adjustment(GTK_ADJUSTMENT(adj
));
1256 GtkWidget
* lw
= gtk_label_new("");
1257 new uiValueDisplay(this, zone
, GTK_LABEL(lw
),precision(step
));
1258 gtk_container_add (GTK_CONTAINER(rei
), re
);
1259 if(fGuiSize
[zone
]) {
1260 float size
= 30 * fGuiSize
[zone
];
1261 gtk_widget_set_size_request(rei
, size
, size
);
1262 gtk_box_pack_start (GTK_BOX(slider
), fil
, TRUE
, TRUE
, 0);
1263 gtk_box_pack_start (GTK_BOX(slider
), rei
, FALSE
, FALSE
, 0);
1265 gtk_container_add (GTK_CONTAINER(slider
), fil
);
1266 gtk_container_add (GTK_CONTAINER(slider
), rei
);
1268 gtk_container_add (GTK_CONTAINER(slider
), lw
);
1269 gtk_widget_show_all(slider
);
1271 if (label
&& label
[0]!=0) {
1272 openFrameBox(label
);
1273 addWidget(label
, slider
);
1276 addWidget(label
, slider
);
1279 checkForTooltip(zone
, slider
);
1282 // -------------------------- Vertical Slider -----------------------------------
1284 void GTKUI::addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1287 addKnob(label
, zone
, init
, min
, max
, step
);
1291 GtkObject
* adj
= gtk_adjustment_new(init
, min
, max
, step
, 10*step
, 0);
1293 uiAdjustment
* c
= new uiAdjustment(this, zone
, GTK_ADJUSTMENT(adj
));
1295 gtk_signal_connect (GTK_OBJECT (adj
), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed
), (gpointer
) c
);
1297 GtkWidget
* slider
= gtk_vscale_new (GTK_ADJUSTMENT(adj
));
1298 gtk_scale_set_digits(GTK_SCALE(slider
), precision(step
));
1300 if(fGuiSize
[zone
]) {
1301 size
= 160 * fGuiSize
[zone
];
1303 gtk_widget_set_size_request(slider
, -1, size
);
1305 gtk_range_set_inverted (GTK_RANGE(slider
), TRUE
);
1307 if (label
&& label
[0]!=0) {
1308 openFrameBox(label
);
1309 addWidget(label
, slider
);
1312 addWidget(label
, slider
);
1315 checkForTooltip(zone
, slider
);
1318 // -------------------------- Horizontal Slider -----------------------------------
1320 void GTKUI::addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1323 addKnob(label
, zone
, init
, min
, max
, step
);
1327 GtkObject
* adj
= gtk_adjustment_new(init
, min
, max
, step
, 10*step
, 0);
1329 uiAdjustment
* c
= new uiAdjustment(this, zone
, GTK_ADJUSTMENT(adj
));
1331 gtk_signal_connect (GTK_OBJECT (adj
), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed
), (gpointer
) c
);
1333 GtkWidget
* slider
= gtk_hscale_new (GTK_ADJUSTMENT(adj
));
1334 gtk_scale_set_digits(GTK_SCALE(slider
), precision(step
));
1336 if(fGuiSize
[zone
]) {
1337 size
= 160 * fGuiSize
[zone
];
1339 gtk_widget_set_size_request(slider
, size
, -1);
1341 if (label
&& label
[0]!=0) {
1342 openFrameBox(label
);
1343 addWidget(label
, slider
);
1346 addWidget(label
, slider
);
1349 checkForTooltip(zone
, slider
);
1353 // ------------------------------ Num Entry -----------------------------------
1355 void GTKUI::addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1358 addKnob(label
, zone
, init
, min
, max
, step
);
1362 GtkObject
* adj
= gtk_adjustment_new(init
, min
, max
, step
, 10*step
, step
);
1364 uiAdjustment
* c
= new uiAdjustment(this, zone
, GTK_ADJUSTMENT(adj
));
1366 gtk_signal_connect (GTK_OBJECT (adj
), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed
), (gpointer
) c
);
1368 GtkWidget
* spinner
= gtk_spin_button_new (GTK_ADJUSTMENT(adj
), 0.005, precision(step
));
1370 openFrameBox(label
);
1371 addWidget(label
, spinner
);
1374 checkForTooltip(zone
, spinner
);
1378 // ========================== passive widgets ===============================
1381 // ------------------------------ Progress Bar -----------------------------------
1383 struct uiBargraph
: public uiItem
1385 GtkProgressBar
* fProgressBar
;
1389 uiBargraph(GUI
* ui
, float* zone
, GtkProgressBar
* pbar
, float lo
, float hi
)
1390 : uiItem(ui
, zone
), fProgressBar(pbar
), fMin(lo
), fMax(hi
) {}
1392 float scale(float v
) { return (v
-fMin
)/(fMax
-fMin
); }
1394 virtual void reflectZone()
1398 gtk_progress_bar_set_fraction(fProgressBar
, scale(v
));
1404 void GTKUI::addVerticalBargraph(const char* label
, float* zone
, float lo
, float hi
)
1406 GtkWidget
* pb
= gtk_progress_bar_new();
1407 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb
), GTK_PROGRESS_BOTTOM_TO_TOP
);
1408 gtk_widget_set_size_request(pb
, 8, -1);
1409 new uiBargraph(this, zone
, GTK_PROGRESS_BAR(pb
), lo
, hi
);
1410 openFrameBox(label
);
1411 addWidget(label
, pb
);
1414 checkForTooltip(zone
, pb
);
1418 void GTKUI::addHorizontalBargraph(const char* label
, float* zone
, float lo
, float hi
)
1420 GtkWidget
* pb
= gtk_progress_bar_new();
1421 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb
), GTK_PROGRESS_LEFT_TO_RIGHT
);
1422 gtk_widget_set_size_request(pb
, -1, 8);
1423 new uiBargraph(this, zone
, GTK_PROGRESS_BAR(pb
), lo
, hi
);
1424 openFrameBox(label
);
1425 addWidget(label
, pb
);
1428 checkForTooltip(zone
, pb
);
1432 // ------------------------------ Num Display -----------------------------------
1434 struct uiNumDisplay
: public uiItem
1439 uiNumDisplay(GUI
* ui
, float* zone
, GtkLabel
* label
, int precision
)
1440 : uiItem(ui
, zone
), fLabel(label
), fPrecision(precision
) {}
1442 virtual void reflectZone()
1447 if (fPrecision
<= 0) {
1448 snprintf(s
, 63, "%d", int(v
));
1449 } else if (fPrecision
>3) {
1450 snprintf(s
, 63, "%f", v
);
1452 const char* format
[] = {"%.1f", "%.2f", "%.3f"};
1453 snprintf(s
, 63, format
[fPrecision
-1], v
);
1455 gtk_label_set_text(fLabel
, s
);
1460 void GTKUI::addNumDisplay(const char* label
, float* zone
, int precision
)
1462 GtkWidget
* lw
= gtk_label_new("");
1463 new uiNumDisplay(this, zone
, GTK_LABEL(lw
), precision
);
1464 openFrameBox(label
);
1465 addWidget(label
, lw
);
1468 checkForTooltip(zone
, lw
);
1472 // ------------------------------ Text Display -----------------------------------
1474 struct uiTextDisplay
: public uiItem
1477 const char** fNames
;
1483 uiTextDisplay (GUI
* ui
, float* zone
, GtkLabel
* label
, const char* names
[], float lo
, float hi
)
1484 : uiItem(ui
, zone
), fLabel(label
), fNames(names
), fMin(lo
), fMax(hi
)
1487 while (fNames
[fNum
] != 0) fNum
++;
1490 virtual void reflectZone()
1495 int idx
= int(fNum
*(v
-fMin
)/(fMax
-fMin
));
1497 if (idx
< 0) idx
= 0;
1498 else if (idx
>= fNum
) idx
= fNum
-1;
1500 gtk_label_set_text(fLabel
, fNames
[idx
]);
1505 void GTKUI::addTextDisplay(const char* label
, float* zone
, const char* names
[], float lo
, float hi
)
1507 GtkWidget
* lw
= gtk_label_new("");
1508 new uiTextDisplay (this, zone
, GTK_LABEL(lw
), names
, lo
, hi
);
1509 openFrameBox(label
);
1510 addWidget(label
, lw
);
1513 checkForTooltip(zone
, lw
);
1521 gtk_widget_show (fBox
[0]);
1522 gtk_widget_show (fWindow
);
1527 * Update all user items reflecting zone z
1530 static gboolean
callUpdateAllGuis(gpointer
)
1532 GUI::updateAllGuis();
1540 gtk_widget_show (fBox
[0]);
1541 gtk_widget_show (fWindow
);
1542 gtk_timeout_add(40, callUpdateAllGuis
, 0);