1 /* giwled.c - GiwLed widget's source
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 - 2013
24
25 #include <math.h>
26 #include <stdio.h>
27
28 #include "main.h"
29
30 #include "giw/giwled.h"
31
32 #define LED_DEFAULT_SIZE 14
33
34 enum {
35 MODE_CHANGED_SIGNAL,
36 LAST_SIGNAL
37 };
38
39 /* Forward declarations */
40
41 static void giw_led_class_init(GiwLedClass *klass);
42 static void giw_led_init(GiwLed *led);
43 static void giw_led_realize(GtkWidget *widget);
44 static void giw_led_size_allocate(GtkWidget *widget,
45 GtkAllocation *allocation);
46 static gint giw_led_button_press(GtkWidget *widget,
47 GdkEventButton *event);
48 static void giw_led_size_request(GtkWidget *widget,
49 GtkRequisition *requisition);
50 #if GTK_CHECK_VERSION(3, 0, 0)
51 static void giw_led_dispose(GObject *object);
52 static void giw_led_get_preferred_width(GtkWidget *widget,
53 gint *minimal_width,
54 gint *natural_width);
55 static void giw_led_get_preferred_height(GtkWidget *widget,
56 gint *minimal_height,
57 gint *natural_height);
58 static gboolean giw_led_draw(GtkWidget *widget, cairo_t *cairo);
59 static void giw_led_style_updated(GtkWidget *widget);
60 static void giw_led_state_flags_changed(GtkWidget *widget,
61 GtkStateFlags previous_state);
62 #else
63 static gint giw_led_expose(GtkWidget *widget,
64 GdkEventExpose *event);
65 static void giw_led_destroy(GtkObject *object);
66 #endif
67
68 /* Local data */
69
70 static guint giw_led_signals[LAST_SIGNAL] = { 0 };
71
72
73 #if GTK_CHECK_VERSION(3, 0, 0)
G_DEFINE_TYPE(GiwLed,giw_led,GTK_TYPE_WIDGET)74 G_DEFINE_TYPE(GiwLed, giw_led, GTK_TYPE_WIDGET)
75 #define parent_class giw_led_parent_class
76 #else
77 static GtkWidgetClass *parent_class = NULL;
78
79
80 /*********************
81 Widget's Functions
82 *********************/
83
84 GType giw_led_get_type() {
85 static GType led_type = 0;
86
87 if (!led_type) {
88 static const GtkTypeInfo led_info = {
89 "GiwLed",
90 sizeof(GiwLed),
91 sizeof(GiwLedClass),
92 (GtkClassInitFunc) giw_led_class_init,
93 (GtkObjectInitFunc) giw_led_init,
94 /*(GtkArgSetFunc)*/ NULL,
95 /*(GtkArgGetFunc)*/ NULL,
96 (GtkClassInitFunc) NULL,
97 };
98
99 led_type = gtk_type_unique(gtk_widget_get_type(), &led_info);
100 }
101
102 return led_type;
103 }
104
105
106 #endif
107
108 static void
109 giw_led_class_init(GiwLedClass *xclass) {
110 #if GTK_CHECK_VERSION(3, 0, 0)
111 GObjectClass *object_class = G_OBJECT_CLASS(xclass);
112 #else
113 GtkObjectClass *object_class = (GtkObjectClass *) xclass;
114 #endif
115 GtkWidgetClass *widget_class;
116
117 widget_class = (GtkWidgetClass *) xclass;
118
119 #if GTK_CHECK_VERSION(3, 0, 0)
120 object_class->dispose = giw_led_dispose;
121 #else
122 parent_class = (GtkWidgetClass *)gtk_type_class(gtk_widget_get_type());
123 object_class->destroy = giw_led_destroy;
124 #endif
125
126 widget_class->realize = giw_led_realize;
127 #if GTK_CHECK_VERSION(3, 0, 0)
128 widget_class->get_preferred_width = giw_led_get_preferred_width;
129 widget_class->get_preferred_height = giw_led_get_preferred_height;
130 widget_class->draw = giw_led_draw;
131 widget_class->style_updated = giw_led_style_updated;
132 widget_class->state_flags_changed = giw_led_state_flags_changed;
133 #else
134 widget_class->expose_event = giw_led_expose;
135 widget_class->size_request = giw_led_size_request;
136 #endif
137 widget_class->size_allocate = giw_led_size_allocate;
138 widget_class->button_press_event = giw_led_button_press;
139
140 giw_led_signals[MODE_CHANGED_SIGNAL] = g_signal_new("mode_changed",
141 G_TYPE_FROM_CLASS(xclass),
142 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
143 G_STRUCT_OFFSET(GiwLedClass, mode_changed),
144 NULL,
145 NULL,
146 g_cclosure_marshal_VOID__VOID,
147 G_TYPE_NONE, 0);
148 }
149
150 static void
giw_led_init(GiwLed * led)151 giw_led_init(GiwLed *led) {
152 g_return_if_fail(led != NULL);
153 g_return_if_fail(GIW_IS_LED(led));
154
155 led->on = 0; //Default position: off
156 led->enable_mouse = FALSE;
157
158 // Default on color, full green
159 led->color_on.green = 65535;
160 led->color_on.red = 0;
161 led->color_on.blue = 0;
162
163 // Default off color, white
164 led->color_off.green = 65535;
165 led->color_off.red = 65535;
166 led->color_off.blue = 65535;
167
168 #if GTK_CHECK_VERSION(2,18,0)
169 gtk_widget_set_has_window(GTK_WIDGET(led), TRUE);
170 #endif
171 }
172
173 GtkWidget *
giw_led_new(void)174 giw_led_new(void) {
175 GiwLed *led;
176
177 #if GTK_CHECK_VERSION(3, 0, 0)
178 led = (GiwLed *)g_object_new(GIW_TYPE_LED, NULL);
179 #else
180 led = (GiwLed *)gtk_type_new(giw_led_get_type());
181 #endif
182
183 return GTK_WIDGET(led);
184 }
185
186 #if GTK_CHECK_VERSION(3, 0, 0)
giw_led_dispose(GObject * object)187 static void giw_led_dispose(GObject *object) {
188 #else
189 static void giw_led_destroy(GtkObject *object) {
190 #endif
191 g_return_if_fail(object != NULL);
192 g_return_if_fail(GIW_IS_LED(object));
193
194 #if GTK_CHECK_VERSION(3, 0, 0)
195 G_OBJECT_CLASS(giw_led_parent_class)->dispose(object);
196 #else
197 if (LIVES_GUI_OBJECT_CLASS(parent_class)->destroy)
198 (* LIVES_GUI_OBJECT_CLASS(parent_class)->destroy)(object);
199 #endif
200 }
201
202
203 static void
204 giw_led_realize(GtkWidget *widget) {
205 GdkWindowAttr attributes;
206 gint attributes_mask;
207
208 #if GTK_CHECK_VERSION(3, 0, 0)
209 GtkStyleContext *stylecon;
210 #endif
211
212 g_return_if_fail(widget != NULL);
213 g_return_if_fail(GIW_IS_LED(widget));
214
215 #if GTK_CHECK_VERSION(2,20,0)
216 gtk_widget_set_realized(widget, TRUE);
217 #else
218 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
219 #endif
220
221
222 attributes.x = lives_widget_get_allocation_x(widget);
223 attributes.y = lives_widget_get_allocation_y(widget);
224 attributes.width = lives_widget_get_allocation_width(widget);
225 attributes.height = lives_widget_get_allocation_height(widget);
226 attributes.wclass = GDK_INPUT_OUTPUT;
227 attributes.window_type = GDK_WINDOW_CHILD;
228 attributes.event_mask = gtk_widget_get_events(widget) |
229 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
230 GDK_BUTTON_RELEASE_MASK;
231
232 attributes_mask = GDK_WA_X | GDK_WA_Y;
233
234 #if !GTK_CHECK_VERSION(3, 0, 0)
235 attributes.visual = gtk_widget_get_visual(widget);
236 attributes_mask |= GDK_WA_COLORMAP | GDK_WA_VISUAL;
237 attributes.colormap = gtk_widget_get_colormap(widget);
238 #endif
239
240 #if GTK_CHECK_VERSION(2,18,0)
241 gtk_widget_set_window(widget, gdk_window_new(lives_widget_get_xwindow(lives_widget_get_parent(widget)), &attributes,
242 attributes_mask));
243 #else
244 widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask);
245 #endif
246
247 #if GTK_CHECK_VERSION(3, 0, 0)
248 stylecon = gtk_widget_get_style_context(widget);
249 if (!stylecon) {
250 stylecon = gtk_style_context_new();
251 gtk_style_context_set_path(stylecon, gtk_widget_get_path(widget));
252 }
253 gtk_style_context_add_class(stylecon, "giwled");
254 gtk_style_context_set_state(stylecon, GTK_STATE_FLAG_ACTIVE);
255 //gtk_style_context_set_background(stylecon,lives_widget_get_xwindow(widget));
256 #else
257 widget->style = gtk_style_attach(widget->style, lives_widget_get_xwindow(widget));
258 gtk_style_set_background(widget->style, lives_widget_get_xwindow(widget), GTK_STATE_ACTIVE);
259 #endif
260
261 gdk_window_set_user_data(lives_widget_get_xwindow(widget), widget);
262
263 }
264
265
266
267
268 static void
269 giw_led_size_request(GtkWidget *widget,
270 GtkRequisition *requisition) {
271 g_return_if_fail(widget != NULL);
272 g_return_if_fail(GIW_IS_LED(widget));
273 g_return_if_fail(requisition != NULL);
274
275 requisition->width = LED_DEFAULT_SIZE;
276 requisition->height = LED_DEFAULT_SIZE;
277 }
278
279 #if GTK_CHECK_VERSION(3, 0, 0)
280
281 static void
282 giw_led_get_preferred_width(GtkWidget *widget,
283 gint *minimal_width,
284 gint *natural_width) {
285 GtkRequisition requisition;
286
287 giw_led_size_request(widget, &requisition);
288
289 *minimal_width = *natural_width = requisition.width;
290 }
291
292 static void
293 giw_led_get_preferred_height(GtkWidget *widget,
294 gint *minimal_height,
295 gint *natural_height) {
296 GtkRequisition requisition;
297
298 giw_led_size_request(widget, &requisition);
299
300 *minimal_height = *natural_height = requisition.height;
301 }
302
303 #endif
304
305
306 static void
307 giw_led_size_allocate(GtkWidget *widget,
308 GtkAllocation *allocation) {
309 GiwLed *led;
310
311 g_return_if_fail(widget != NULL);
312 g_return_if_fail(GIW_IS_LED(widget));
313 g_return_if_fail(allocation != NULL);
314
315 #if GTK_CHECK_VERSION(2,18,0)
316 gtk_widget_set_allocation(widget, allocation);
317 #else
318 widget->allocation = *allocation;
319 #endif
320
321 led = GIW_LED(widget);
322
323 if (lives_widget_is_realized(widget)) {
324 gdk_window_move_resize(lives_widget_get_xwindow(widget),
325 allocation->x, allocation->y,
326 allocation->width, allocation->height);
327
328 }
329
330 // The size of the led will be the lower dimension of the widget
331 if (lives_widget_get_allocation_width(widget) > lives_widget_get_allocation_height(widget)) {
332 led->size = lives_widget_get_allocation_height(widget);
333 led->radius = led->size - 4;
334 led->x = (lives_widget_get_allocation_width(widget) / 2) - (led->size / 2);
335 led->y = 0;
336 } else {
337 led->size = lives_widget_get_allocation_width(widget);
338 led->radius = led->size - 4;
339 led->x = 0;
340 led->y = (lives_widget_get_allocation_height(widget) / 2) - (led->size / 2);
341 }
342 }
343
344 #if GTK_CHECK_VERSION(3, 0, 0)
345 static gboolean giw_led_draw(GtkWidget *widget, cairo_t *cairo) {
346
347 #else
348
349 static gint
350 giw_led_expose(GtkWidget *widget,
351 GdkEventExpose *event) {
352 #endif
353 GiwLed *led;
354 GdkRectangle rect;
355
356 #if !GTK_CHECK_VERSION(3, 0, 0)
357 GdkGC *gc; // To put the on and off colors
358
359 g_return_val_if_fail(event != NULL, FALSE);
360
361 if (event->count > 0)
362 return FALSE;
363 #endif
364
365 g_return_val_if_fail(widget != NULL, FALSE);
366 g_return_val_if_fail(GIW_IS_LED(widget), FALSE);
367
368 led = GIW_LED(widget);
369
370 rect.x = 0;
371 rect.y = 0;
372 rect.width = lives_widget_get_allocation_width(widget);
373 rect.height = lives_widget_get_allocation_height(widget);
374
375 // Drawing background
376 #if GTK_CHECK_VERSION(3, 0, 0)
377 cairo_set_line_width(cairo, 1.);
378
379 gtk_render_background(gtk_widget_get_style_context(widget),
380 cairo,
381 0,
382 0,
383 rect.width,
384 rect.height);
385
386 if (led->on)
387 cairo_set_source_rgb(cairo, 1., 1., 1.);
388 else
389 cairo_set_source_rgba(cairo,
390 led->color_off.red,
391 led->color_off.green,
392 led->color_off.blue,
393 led->color_off.alpha
394 );
395
396 cairo_arc(cairo,
397 rect.width / 2 + 2,
398 rect.height / 2 + 2,
399 led->radius / 2,
400 0.,
401 2.*M_PI);
402
403 if (led->on) cairo_set_source_rgb(cairo, 0., 0., 0.);
404
405 cairo_arc(cairo,
406 rect.width / 2 + 1,
407 rect.height / 2 + 1,
408 led->radius / 2 + 1,
409 -45. / M_PI,
410 57.5 / M_PI);
411
412 cairo_arc(cairo,
413 rect.width / 2,
414 rect.height / 2,
415 led->radius / 2 + 1.5,
416 -32 / M_PI,
417 37.5 / M_PI);
418
419 if (led->on)
420 cairo_set_source_rgba(cairo,
421 (double)(led->color_on.red),
422 (double)(led->color_on.green),
423 (double)(led->color_on.blue),
424 (double)(led->color_on.alpha)
425 );
426 else
427 cairo_set_source_rgba(cairo,
428 (double)(led->color_off.red),
429 (double)(led->color_off.green),
430 (double)(led->color_off.blue),
431 (double)(led->color_off.alpha)
432 );
433
434
435 cairo_arc(cairo,
436 rect.width / 2 + 2,
437 rect.height / 2 + 2,
438 (led->size - 4) / 2,
439 0,
440 2.*M_PI);
441
442 cairo_fill(cairo);
443
444 #else
445 gtk_paint_flat_box(widget->style,
446 widget->window,
447 (GtkStateType)(widget->parent == NULL ? GTK_STATE_NORMAL : widget->parent->state),
448 GTK_SHADOW_NONE,
449 &rect,
450 widget,
451 NULL,
452 0,
453 0,
454 -1,
455 -1);
456
457 gc = gdk_gc_new(widget->window); // Allocating memory
458 gdk_gc_copy(gc, widget->style->fg_gc[widget->state]);
459
460 if (led->on)
461 gdk_gc_set_rgb_fg_color(gc, &(led->color_on));
462 else
463 gdk_gc_set_rgb_fg_color(gc, &(led->color_off));
464
465
466 // The border
467 gdk_draw_arc(widget->window,
468 led->on ? widget->style->white_gc : gc,
469 FALSE,
470 led->x + 2,
471 led->y + 2,
472 led->radius,
473 led->radius,
474 0,
475 64 * 360);
476
477 gdk_draw_arc(widget->window,
478 widget->style->black_gc,
479 FALSE,
480 led->x + 1,
481 led->y + 1,
482 led->radius + 2,
483 led->radius + 2,
484 -64 * 90,
485 64 * 115);
486
487 gdk_draw_arc(widget->window,
488 widget->style->black_gc,
489 FALSE,
490 led->x + 1,
491 led->y + 1,
492 led->radius + 3,
493 led->radius + 3,
494 -64 * 60,
495 64 * 75);
496
497 gdk_draw_arc(widget->window,
498 gc,
499 TRUE,
500 led->x + 2,
501 led->y + 2,
502 led->size - 4,
503 led->size - 4,
504 0,
505 64 * 360);
506
507 g_object_unref(gc);
508 #endif
509
510 return FALSE;
511 }
512
513 #if GTK_CHECK_VERSION(3, 0, 0)
514 static void
515 giw_led_style_updated(GtkWidget *widget) {
516 GTK_WIDGET_CLASS(giw_led_parent_class)->style_updated(widget);
517 }
518
519 static void
520 giw_led_state_flags_changed(GtkWidget *widget, GtkStateFlags previous_state) {
521 gtk_widget_queue_draw(widget);
522 }
523 #endif
524
525 static gint
526 giw_led_button_press(GtkWidget *widget,
527 GdkEventButton *event) {
528 GiwLed *led;
529 guint dx, dy, d;
530
531 g_return_val_if_fail(widget != NULL, FALSE);
532 g_return_val_if_fail(GIW_IS_LED(widget), FALSE);
533 g_return_val_if_fail(event != NULL, FALSE);
534
535 led = GIW_LED(widget);
536
537 if (led->enable_mouse == 0) return FALSE;
538
539 dx = event->x - lives_widget_get_allocation_width(widget) / 2;
540 dy = lives_widget_get_allocation_height(widget) / 2 - event->y;
541
542 d = sqrt(dx * dx + dy * dy); // Distance between the pointer and the center
543
544 if (d <= (led->size / 2)) { // If it's inside the led
545 if (led->on == FALSE)
546 led->on = TRUE;
547 else
548 led->on = FALSE;
549
550 g_signal_emit(G_OBJECT(led), giw_led_signals[MODE_CHANGED_SIGNAL], 0);
551 }
552
553 gtk_widget_queue_draw(GTK_WIDGET(led));
554
555 return FALSE;
556 }
557
558 /******************
559 Users Functions
560 ******************/
561
562 void
563 giw_led_set_mode(GiwLed *led,
564 guint8 mode) {
565 g_return_if_fail(led != NULL);
566 g_return_if_fail(GIW_IS_LED(led));
567
568 if (led->on != mode) {
569 led->on = mode;
570 g_signal_emit(G_OBJECT(led), giw_led_signals[MODE_CHANGED_SIGNAL], 0);
571
572 gtk_widget_queue_draw(GTK_WIDGET(led));
573 }
574 }
575
576 guint8
577 giw_led_get_mode(GiwLed *led) {
578 g_return_val_if_fail(led != NULL, 0);
579 g_return_val_if_fail(GIW_IS_LED(led), 0);
580
581 return (led->on);
582 }
583
584 #if GTK_CHECK_VERSION(3, 0, 0)
585 void
586 giw_led_set_rgba(GiwLed *led,
587 GdkRGBA on_color,
588 GdkRGBA off_color) {
589 g_return_if_fail(led != NULL);
590 g_return_if_fail(GIW_IS_LED(led));
591
592 led->color_on = on_color;
593 led->color_off = off_color;
594
595 gtk_widget_queue_draw(GTK_WIDGET(led));
596 }
597 #endif
598 void
599 giw_led_set_colors(GiwLed *led,
600 GdkColor on_color,
601 GdkColor off_color) {
602 g_return_if_fail(led != NULL);
603 g_return_if_fail(GIW_IS_LED(led));
604
605 #if GTK_CHECK_VERSION(3, 0, 0)
606 led->color_on.red = (gdouble)on_color.red / 65535.;
607 led->color_on.green = (gdouble)on_color.green / 65535.;
608 led->color_on.blue = (gdouble)on_color.blue / 65535.;
609 led->color_on.alpha = 1.;
610 led->color_off.red = (gdouble)off_color.red / 65535.;
611 led->color_off.green = (gdouble)off_color.green / 65535.;
612 led->color_off.blue = (gdouble)off_color.blue / 65535.;
613 led->color_off.alpha = 1.;
614 #else
615 led->color_on = on_color;
616 led->color_off = off_color;
617 #endif
618 gtk_widget_queue_draw(GTK_WIDGET(led));
619 }
620
621 void
622 giw_led_enable_mouse(GiwLed *led,
623 gboolean option) {
624 g_return_if_fail(led != NULL);
625 g_return_if_fail(GIW_IS_LED(led));
626
627 led->enable_mouse = option;
628 }
629
630 /******************
631 Local Functions
632 ******************/
633
634
635