1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "ags_led.h"
21 
22 #include <stdlib.h>
23 #include <math.h>
24 
25 void ags_led_class_init(AgsLedClass *led);
26 void ags_led_init(AgsLed *led);
27 
28 void ags_led_realize(GtkWidget *widget);
29 void ags_led_size_allocate(GtkWidget *widget,
30 			   GtkAllocation *allocation);
31 void ags_led_get_preferred_width(GtkWidget *widget,
32 				 gint *minimal_width,
33 				 gint *natural_width);
34 void ags_led_get_preferred_height(GtkWidget *widget,
35 				  gint *minimal_height,
36 				  gint *natural_height);
37 
38 void ags_led_send_configure(AgsLed *led);
39 
40 gboolean ags_led_draw(AgsLed *led, cairo_t *cr);
41 
42 /**
43  * SECTION:ags_led
44  * @short_description: A led widget
45  * @title: AgsLed
46  * @section_id:
47  * @include: ags/widget/ags_led.h
48  *
49  * #AgsLed is a widget visualizing a #gboolean value.
50  */
51 
52 static gpointer ags_led_parent_class = NULL;
53 
54 GType
ags_led_get_type(void)55 ags_led_get_type(void)
56 {
57   static volatile gsize g_define_type_id__volatile = 0;
58 
59   if(g_once_init_enter (&g_define_type_id__volatile)){
60     GType ags_type_led = 0;
61 
62     static const GTypeInfo ags_led_info = {
63       sizeof(AgsLedClass),
64       NULL, /* base_init */
65       NULL, /* base_finalize */
66       (GClassInitFunc) ags_led_class_init,
67       NULL, /* class_finalize */
68       NULL, /* class_data */
69       sizeof(AgsLed),
70       0,    /* n_preallocs */
71       (GInstanceInitFunc) ags_led_init,
72     };
73 
74     ags_type_led = g_type_register_static(GTK_TYPE_WIDGET,
75 					  "AgsLed", &ags_led_info,
76 					  0);
77 
78     g_once_init_leave(&g_define_type_id__volatile, ags_type_led);
79   }
80 
81   return g_define_type_id__volatile;
82 }
83 
84 void
ags_led_class_init(AgsLedClass * led)85 ags_led_class_init(AgsLedClass *led)
86 {
87   GtkWidgetClass *widget;
88 
89   ags_led_parent_class = g_type_class_peek_parent(led);
90 
91   widget = (GtkWidgetClass *) led;
92 
93   widget->realize = ags_led_realize;
94   widget->get_preferred_width = ags_led_get_preferred_width;
95   widget->get_preferred_height = ags_led_get_preferred_height;
96   widget->size_allocate = ags_led_size_allocate;
97   widget->draw = ags_led_draw;
98 }
99 
100 void
ags_led_init(AgsLed * led)101 ags_led_init(AgsLed *led)
102 {
103   g_object_set(G_OBJECT(led),
104 	       "app-paintable", TRUE,
105 	       NULL);
106 
107   led->flags = 0;
108 }
109 
110 void
ags_led_realize(GtkWidget * widget)111 ags_led_realize(GtkWidget *widget)
112 {
113   AgsLed *led;
114 
115   GdkWindow *window;
116 
117   GtkAllocation allocation;
118   GdkWindowAttr attributes;
119 
120   gint attributes_mask;
121 
122   g_return_if_fail(widget != NULL);
123   g_return_if_fail(AGS_IS_LED(widget));
124 
125   led = AGS_LED(widget);
126 
127   gtk_widget_set_realized(widget, TRUE);
128 
129   gtk_widget_get_allocation(widget,
130 			    &allocation);
131 
132   /*  */
133   //TODO:JK: apply borders of container widgets
134   attributes.window_type = GDK_WINDOW_CHILD;
135 
136   attributes.x = allocation.x;
137   attributes.y = allocation.y;
138   attributes.width = allocation.width;
139   attributes.height = allocation.height;
140 
141   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
142 
143   attributes.wclass = GDK_INPUT_OUTPUT;
144   attributes.visual = gtk_widget_get_visual(widget);
145   attributes.event_mask = gtk_widget_get_events (widget);
146   attributes.event_mask |= (GDK_EXPOSURE_MASK |
147 			    GDK_BUTTON_PRESS_MASK |
148 			    GDK_BUTTON_RELEASE_MASK |
149 			    GDK_POINTER_MOTION_MASK |
150 			    GDK_POINTER_MOTION_HINT_MASK);
151 
152   window = gdk_window_new(gtk_widget_get_parent_window(widget),
153 			  &attributes, attributes_mask);
154 
155   gtk_widget_register_window(widget, window);
156   gtk_widget_set_window(widget, window);
157 
158   ags_led_send_configure(led);
159 }
160 
161 void
ags_led_size_allocate(GtkWidget * widget,GtkAllocation * allocation)162 ags_led_size_allocate(GtkWidget *widget,
163 		      GtkAllocation *allocation)
164 {
165   AgsLed *led;
166 
167   g_return_if_fail(AGS_IS_LED(widget));
168   g_return_if_fail(allocation != NULL);
169 
170   led = AGS_LED(widget);
171 
172   allocation->width = AGS_LED_DEFAULT_WIDTH;
173   allocation->height = AGS_LED_DEFAULT_HEIGHT;
174 
175   gtk_widget_set_allocation(widget, allocation);
176 
177   if(gtk_widget_get_realized(widget)){
178     gdk_window_move_resize(gtk_widget_get_window(widget),
179 			   allocation->x, allocation->y,
180 			   allocation->width, allocation->height);
181 
182     ags_led_send_configure(led);
183   }
184 }
185 
186 void
ags_led_send_configure(AgsLed * led)187 ags_led_send_configure(AgsLed *led)
188 {
189   GtkAllocation allocation;
190   GtkWidget *widget;
191   GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
192 
193   widget = GTK_WIDGET(led);
194   gtk_widget_get_allocation(widget, &allocation);
195 
196   event->configure.window = g_object_ref(gtk_widget_get_window (widget));
197   event->configure.send_event = TRUE;
198   event->configure.x = allocation.x;
199   event->configure.y = allocation.y;
200   event->configure.width = allocation.width;
201   event->configure.height = allocation.height;
202 
203   gtk_widget_event(widget, event);
204   gdk_event_free(event);
205 }
206 
207 void
ags_led_get_preferred_width(GtkWidget * widget,gint * minimal_width,gint * natural_width)208 ags_led_get_preferred_width(GtkWidget *widget,
209 			    gint *minimal_width,
210 			    gint *natural_width)
211 {
212   minimal_width[0] =
213     natural_width[0] = AGS_LED_DEFAULT_WIDTH;
214 }
215 
216 void
ags_led_get_preferred_height(GtkWidget * widget,gint * minimal_height,gint * natural_height)217 ags_led_get_preferred_height(GtkWidget *widget,
218 			     gint *minimal_height,
219 			     gint *natural_height)
220 {
221   minimal_height[0] =
222     natural_height[0] = AGS_LED_DEFAULT_HEIGHT;
223 }
224 
225 gboolean
ags_led_draw(AgsLed * led,cairo_t * cr)226 ags_led_draw(AgsLed *led, cairo_t *cr)
227 {
228   GtkWidget *widget;
229 
230   GtkStyleContext *led_style_context;
231 
232   GtkAllocation allocation;
233 
234   GdkRGBA *fg_color;
235   GdkRGBA *bg_color;
236   GdkRGBA *border_color;
237 
238   GValue value = {0,};
239 
240   widget = GTK_WIDGET(led);
241 
242   gtk_widget_get_allocation(widget,
243 			    &allocation);
244 
245 //  g_message("led %d|%d %d|%d", allocation.x, allocation.y, allocation.width, allocation.height);
246 
247   /* style context */
248   led_style_context = gtk_widget_get_style_context(GTK_WIDGET(led));
249 
250   gtk_style_context_get_property(led_style_context,
251 				 "color",
252 				 GTK_STATE_FLAG_NORMAL,
253 				 &value);
254 
255   fg_color = g_value_dup_boxed(&value);
256   g_value_unset(&value);
257 
258   gtk_style_context_get_property(led_style_context,
259 				 "background-color",
260 				 GTK_STATE_FLAG_NORMAL,
261 				 &value);
262 
263   bg_color = g_value_dup_boxed(&value);
264   g_value_unset(&value);
265 
266   gtk_style_context_get_property(led_style_context,
267 				 "border-color",
268 				 GTK_STATE_FLAG_NORMAL,
269 				 &value);
270 
271   border_color = g_value_dup_boxed(&value);
272   g_value_unset(&value);
273 
274   /*  */
275   //  cairo_surface_flush(cairo_get_target(cr));
276   cairo_push_group(cr);
277 
278   if((AGS_LED_ACTIVE & (led->flags)) != 0){
279     /* active */
280     cairo_set_source_rgba(cr,
281 			  fg_color->red,
282 			  fg_color->green,
283 			  fg_color->blue,
284 			  fg_color->alpha);
285   }else{
286     /* normal */
287     cairo_set_source_rgba(cr,
288 			  bg_color->red,
289 			  bg_color->green,
290 			  bg_color->blue,
291 			  bg_color->alpha);
292   }
293 
294   cairo_rectangle(cr,
295 		  0.0, 0.0,
296 		  (gdouble) allocation.width, (gdouble) allocation.height);
297   cairo_fill(cr);
298 
299   /* outline */
300   cairo_set_source_rgba(cr,
301 			border_color->red,
302 			border_color->green,
303 			border_color->blue,
304 			border_color->alpha);
305   cairo_set_line_width(cr,
306 		       1.25);
307 
308   cairo_rectangle(cr,
309 		  0.0, 0.0,
310 		  (gdouble) allocation.width, (gdouble) allocation.height);
311   cairo_stroke(cr);
312 
313   cairo_pop_group_to_source(cr);
314   cairo_paint(cr);
315 
316   g_boxed_free(GDK_TYPE_RGBA, fg_color);
317   g_boxed_free(GDK_TYPE_RGBA, bg_color);
318   g_boxed_free(GDK_TYPE_RGBA, border_color);
319 
320 //  cairo_surface_mark_dirty(cairo_get_target(cr));
321 
322   return(FALSE);
323 }
324 
325 /**
326  * ags_led_is_active:
327  * @led: the #AgsLed
328  *
329  * Set @led to active state.
330  *
331  * Returns: %TRUE if led active, otherwise %FALSE
332  *
333  * Since: 3.2.0
334  */
335 gboolean
ags_led_is_active(AgsLed * led)336 ags_led_is_active(AgsLed *led)
337 {
338   if(!AGS_IS_LED(led)){
339     return(FALSE);
340   }
341 
342   if((AGS_LED_ACTIVE & (led->flags)) != 0){
343     return(TRUE);
344   }
345 
346   return(FALSE);
347 }
348 
349 /**
350  * ags_led_set_active:
351  * @led: the #AgsLed
352  *
353  * Set @led to active state.
354  *
355  * Since: 3.0.0
356  */
357 void
ags_led_set_active(AgsLed * led)358 ags_led_set_active(AgsLed *led)
359 {
360   if(!AGS_IS_LED(led)){
361     return;
362   }
363 
364   if((AGS_LED_ACTIVE & (led->flags)) == 0){
365     led->flags |= AGS_LED_ACTIVE;
366 
367     gtk_widget_queue_draw((GtkWidget *) led);
368   }
369 }
370 
371 /**
372  * ags_led_unset_active:
373  * @led: the #AgsLed
374  *
375  * Unset @led active state.
376  *
377  * Since: 3.0.0
378  */
379 void
ags_led_unset_active(AgsLed * led)380 ags_led_unset_active(AgsLed *led)
381 {
382   if(!AGS_IS_LED(led)){
383     return;
384   }
385 
386   if((AGS_LED_ACTIVE & (led->flags)) != 0){
387     led->flags &= (~AGS_LED_ACTIVE);
388 
389     gtk_widget_queue_draw((GtkWidget *) led);
390   }
391 }
392 
393 /**
394  * ags_led_new:
395  *
396  * Create a new instance of #AgsLed.
397  *
398  * Returns: the new #AgsLed
399  *
400  * Since: 3.0.0
401  */
402 AgsLed*
ags_led_new()403 ags_led_new()
404 {
405   AgsLed *led;
406 
407   led = (AgsLed *) g_object_new(AGS_TYPE_LED,
408 				NULL);
409 
410   return(led);
411 }
412