1 /* giwknob.c - GiwKnob widget's source Version 0.1
2 Copyright (C) 2006 Alexandre Pereira Bueno, Eduardo Parente Ribeiro
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Maintainers
19 Alexandre Pereira Bueno - alpebu@yahoo.com.br
20 James Scott Jr <skoona@users.sourceforge.net>
21 */
22
23 // additional code G. Finch (salsaman@gmail.com) 2010 - 2016
24
25
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "main.h"
32
33 #include "giw/giwknob.h"
34
35
36 #define KNOB_DEFAULT_SIZE 150
37
38 /* Forward declarations */
39 static void giw_knob_class_init(GiwKnobClass *klass);
40 static void giw_knob_init(GiwKnob *knob);
41 static void giw_knob_realize(GtkWidget *widget);
42 static void giw_knob_size_request(GtkWidget *widget,
43 GtkRequisition *requisition);
44 #if GTK_CHECK_VERSION(3, 0, 0)
45 static void giw_knob_dispose(GObject *object);
46 static void giw_knob_get_preferred_width(GtkWidget *widget,
47 gint *minimal_width,
48 gint *natural_width);
49 static void giw_knob_get_preferred_height(GtkWidget *widget,
50 gint *minimal_height,
51 gint *natural_height);
52 static gboolean giw_knob_draw(GtkWidget *widget, cairo_t *cairo);
53 static void giw_knob_style_updated(GtkWidget *widget);
54 #else
55 static void giw_knob_destroy(GtkObject *object);
56 static gint giw_knob_expose(GtkWidget *widget,
57 GdkEventExpose *event);
58 #endif
59
60 static void giw_knob_size_allocate(GtkWidget *widget,
61 GtkAllocation *allocation);
62 static gint giw_knob_button_press(GtkWidget *widget,
63 GdkEventButton *event);
64 static gint giw_knob_button_release(GtkWidget *widget,
65 GdkEventButton *event);
66 static gint giw_knob_motion_notify(GtkWidget *widget,
67 GdkEventMotion *event);
68 static void giw_knob_style_set(GtkWidget *widget,
69 GtkStyle *previous_style);
70 // Changes the value, by mouse position
71 void knob_update_mouse(GiwKnob *knob, gint x, gint y);
72
73 // Updates the false pointer's angle
74 void knob_update_false_mouse(GiwKnob *knob, gint x, gint y);
75
76 // Calculate the value, using the angle
77 gdouble knob_calculate_value_with_angle(GiwKnob *knob,
78 gdouble angle);
79 // Calculate the angle, using the value
80 gdouble knob_calculate_angle_with_value(GiwKnob *knob,
81 gdouble value);
82 // Calculate all sizes
83 static void knob_calculate_sizes(GiwKnob *knob);
84 // To make the changes needed when someno changes the lower ans upper fields of the adjustment
85 static void giw_knob_adjustment_changed(GtkAdjustment *adjustment,
86 gpointer data);
87 // To make the changes needed when someno changes the value of the adjustment
88 static void giw_knob_adjustment_value_changed(GtkAdjustment *adjustment,
89 gpointer data);
90 // A not public knob_set_angle function, for internal using, it only sets the angle, nothing more
91 void knob_set_angle(GiwKnob *knob,
92 gdouble angle);
93 // A not public knob_set_value function, for internal using, it only sets the value, nothing more
94 void knob_set_value(GiwKnob *knob,
95 gdouble value);
96 // A function that creates the layout of legends and calculates it's sizes
97 void knob_build_legends(GiwKnob *knob);
98
99 // A function that frees the layout of legends
100 void knob_free_legends(GiwKnob *knob);
101
102 // A function that creates the layout of the title
103 void knob_build_title(GiwKnob *knob);
104
105 // A function that calculates width and height of the legend's the layout
106 void knob_calculate_legends_sizes(GiwKnob *knob);
107
108 // A function that calculates width and height of the title's the layout
109 void knob_calculate_title_sizes(GiwKnob *knob);
110
111 #if GTK_CHECK_VERSION(3, 0, 0)
G_DEFINE_TYPE(GiwKnob,giw_knob,GTK_TYPE_WIDGET)112 G_DEFINE_TYPE(GiwKnob, giw_knob, GTK_TYPE_WIDGET)
113 #define parent_class giw_knob_parent_class
114
115 #else
116 static GtkWidgetClass *parent_class = NULL;
117
118
119 /*********************
120 Widget's Functions
121 *********************/
122 GType
123 giw_knob_get_type() {
124 static GType knob_type = 0;
125
126 if (!knob_type) {
127 static const GtkTypeInfo knob_info = {
128 "GiwKnob",
129 sizeof(GiwKnob),
130 sizeof(GiwKnobClass),
131 (GtkClassInitFunc) giw_knob_class_init,
132 (GtkObjectInitFunc) giw_knob_init,
133 /*(GtkArgSetFunc)*/ NULL,
134 /*(GtkArgGetFunc)*/ NULL,
135 (GtkClassInitFunc) NULL,
136 };
137
138 knob_type = gtk_type_unique(gtk_widget_get_type(), &knob_info);
139 }
140
141 return knob_type;
142 }
143
144 #endif
145
146 static void
147 giw_knob_class_init(GiwKnobClass *xclass) {
148 #if GTK_CHECK_VERSION(3, 0, 0)
149 GObjectClass *object_class = G_OBJECT_CLASS(xclass);
150 #else
151 GtkObjectClass *object_class = (GtkObjectClass *) xclass;
152 #endif
153 GtkWidgetClass *widget_class;
154
155 widget_class = (GtkWidgetClass *) xclass;
156
157 #if GTK_CHECK_VERSION(3, 0, 0)
158 object_class->dispose = giw_knob_dispose;
159 #else
160 parent_class = (GtkWidgetClass *)gtk_type_class(gtk_widget_get_type());
161 object_class->destroy = giw_knob_destroy;
162 #endif
163
164 widget_class->realize = giw_knob_realize;
165
166 #if GTK_CHECK_VERSION(3, 0, 0)
167 widget_class->get_preferred_width = giw_knob_get_preferred_width;
168 widget_class->get_preferred_height = giw_knob_get_preferred_height;
169 widget_class->draw = giw_knob_draw;
170 widget_class->style_updated = giw_knob_style_updated;
171 #else
172 widget_class->expose_event = giw_knob_expose;
173 widget_class->size_request = giw_knob_size_request;
174 #endif
175 widget_class->size_allocate = giw_knob_size_allocate;
176 widget_class->button_press_event = giw_knob_button_press;
177 widget_class->button_release_event = giw_knob_button_release;
178 widget_class->motion_notify_event = giw_knob_motion_notify;
179 widget_class->style_set = giw_knob_style_set;
180 }
181
182 static void
giw_knob_init(GiwKnob * knob)183 giw_knob_init(GiwKnob *knob) {
184 g_return_if_fail(knob != NULL);
185 g_return_if_fail(GIW_IS_KNOB(knob));
186
187 knob->button = 0;
188 knob->mouse_policy = GIW_KNOB_MOUSE_AUTOMATICALLY;
189 knob->major_ticks = 9;
190 knob->minor_ticks = 3;
191 knob->major_ticks_size = 5;
192 knob->minor_ticks_size = 3;
193 knob->legends_digits = 3;
194 knob->title = NULL;
195 knob->wrap = FALSE;
196
197 #if GTK_CHECK_VERSION(2,18,0)
198 gtk_widget_set_has_window(GTK_WIDGET(knob), TRUE);
199 #endif
200
201 }
202
203 GtkWidget *
giw_knob_new(GtkAdjustment * adjustment)204 giw_knob_new(GtkAdjustment *adjustment) {
205 GiwKnob *knob;
206
207 g_return_val_if_fail(adjustment != NULL, NULL);
208
209 #if GTK_CHECK_VERSION(3, 0, 0)
210 knob = (GiwKnob *)g_object_new(GIW_TYPE_KNOB, NULL);
211 #else
212 knob = (GiwKnob *)gtk_type_new(giw_knob_get_type());
213 #endif
214 giw_knob_set_adjustment(knob, adjustment);
215
216 // Without this, in the first draw, the pointer wouldn't be in the right value
217 knob_set_angle(knob, knob_calculate_angle_with_value(knob, gtk_adjustment_get_value(adjustment)));
218
219 return GTK_WIDGET(knob);
220 }
221
222 GtkWidget *
giw_knob_new_with_adjustment(gdouble value,gdouble lower,gdouble upper)223 giw_knob_new_with_adjustment(gdouble value,
224 gdouble lower,
225 gdouble upper) {
226 GiwKnob *knob;
227
228 #if GTK_CHECK_VERSION(3, 0, 0)
229 knob = (GiwKnob *)g_object_new(GIW_TYPE_KNOB, NULL);
230 #else
231 knob = (GiwKnob *)gtk_type_new(giw_knob_get_type());
232 #endif
233 giw_knob_set_adjustment(knob, (GtkAdjustment *) gtk_adjustment_new(value, lower, upper, 1.0, 1.0, 1.0));
234
235 // Without this, in the first draw, the pointer wouldn't be in the right value
236 knob_set_angle(knob, knob_calculate_angle_with_value(knob, gtk_adjustment_get_value(knob->adjustment)));
237
238 return GTK_WIDGET(knob);
239 }
240
241 #if GTK_CHECK_VERSION(3, 0, 0)
giw_knob_dispose(GObject * object)242 static void giw_knob_dispose(GObject *object) {
243 #else
244 static void giw_knob_destroy(GtkObject *object) {
245 #endif
246 GiwKnob *knob;
247 gint loop;
248
249 g_return_if_fail(object != NULL);
250 g_return_if_fail(GIW_IS_KNOB(object));
251
252 knob = GIW_KNOB(object);
253
254 if (knob->adjustment)
255 g_object_unref(G_OBJECT(knob->adjustment));
256 knob->adjustment = NULL;
257
258 if (knob->legends) {
259 for (loop = 0; loop < knob->major_ticks; loop++) {
260 g_object_unref(G_OBJECT(knob->legends[loop]));
261 }
262 g_free(knob->legends);
263 knob->legends = NULL;
264 }
265 if (knob->title_str)
266 g_free(knob->title_str);
267 if (knob->title)
268 g_object_unref(G_OBJECT(knob->title));
269
270 #if GTK_CHECK_VERSION(3, 0, 0)
271 G_OBJECT_CLASS(giw_knob_parent_class)->dispose(object);
272 #else
273 if (LIVES_GUI_OBJECT_CLASS(parent_class)->destroy)
274 (* LIVES_GUI_OBJECT_CLASS(parent_class)->destroy)(object);
275 #endif
276 }
277
278 static void
279 giw_knob_realize(GtkWidget *widget) {
280 GiwKnob *knob;
281 GdkWindowAttr attributes;
282 gint attributes_mask;
283
284 #if GTK_CHECK_VERSION(3, 0, 0)
285 GtkStyleContext *stylecon;
286 #endif
287
288 g_return_if_fail(widget != NULL);
289 g_return_if_fail(GIW_IS_KNOB(widget));
290
291 #if GTK_CHECK_VERSION(2,20,0)
292 gtk_widget_set_realized(widget, TRUE);
293 #else
294 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
295 #endif
296
297 knob = GIW_KNOB(widget);
298
299 attributes.x = lives_widget_get_allocation_x(widget);
300 attributes.y = lives_widget_get_allocation_y(widget);
301 attributes.width = lives_widget_get_allocation_width(widget);
302 attributes.height = lives_widget_get_allocation_height(widget);
303 attributes.wclass = GDK_INPUT_OUTPUT;
304 attributes.window_type = GDK_WINDOW_CHILD;
305 attributes.event_mask = gtk_widget_get_events(widget) |
306 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
307 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
308 GDK_POINTER_MOTION_HINT_MASK;
309
310 attributes_mask = GDK_WA_X | GDK_WA_Y;
311
312
313 #if !GTK_CHECK_VERSION(3, 0, 0)
314 attributes_mask |= GDK_WA_COLORMAP | GDK_WA_VISUAL;
315 attributes.visual = gtk_widget_get_visual(widget);
316 attributes.colormap = gtk_widget_get_colormap(widget);
317 #endif
318
319 #if GTK_CHECK_VERSION(2,18,0)
320 gtk_widget_set_window(widget, gdk_window_new(lives_widget_get_xwindow(lives_widget_get_parent(widget)), &attributes,
321 attributes_mask));
322 #else
323 widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask);
324 #endif
325
326 #if GTK_CHECK_VERSION(3, 0, 0)
327 stylecon = gtk_style_context_new();
328 gtk_style_context_set_path(stylecon, gtk_widget_get_path(widget));
329 gtk_style_context_set_state(stylecon, GTK_STATE_FLAG_ACTIVE);
330 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
331 gtk_style_context_set_background(stylecon, lives_widget_get_xwindow(lives_widget_get_parent(widget)));
332 G_GNUC_END_IGNORE_DEPRECATIONS
333 #else
334 widget->style = gtk_style_attach(widget->style, lives_widget_get_xwindow(widget));
335 gtk_style_set_background(widget->style, lives_widget_get_xwindow(widget), GTK_STATE_ACTIVE);
336 #endif
337
338 gdk_window_set_user_data(lives_widget_get_xwindow(widget), widget);
339
340 // Create the initial legends
341 knob_build_legends(knob);
342 }
343
344
345
346
347 static void
348 giw_knob_size_request(GtkWidget *widget,
349 GtkRequisition *requisition) {
350 requisition->width = KNOB_DEFAULT_SIZE;
351 requisition->height = KNOB_DEFAULT_SIZE;
352 }
353
354 #if GTK_CHECK_VERSION(3, 0, 0)
355
356 static void
357 giw_knob_get_preferred_width(GtkWidget *widget,
358 gint *minimal_width,
359 gint *natural_width) {
360 GtkRequisition requisition;
361
362 giw_knob_size_request(widget, &requisition);
363
364 *minimal_width = *natural_width = requisition.width / 4.;
365 }
366
367 static void
368 giw_knob_get_preferred_height(GtkWidget *widget,
369 gint *minimal_height,
370 gint *natural_height) {
371 GtkRequisition requisition;
372
373 giw_knob_size_request(widget, &requisition);
374
375 *minimal_height = *natural_height = requisition.height / 4.;
376 }
377
378 #endif
379
380 static void
381 giw_knob_size_allocate(GtkWidget *widget,
382 GtkAllocation *allocation) {
383 GiwKnob *knob;
384
385 g_return_if_fail(widget != NULL);
386 g_return_if_fail(GIW_IS_KNOB(widget));
387 g_return_if_fail(allocation != NULL);
388
389 #if GTK_CHECK_VERSION(2,18,0)
390 gtk_widget_set_allocation(widget, allocation);
391 #else
392 widget->allocation = *allocation;
393 #endif
394
395 knob = GIW_KNOB(widget);
396
397 if (lives_widget_is_realized(widget)) {
398 gdk_window_move_resize(lives_widget_get_xwindow(widget),
399 allocation->x, allocation->y,
400 allocation->width, allocation->height);
401
402 }
403 knob_calculate_sizes(knob);
404 }
405
406
407 #if GTK_CHECK_VERSION(3, 0, 0)
408 static gboolean giw_knob_draw(GtkWidget *widget, cairo_t *cairo) {
409 //GdkRGBA color;
410 #else
411
412 static gint
413 giw_knob_expose(GtkWidget *widget,
414 GdkEventExpose *event) {
415 #endif
416 GiwKnob *knob;
417 gdouble s, c;
418 gint xc, yc;
419 gdouble loop1;
420 guint dx1, dy1, dx2, dy2;
421 gint counter = 0;
422 GdkRectangle rect;
423
424 g_return_val_if_fail(widget != NULL, FALSE);
425 g_return_val_if_fail(GIW_IS_KNOB(widget), FALSE);
426 #if !GTK_CHECK_VERSION(3, 0, 0)
427 g_return_val_if_fail(event != NULL, FALSE);
428 if (event->count > 0)
429 return FALSE;
430 #endif
431
432 knob = GIW_KNOB(widget);
433
434 rect.x = 0;
435 rect.y = 0;
436 rect.width = lives_widget_get_allocation_width(widget);
437 rect.height = lives_widget_get_allocation_height(widget);
438
439 // The center
440 xc = lives_widget_get_allocation_width(widget) / 2;
441 yc = lives_widget_get_allocation_height(widget) / 2;
442
443 s = sin(knob->angle);
444 c = cos(knob->angle);
445
446
447 #if GTK_CHECK_VERSION(3, 0, 0)
448 gtk_render_background(gtk_widget_get_style_context(widget),
449 cairo,
450 0,
451 0,
452 rect.width,
453 rect.height);
454
455 cairo_set_source_rgb(cairo, 0., 0., 0.);
456
457 cairo_arc(cairo,
458 knob->x + ((knob->size / 2)),
459 knob->y + ((knob->size / 2)),
460 knob->radius,
461 0,
462 2.*M_PI);
463
464 cairo_fill(cairo);
465
466 // not working
467 /*
468 gtk_style_context_get_color (gtk_widget_get_style_context (widget), gtk_widget_get_state(widget), &color);
469 cairo_set_source_rgba (cairo, color.red, color.green, color.blue, color.alpha);
470
471 cairo_arc(cairo,
472 knob->x+((knob->size/2)),
473 knob->y+((knob->size/2)),
474 knob->radius/4.*3.,
475 0,
476 2.*M_PI);
477
478 cairo_fill(cairo);*/
479
480
481 cairo_set_source_rgb(cairo, 1., 1., 1.);
482
483 cairo_move_to(cairo,
484 xc + c * ((float)knob->radius * 0.6),
485 yc - s * ((float)knob->radius * 0.6));
486
487 cairo_line_to(cairo,
488 xc + c * knob->radius,
489 yc - s * knob->radius);
490
491 cairo_stroke(cairo);
492
493 cairo_arc(cairo,
494 xc + c * ((float)knob->radius * 0.8),
495 yc - s * ((float)knob->radius * 0.8),
496 knob->radius / 2 * 0.1,
497 0,
498 2.*M_PI);
499
500 cairo_fill(cairo);
501
502 if ((knob->mouse_policy == GIW_KNOB_MOUSE_DELAYED) & (knob->button != 0)) {
503 s = sin(knob->false_angle);
504 c = cos(knob->false_angle);
505
506 //lives_widget_get_fg_state_color (widget, GTK_STATE_FLAG_PRELIGHT, &color);
507
508 cairo_move_to(cairo,
509 xc + c * ((float)knob->radius * 0.8),
510 yc - s * ((float)knob->radius * 0.8));
511 cairo_line_to(cairo,
512 xc + c * knob->radius,
513 yc - s * knob->radius);
514
515
516 }
517
518 // Now, draw the ticks
519 // The major ticks (and legends)
520 if (knob->major_ticks != 0)
521 for (loop1 = (3.0 * M_PI / 2.0); loop1 >= -0.0001;
522 loop1 -= knob->d_major_ticks) { // -0.0001 (and not 0) to avoid rounding errors
523 s = sin(loop1 - M_PI / 4.0);
524 c = cos(loop1 - M_PI / 4.0);
525 dx1 = c * knob->radius;
526 dy1 = s * knob->radius;
527 dx2 = c * (knob->radius + knob->major_ticks_size);
528 dy2 = s * (knob->radius + knob->major_ticks_size);
529 cairo_move_to(cairo,
530 xc + dx1,
531 yc - dy1);
532
533 cairo_line_to(cairo,
534 xc + dx2,
535 yc - dy2);
536
537 cairo_stroke(cairo);
538
539 // Drawing the legends
540 if (knob->legends_digits != 0)
541 gtk_render_layout(gtk_widget_get_style_context(widget),
542 cairo,
543 xc + (c * knob->legend_radius) - (knob->legend_width / 2),
544 yc - (s * knob->legend_radius) - (knob->legend_height / 2),
545 knob->legends[counter]);
546 counter++;
547 }
548
549
550 // The minor ticks
551 if (knob->minor_ticks != 0)
552 for (loop1 = (3.0 * M_PI / 2.0); loop1 >= 0.0; loop1 -= knob->d_minor_ticks) {
553 s = sin(loop1 - M_PI / 4.0);
554 c = cos(loop1 - M_PI / 4.0);
555 dx1 = c * knob->radius;
556 dy1 = s * knob->radius;
557 dx2 = c * (knob->radius + knob->minor_ticks_size);
558 dy2 = s * (knob->radius + knob->minor_ticks_size);
559 cairo_move_to(cairo,
560 xc + dx1,
561 yc - dy1);
562 cairo_line_to(cairo,
563 xc + dx2,
564 yc - dy2);
565 cairo_stroke(cairo);
566 }
567
568 // Draw the title
569 if (knob->title_str != NULL) // font_str==NULL means no title
570 gtk_render_layout(gtk_widget_get_style_context(widget),
571 cairo,
572 xc - knob->title_width / 2,
573 knob->size - knob->title_height - 5, // 5 pixels to separate from the borders
574 knob->title);
575
576 #else
577 // Drawing background
578 gtk_paint_flat_box(widget->style,
579 widget->window,
580 GTK_STATE_NORMAL,
581 GTK_SHADOW_NONE,
582 &rect,
583 widget,
584 NULL,
585 0,
586 0,
587 -1,
588 -1);
589
590 // The arc
591 gdk_draw_arc(widget->window,
592 widget->style->black_gc,
593 TRUE,
594 knob->x + ((knob->size / 2) - knob->radius),
595 knob->y + ((knob->size / 2) - knob->radius),
596 knob->radius * 2,
597 knob->radius * 2,
598 0,
599 360 * 64);
600
601
602
603 gdk_draw_line(widget->window,
604 widget->style->white_gc,
605 xc + c * ((float)knob->radius * 0.6),
606 yc - s * ((float)knob->radius * 0.6),
607 xc + c * knob->radius,
608 yc - s * knob->radius);
609 gdk_draw_arc(widget->window,
610 widget->style->white_gc,
611 TRUE,
612 xc + c * ((float)knob->radius * 0.8) - knob->radius * 0.1,
613 yc - s * ((float)knob->radius * 0.8) - knob->radius * 0.1,
614 knob->radius * 0.2,
615 knob->radius * 0.2,
616 0,
617 360 * 64);
618
619 // Draw the false-pointer if the delayed policy of mouse is set and a button is pressed
620 if ((knob->mouse_policy == GIW_KNOB_MOUSE_DELAYED) & (knob->button != 0)) {
621 s = sin(knob->false_angle);
622 c = cos(knob->false_angle);
623
624 gdk_draw_line(widget->window,
625 widget->style->fg_gc[widget->state],
626 xc + c * ((float)knob->radius * 0.8),
627 yc - s * ((float)knob->radius * 0.8),
628 xc + c * knob->radius,
629 yc - s * knob->radius);
630
631 gdk_draw_arc(widget->window,
632 widget->style->black_gc,
633 FALSE,
634 xc + c * ((float)knob->radius * 0.8) - knob->radius * 0.1,
635 yc - s * ((float)knob->radius * 0.8) - knob->radius * 0.1,
636 knob->radius * 0.2,
637 knob->radius * 0.2,
638 0,
639 360 * 64);
640 }
641
642 // Now, draw the ticks
643 // The major ticks (and legends)
644 if (knob->major_ticks != 0)
645 for (loop1 = (3.0 * M_PI / 2.0); loop1 >= -0.0001;
646 loop1 -= knob->d_major_ticks) { // -0.0001 (and not 0) to avoid rounding errors
647 s = sin(loop1 - M_PI / 4.0);
648 c = cos(loop1 - M_PI / 4.0);
649 dx1 = c * knob->radius;
650 dy1 = s * knob->radius;
651 dx2 = c * (knob->radius + knob->major_ticks_size);
652 dy2 = s * (knob->radius + knob->major_ticks_size);
653 gdk_draw_line(widget->window,
654 widget->style->fg_gc[widget->state],
655 xc + dx1,
656 yc - dy1,
657 xc + dx2,
658 yc - dy2);
659 // Drawing the legends
660 if (knob->legends_digits != 0)
661 gtk_paint_layout(widget->style,
662 widget->window,
663 GTK_STATE_NORMAL,
664 TRUE,
665 &rect,
666 widget,
667 NULL,
668 xc + (c * knob->legend_radius) - (knob->legend_width / 2),
669 yc - (s * knob->legend_radius) - (knob->legend_height / 2),
670 knob->legends[counter]);
671 counter++;
672 }
673 // The minor ticks
674 if (knob->minor_ticks != 0)
675 for (loop1 = (3.0 * M_PI / 2.0); loop1 >= 0.0; loop1 -= knob->d_minor_ticks) {
676 s = sin(loop1 - M_PI / 4.0);
677 c = cos(loop1 - M_PI / 4.0);
678 dx1 = c * knob->radius;
679 dy1 = s * knob->radius;
680 dx2 = c * (knob->radius + knob->minor_ticks_size);
681 dy2 = s * (knob->radius + knob->minor_ticks_size);
682 gdk_draw_line(widget->window,
683 widget->style->fg_gc[widget->state],
684 xc + dx1,
685 yc - dy1,
686 xc + dx2,
687 yc - dy2);
688 }
689
690 // Draw the title
691 if (knob->title_str != NULL) // font_str==NULL means no title
692 gtk_paint_layout(widget->style,
693 widget->window,
694 GTK_STATE_NORMAL,
695 TRUE,
696 &rect,
697 widget,
698 NULL,
699 xc - knob->title_width / 2,
700 knob->size - knob->title_height - 5, // 5 pixels to separate from the borders
701 knob->title);
702
703 #endif
704
705 return FALSE;
706 }
707
708
709 static gint
710 giw_knob_button_press(GtkWidget *widget,
711 GdkEventButton *event) {
712 GiwKnob *knob;
713 gint xc, yc, dx, dy;
714
715 g_return_val_if_fail(widget != NULL, TRUE);
716 g_return_val_if_fail(GIW_IS_KNOB(widget), TRUE);
717 g_return_val_if_fail(event != NULL, TRUE);
718
719 knob = GIW_KNOB(widget);
720
721 if (knob->mouse_policy == GIW_KNOB_MOUSE_DISABLED) return TRUE;
722 if (knob->button) return TRUE; // Some button is already pressed
723
724 /* To verify if the pointer is in the knob, the distance between the pointer and the center
725 of the circle is calculated, if it's less than the radius of the circle , it's in!!*/
726
727 xc = lives_widget_get_allocation_width(widget) / 2;
728 yc = lives_widget_get_allocation_height(widget) / 2;
729
730 dx = abs((int)event->x - xc);
731 dy = abs((int)event->y - yc);
732
733 if (!knob->button & (dx < knob->radius) & (dy < knob->radius))
734 knob->button = event->button;
735
736 return FALSE;
737 }
738
739 static gint
740 giw_knob_button_release(GtkWidget *widget,
741 GdkEventButton *event) {
742 GiwKnob *knob;
743 gint x, y;
744
745 g_return_val_if_fail(widget != NULL, TRUE);
746 g_return_val_if_fail(GIW_IS_KNOB(widget), TRUE);
747 g_return_val_if_fail(event != NULL, TRUE);
748
749 knob = GIW_KNOB(widget);
750
751 g_return_val_if_fail(knob->adjustment != NULL, TRUE);
752
753 if (knob->mouse_policy == GIW_KNOB_MOUSE_DISABLED) return TRUE;
754
755 // If the policy is delayed, now that the button was released (if it is), it's time to update the value
756 if ((knob->mouse_policy == GIW_KNOB_MOUSE_DELAYED) &&
757 (knob->button == event->button)) {
758 x = event->x;
759 y = event->y;
760
761 knob_update_mouse(knob, x, y);
762 }
763
764
765 if (knob->button == event->button)
766 knob->button = 0;
767
768 return FALSE;
769 }
770
771 static gint
772 giw_knob_motion_notify(GtkWidget *widget,
773 GdkEventMotion *event) {
774 GiwKnob *knob;
775 gint x, y;
776
777 g_return_val_if_fail(widget != NULL, TRUE);
778 g_return_val_if_fail(GTK_IS_WIDGET(widget), TRUE);
779 g_return_val_if_fail(GIW_IS_KNOB(widget), TRUE);
780 g_return_val_if_fail(event != NULL, TRUE);
781
782 knob = GIW_KNOB(widget);
783
784 g_return_val_if_fail(knob->adjustment != NULL, TRUE);
785
786 if (knob->mouse_policy == GIW_KNOB_MOUSE_DISABLED) return TRUE;
787
788 // If the some button is pressed and the policy is set to update the value AUTOMATICALLY, update the knob's value
789 if ((knob->button != 0) && (knob->mouse_policy == GIW_KNOB_MOUSE_AUTOMATICALLY)) {
790 x = event->x;
791 y = event->y;
792
793 if (event->is_hint || (event->window != lives_widget_get_xwindow(widget)))
794 #if GTK_CHECK_VERSION(3, 0, 0)
795 gdk_window_get_device_position(lives_widget_get_xwindow(widget),
796 gdk_event_get_device((GdkEvent *)(event)),
797 &x,
798 &y,
799 NULL);
800 #else
801 gdk_window_get_pointer(lives_widget_get_xwindow(widget), &x, &y, NULL);
802 #endif
803 knob_update_mouse(knob, x, y);
804 }
805
806 // If the some button is pressed and the policy is set to update the value delayed, update the knob's false pointer's angle
807 if ((knob->button != 0) && (knob->mouse_policy == GIW_KNOB_MOUSE_DELAYED)) {
808 x = event->x;
809 y = event->y;
810
811 if (event->is_hint || (event->window != lives_widget_get_xwindow(widget)))
812 #if GTK_CHECK_VERSION(3, 0, 0)
813 gdk_window_get_device_position(lives_widget_get_xwindow(widget),
814 gdk_event_get_device((GdkEvent *)(event)),
815 &x,
816 &y,
817 NULL);
818 #else
819 gdk_window_get_pointer(lives_widget_get_xwindow(widget), &x, &y, NULL);
820 #endif
821
822 knob_update_false_mouse(knob, x, y);
823 }
824
825 /*if (knob->button != 0)
826 {
827 x = event->x;
828 y = event->y;
829
830 if (event->is_hint || (event->window != widget->window))
831 gdk_window_get_pointer (widget->window, &x, &y, NULL);
832
833 knob_update_mouse (knob, x,y);
834 }*/
835
836 return FALSE;
837 }
838
839 static void
840 giw_knob_style_set(GtkWidget *widget,
841 GtkStyle *previous_style) {
842 GiwKnob *knob;
843
844 g_return_if_fail(widget != NULL);
845 g_return_if_fail(GIW_IS_KNOB(widget));
846
847 knob = GIW_KNOB(widget);
848
849 // The only thing to fo is recalculate the layout's sizes
850 knob_calculate_legends_sizes(knob);
851 knob_calculate_title_sizes(knob);
852 }
853
854 #if GTK_CHECK_VERSION(3, 0, 0)
855 static void
856 giw_knob_style_updated(GtkWidget *widget) {
857
858 }
859
860 #endif
861
862 /******************
863 Users Functions
864 ******************/
865
866 gdouble
867 giw_knob_get_value(GiwKnob *knob) {
868 g_return_val_if_fail(knob != NULL, 0.0);
869 g_return_val_if_fail(GIW_IS_KNOB(knob), 0.0);
870
871 return (gtk_adjustment_get_value(knob->adjustment));
872 }
873
874 void
875 giw_knob_set_value(GiwKnob *knob,
876 gdouble value) {
877 g_return_if_fail(knob != NULL);
878 g_return_if_fail(GIW_IS_KNOB(knob));
879
880
881 if (value != gtk_adjustment_get_value(knob->adjustment)) {
882 knob_set_value(knob, value);
883 g_return_if_fail(knob->adjustment != NULL);
884 #if !GTK_CHECK_VERSION(3,18,0)
885 gtk_adjustment_value_changed(knob->adjustment);
886 #endif
887 }
888 }
889
890 void
891 giw_knob_set_adjustment(GiwKnob *knob,
892 GtkAdjustment *adjustment) {
893 g_return_if_fail(knob != NULL);
894 g_return_if_fail(GIW_IS_KNOB(knob));
895 g_return_if_fail(adjustment != NULL);
896
897 // Freeing the last one
898 if (knob->adjustment) {
899 #if GTK_CHECK_VERSION(3, 0, 0)
900 g_signal_handler_disconnect((gpointer)(knob->adjustment), knob->chsig);
901 g_signal_handler_disconnect((gpointer)(knob->adjustment), knob->vchsig);
902 #else
903 gtk_signal_disconnect_by_data(LIVES_GUI_OBJECT(knob->adjustment), (gpointer) knob);
904 #endif
905 g_object_unref(LIVES_GUI_OBJECT(knob->adjustment));
906 }
907
908 knob->adjustment = adjustment;
909 g_object_ref(LIVES_GUI_OBJECT(knob->adjustment));
910
911 knob->chsig = g_signal_connect(LIVES_GUI_OBJECT(adjustment), "changed",
912 (GCallback) giw_knob_adjustment_changed,
913 (gpointer) knob);
914 knob->vchsig = g_signal_connect(LIVES_GUI_OBJECT(adjustment), "value_changed",
915 (GCallback) giw_knob_adjustment_value_changed,
916 (gpointer) knob);
917
918 #if !GTK_CHECK_VERSION(3,18,0)
919 gtk_adjustment_value_changed(knob->adjustment);
920 gtk_adjustment_changed(knob->adjustment);
921 #endif
922 }
923
924 GtkAdjustment *
925 giw_knob_get_adjustment(GiwKnob *knob) {
926 g_return_val_if_fail(knob != NULL, NULL);
927 g_return_val_if_fail(GIW_IS_KNOB(knob), NULL);
928
929 return (knob->adjustment);
930 }
931
932
933 void
934 giw_knob_set_wrap(GiwKnob *knob,
935 gboolean wrap) {
936 g_return_if_fail(knob != NULL);
937 g_return_if_fail(GIW_IS_KNOB(knob));
938
939 knob->wrap = wrap;
940
941 knob_build_legends(knob);
942 knob_calculate_sizes(knob);
943 knob_set_angle(knob, knob_calculate_angle_with_value(knob, gtk_adjustment_get_value(knob->adjustment)));
944 gtk_widget_queue_draw(GTK_WIDGET(knob));
945 }
946
947
948
949 void
950 giw_knob_set_legends_digits(GiwKnob *knob,
951 guint digits_number) {
952 g_return_if_fail(knob != NULL);
953 g_return_if_fail(GIW_IS_KNOB(knob));
954
955 if (digits_number != knob->legends_digits) {
956 knob_free_legends(knob);
957
958 knob->legends_digits = digits_number;
959
960 knob_build_legends(knob);
961 knob_calculate_sizes(knob);
962 gtk_widget_queue_draw(GTK_WIDGET(knob));
963 }
964 }
965
966 void
967 giw_knob_set_ticks_number(GiwKnob *knob,
968 guint major, guint minor) {
969 g_return_if_fail(knob != NULL);
970 g_return_if_fail(GIW_IS_KNOB(knob));
971
972 if ((major != knob->major_ticks) || (minor != knob->minor_ticks)) {
973 knob_free_legends(knob);
974
975 knob->major_ticks = major;
976
977 if (knob->major_ticks == 0)
978 knob->minor_ticks = 0; // It's impossible to have minor ticks without major ticks
979 else
980 knob->minor_ticks = minor;
981
982 knob_build_legends(knob);
983 knob_calculate_sizes(knob);
984 gtk_widget_queue_draw(GTK_WIDGET(knob));
985 }
986 }
987
988 void
989 giw_knob_set_mouse_policy(GiwKnob *knob,
990 GiwKnobMousePolicy policy) {
991 g_return_if_fail(knob != NULL);
992 g_return_if_fail(GIW_IS_KNOB(knob));
993
994 if (knob->button == 0) // The policy can only be change when there is no button pressed
995 knob->mouse_policy = policy;
996 }
997
998 static void
999 giw_knob_adjustment_changed(GtkAdjustment *adjustment,
1000 gpointer data) {
1001 GiwKnob *knob;
1002
1003 g_return_if_fail(adjustment != NULL);
1004 g_return_if_fail(data != NULL);
1005
1006 knob = GIW_KNOB(data);
1007
1008 knob_free_legends(knob);
1009 knob_build_legends(knob);
1010 knob_calculate_sizes(knob);
1011 gtk_widget_queue_draw(GTK_WIDGET(knob));
1012 }
1013
1014 static void
1015 giw_knob_adjustment_value_changed(GtkAdjustment *adjustment,
1016 gpointer data) {
1017 GiwKnob *knob;
1018
1019 g_return_if_fail(adjustment != NULL);
1020 g_return_if_fail(data != NULL);
1021
1022 knob = GIW_KNOB(data);
1023
1024 knob_set_angle(knob, knob_calculate_angle_with_value(knob, gtk_adjustment_get_value(adjustment)));
1025
1026 gtk_widget_queue_draw(GTK_WIDGET(knob));
1027 }
1028
1029 void
1030 giw_knob_set_title(GiwKnob *knob, gchar *str) {
1031 g_return_if_fail(knob != NULL);
1032 g_return_if_fail(GIW_IS_KNOB(knob));
1033
1034 knob->title_str = g_strdup(str); // Duplicate the string, after this, str can be freed
1035
1036 knob_build_title(knob);
1037 knob_calculate_sizes(knob);
1038 gtk_widget_queue_draw(GTK_WIDGET(knob));
1039 }
1040
1041 /******************
1042 Local Functions
1043 ******************/
1044
1045 void
1046 knob_update_mouse(GiwKnob *knob, gint x, gint y) {
1047 gint xc, yc;
1048
1049 g_return_if_fail(knob != NULL);
1050 g_return_if_fail(GIW_IS_KNOB(knob));
1051
1052 gtk_widget_queue_draw(GTK_WIDGET(knob));
1053
1054 xc = lives_widget_get_allocation_width(LIVES_WIDGET(knob)) / 2;
1055 yc = lives_widget_get_allocation_height(LIVES_WIDGET(knob)) / 2;
1056
1057 // Calculating the new angle
1058 if (knob->angle != atan2(yc - y, x - xc)) {
1059 knob_set_value(knob, knob_calculate_value_with_angle(knob, atan2(yc - y, x - xc)));
1060 g_return_if_fail(knob->adjustment != NULL);
1061 #if !GTK_CHECK_VERSION(3,18,0)
1062 gtk_adjustment_value_changed(knob->adjustment);
1063 #endif
1064 }
1065 }
1066
1067 void
1068 knob_update_false_mouse(GiwKnob *knob, gint x, gint y) {
1069 gint xc, yc;
1070
1071 g_return_if_fail(knob != NULL);
1072 g_return_if_fail(GIW_IS_KNOB(knob));
1073
1074 xc = lives_widget_get_allocation_width(LIVES_WIDGET(knob)) / 2;
1075 yc = lives_widget_get_allocation_height(LIVES_WIDGET(knob)) / 2;
1076
1077 // Calculating the new angle
1078 knob->false_angle = atan2(yc - y, x - xc);
1079
1080 // Putting the angle between 0 and 2PI, because the atan2 returns the angle between PI and -PI
1081 while (knob->false_angle < 0)
1082 knob->false_angle += (2.0 * M_PI);
1083
1084 if (!knob->wrap) {
1085 // Taking out of the "forbidden" region
1086 if ((knob->false_angle <= (3.0 * M_PI / 2.0)) &&
1087 (knob->false_angle > (5.0 * M_PI / 4.0)))
1088 knob->false_angle = 5.0 * M_PI / 4.0;
1089 if ((knob->false_angle < (7.0 * M_PI / 4.0)) &&
1090 (knob->false_angle >= (3.0 * M_PI / 2.0)))
1091 knob->false_angle = 7.0 * M_PI / 4.0;
1092 }
1093
1094 gtk_widget_queue_draw(GTK_WIDGET(knob));
1095 }
1096
1097 static void
1098 knob_calculate_sizes(GiwKnob *knob) {
1099 GtkWidget *widget;
1100
1101 g_return_if_fail(knob != NULL);
1102 g_return_if_fail(GIW_IS_KNOB(knob));
1103
1104 widget = GTK_WIDGET(knob);
1105
1106 // Getting the radius and size
1107 if (lives_widget_get_allocation_width(widget) < lives_widget_get_allocation_height(widget)) {
1108 knob->size = lives_widget_get_allocation_width(widget);
1109 knob->x = 0;
1110 knob->y = lives_widget_get_allocation_height(widget) / 2 - knob->size / 2;
1111 } else {
1112 knob->size = lives_widget_get_allocation_height(widget);
1113 knob->y = 0;
1114 knob->x = lives_widget_get_allocation_width(widget) / 2 - knob->size / 2;
1115 }
1116
1117 // The distance between the radius and the widget limits is the bigger dimension of the legends plus the major_ticks_size,
1118 // so it's the half of size, less the bigger dimension of the legends less the major_ticks size (wich depends of the radius),
1119 // then, with some algebra, it results in this equation:
1120 knob->radius = 8 * ((knob->size / 2) - sqrt(knob->legend_width * knob->legend_width + knob->legend_height *
1121 knob->legend_height)) / 9;
1122
1123 if (!knob->wrap)
1124 knob->d_major_ticks = (3.0 * M_PI / 2.0) / (knob->major_ticks - 1);
1125 else
1126 knob->d_major_ticks = (2.0 * M_PI) / (knob->major_ticks - 1);
1127
1128 knob->d_minor_ticks = knob->d_major_ticks / (knob->minor_ticks + 1);
1129
1130 knob->major_ticks_size = knob->radius / 8.0;
1131 knob->minor_ticks_size = knob->radius / 16.0;
1132
1133 // The legend will in the middle of the inside (plus the major_ticks_size) and outside circle
1134 knob->legend_radius = ((knob->radius + knob->major_ticks_size + (knob->size / 2)) / 2);
1135 }
1136
1137 gdouble
1138 knob_calculate_value_with_angle(GiwKnob *knob, gdouble angle) {
1139 gdouble d_angle = 0.0; // How many the pointer is far from the lower angle (5PI/4)
1140
1141 g_return_val_if_fail(knob != NULL, 0.0);
1142 g_return_val_if_fail(GIW_IS_KNOB(knob), 0.0);
1143
1144 // Putting the angle between 0 and 2PI, because the atan2 returns the angle between PI and -PI
1145 while (angle < 0)
1146 angle = angle + (2.0 * M_PI);
1147
1148 if (!knob->wrap) {
1149 // Taking out of the "forbidden" region
1150 if ((angle <= (3.0 * M_PI / 2.0)) && (angle > (5.0 * M_PI / 4.0))) angle = 5.0 * M_PI / 4.0;
1151 if ((angle < (7.0 * M_PI / 4.0)) && (angle >= (3.0 * M_PI / 2.0))) angle = 7.0 * M_PI / 4.0;
1152
1153 // Calculating the distance (in radians) between the pointer and the lower angle
1154 if (angle <= (5.0 * M_PI / 4.0)) d_angle = (5.0 * M_PI / 4.0) - angle;
1155 if (angle >= (7.0 * M_PI / 4.0)) d_angle = (13.0 * M_PI / 4.0) - angle;
1156
1157 return (lives_adjustment_get_lower(knob->adjustment) +
1158 fabs(lives_adjustment_get_upper(knob->adjustment) - lives_adjustment_get_lower(knob->adjustment)) * d_angle /
1159 (3.0 * M_PI / 2.0));
1160 }
1161
1162 if (angle < 3 * M_PI / 2.) d_angle = (3.*M_PI / 2.) - angle;
1163 else d_angle = 7. / 2.*M_PI - angle;
1164 return (lives_adjustment_get_lower(knob->adjustment) +
1165 fabs(lives_adjustment_get_upper(knob->adjustment) - lives_adjustment_get_lower(knob->adjustment)) * d_angle / (2.0 * M_PI));
1166 }
1167
1168
1169
1170 gdouble
1171 knob_calculate_angle_with_value(GiwKnob *knob, gdouble value) {
1172 gdouble angle;
1173
1174 g_return_val_if_fail(knob != NULL, 0.0);
1175 g_return_val_if_fail(GIW_IS_KNOB(knob), 0.0);
1176 g_return_val_if_fail(knob->adjustment != NULL, 0.0);
1177
1178 if (!knob->wrap) {
1179 angle = (value - lives_adjustment_get_lower(knob->adjustment)) *
1180 (3.0 * M_PI / 2.0) / fabs(lives_adjustment_get_upper(knob->adjustment) - lives_adjustment_get_lower(knob->adjustment));
1181
1182 // Now, the angle is relative to the 3 o'clock position, and need to be changed in order to be relative to the initial angle ((5.0*M_PI/4.0)
1183 angle = (5.0 * M_PI / 4.0) - angle;
1184 } else {
1185 angle = (value - lives_adjustment_get_lower(knob->adjustment)) *
1186 (2.0 * M_PI) / fabs(lives_adjustment_get_upper(knob->adjustment) - lives_adjustment_get_lower(knob->adjustment));
1187
1188 // Now, the angle is relative to the 3 o'clock position, and need to be changed in order to be relative to the initial angle (3*M_PI/2)
1189 angle = 3.*M_PI / 2. - angle;
1190 }
1191
1192 return (angle);
1193 }
1194
1195
1196 void
1197 knob_set_angle(GiwKnob *knob,
1198 gdouble angle) {
1199
1200 g_return_if_fail(knob != NULL);
1201 g_return_if_fail(GIW_IS_KNOB(knob));
1202
1203 // Putting the angle between 0 and 2PI(360�)
1204 while (angle > 2.0 * M_PI)
1205 angle = angle - (2.0 * M_PI);
1206
1207 while (angle < 0)
1208 angle = angle + (2.0 * M_PI);
1209
1210 if (knob->angle != angle) {
1211 if (!knob->wrap) {
1212 // Taking out of the "forbidden" region
1213 if ((angle <= (3.0 * M_PI / 2.0)) && (angle > (5.0 * M_PI / 4.0))) angle = 5.0 * M_PI / 4.0;
1214 if ((angle < (7.0 * M_PI / 4.0)) && (angle >= (3.0 * M_PI / 2.0))) angle = 7.0 * M_PI / 4.0;
1215 }
1216 knob->angle = angle;
1217 }
1218 }
1219
1220 void
1221 knob_set_value(GiwKnob *knob,
1222 gdouble value) {
1223 g_return_if_fail(knob != NULL);
1224 g_return_if_fail(GIW_IS_KNOB(knob));
1225 g_return_if_fail(knob->adjustment != NULL);
1226
1227 gtk_adjustment_set_value(knob->adjustment, value);
1228 }
1229
1230 void
1231 knob_build_legends(GiwKnob *knob) {
1232 GtkWidget *widget;
1233 gint loop;
1234 gchar *str;
1235
1236 g_return_if_fail(knob != NULL);
1237
1238 widget = GTK_WIDGET(knob);
1239
1240 if (knob->major_ticks == 0) // Preventing from bugs
1241 return;
1242
1243 // Creating the legend's layouts
1244 if (knob->legends_digits != 0) {
1245 knob->legends = g_new(PangoLayout *, knob->major_ticks);
1246 str = g_new(gchar, knob->legends_digits + 1); // +1 for the '/0'
1247 for (loop = 0; loop < knob->major_ticks; loop++) {
1248 snprintf(str, knob->legends_digits + 1, "%f",
1249 lives_adjustment_get_lower(knob->adjustment) +
1250 loop * (lives_adjustment_get_upper(knob->adjustment) -
1251 lives_adjustment_get_lower(knob->adjustment)) /
1252 (knob->major_ticks - 1)); // Creating the legends string
1253 knob->legends[loop] = gtk_widget_create_pango_layout(widget, str);
1254 }
1255 g_free(str);
1256
1257 // Getting the size of the legends
1258 knob_calculate_legends_sizes(knob);
1259 } else { // If there are no legends (0 digits), the size is the major ticks size (5)
1260 knob->legend_width = 0;
1261 knob->legend_height = 0;
1262 }
1263 }
1264
1265 void
1266 knob_free_legends(GiwKnob *knob) {
1267 gint loop;
1268
1269 g_return_if_fail(knob != NULL);
1270
1271 if (knob->legends != NULL) {
1272 for (loop = 0; loop < knob->major_ticks; loop++)
1273 if (knob->legends[loop] != NULL)
1274 g_object_unref(G_OBJECT(knob->legends[loop]));
1275 g_free(knob->legends);
1276 knob->legends = NULL;
1277 }
1278 }
1279
1280 void
1281 knob_build_title(GiwKnob *knob) {
1282 GtkWidget *widget;
1283
1284 g_return_if_fail(knob != NULL);
1285
1286 widget = GTK_WIDGET(knob);
1287
1288 if (knob->title_str == NULL) // Return if there is no title (the layout will be keeped, but not drawed)
1289 return;
1290
1291 if (knob->title)
1292 pango_layout_set_text(knob->title, knob->title_str, strlen(knob->title_str));
1293 else // If the title hasn't been created yet..
1294 knob->title = gtk_widget_create_pango_layout(widget, knob->title_str);
1295
1296 // Calculating new size
1297 knob_calculate_title_sizes(knob);
1298 }
1299
1300 void
1301 knob_calculate_legends_sizes(GiwKnob *knob) {
1302 GtkWidget *widget;
1303
1304 #if GTK_CHECK_VERSION(3,8,0)
1305 PangoFontDescription *fontdesc;
1306 #endif
1307
1308 g_return_if_fail(knob != NULL);
1309
1310 widget = GTK_WIDGET(knob);
1311
1312 if (knob->legends != NULL) {
1313
1314 #if GTK_CHECK_VERSION(3, 0, 0)
1315 #if GTK_CHECK_VERSION(3,8,0)
1316 fontdesc = pango_font_description_new();
1317 gtk_style_context_get(gtk_widget_get_style_context(widget),
1318 gtk_widget_get_state_flags(widget),
1319 GTK_STYLE_PROPERTY_FONT,
1320 &fontdesc,
1321 NULL
1322 );
1323 pango_layout_set_font_description(knob->legends[0], fontdesc);
1324 pango_font_description_free(fontdesc);
1325 #else
1326 pango_layout_set_font_description(knob->legends[0],
1327 gtk_style_context_get_font(gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget)));
1328 #endif
1329 #else
1330 pango_layout_set_font_description(knob->legends[0], widget->style->font_desc);
1331 #endif
1332 pango_layout_get_size(knob->legends[0], &(knob->legend_width), &(knob->legend_height));
1333 knob->legend_width /= PANGO_SCALE;
1334 knob->legend_height /= PANGO_SCALE;
1335 }
1336 }
1337
1338 void
1339 knob_calculate_title_sizes(GiwKnob *knob) {
1340 GtkWidget *widget;
1341
1342 #if GTK_CHECK_VERSION(3,8,0)
1343 PangoFontDescription *fontdesc;
1344 #endif
1345
1346 g_return_if_fail(knob != NULL);
1347
1348 if (knob->title == NULL) return;
1349
1350 widget = GTK_WIDGET(knob);
1351
1352 #if GTK_CHECK_VERSION(3, 0, 0)
1353 #if GTK_CHECK_VERSION(3,8,0)
1354 fontdesc = pango_font_description_new();
1355 gtk_style_context_get(gtk_widget_get_style_context(widget),
1356 gtk_widget_get_state_flags(widget),
1357 GTK_STYLE_PROPERTY_FONT,
1358 &fontdesc,
1359 NULL
1360 );
1361 pango_layout_set_font_description(knob->legends[0], fontdesc);
1362 pango_font_description_free(fontdesc);
1363 #else
1364 pango_layout_set_font_description(knob->legends[0],
1365 gtk_style_context_get_font(gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget)));
1366 #endif
1367 #else
1368 pango_layout_set_font_description(knob->legends[0], widget->style->font_desc);
1369 #endif
1370 pango_layout_get_size(knob->title, &(knob->title_width), &(knob->title_height));
1371 knob->title_width /= PANGO_SCALE;
1372 knob->title_height /= PANGO_SCALE;
1373
1374 knob_calculate_sizes(knob);
1375 }
1376