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