* New: selectable styles
[calf.git] / src / ctl_led.cpp
blob3647dd9b81484ba4533990feb515e2b31df95142
1 /* Calf DSP Library
2 * Light emitting diode-like control.
4 * Copyright (C) 2008 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #include <calf/ctl_led.h>
22 #include <math.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <calf/drawingutils.h>
27 GtkWidget *
28 calf_led_new()
30 GtkWidget *widget = GTK_WIDGET( g_object_new (CALF_TYPE_LED, NULL ));
31 return widget;
34 static gboolean
35 calf_led_expose (GtkWidget *widget, GdkEventExpose *event)
37 g_assert(CALF_IS_LED(widget));
39 CalfLed *self = CALF_LED(widget);
40 GdkWindow *window = widget->window;
41 cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(window));
42 GtkStyle *style = gtk_widget_get_style(widget);
44 int width = widget->allocation.width;
45 int height = widget->allocation.height;
46 int x = widget->allocation.x;
47 int y = widget->allocation.y;
48 int ox = widget->style->xthickness;
49 int oy = widget->style->ythickness;
50 int sx = width - ox * 2;
51 int sy = height - oy * 2;
52 int xc = x + width / 2;
53 int yc = y + height / 2;
54 int pad;
55 float r, g, b;
57 if( self->cache_surface == NULL ) {
58 // looks like its either first call or the widget has been resized.
59 // create the cache_surface.
60 self->cache_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
61 cairo_t *cache_cr = cairo_create( self->cache_surface );
63 float radius, bevel;
64 get_bg_color(widget, NULL, &r, &g, &b);
65 gtk_widget_style_get(widget, "border-radius", &radius, "bevel", &bevel, NULL);
66 create_rectangle(cache_cr, 0, 0, width, height, radius);
67 cairo_set_source_rgb(cache_cr, r, g, b);
68 cairo_fill(cache_cr);
69 draw_bevel(cache_cr, 0, 0, width, height, radius, bevel);
70 cairo_rectangle(cache_cr, ox, oy, sx, sy);
71 cairo_set_source_rgb (cache_cr, 0, 0, 0);
72 cairo_fill(cache_cr);
74 cairo_destroy( cache_cr );
77 cairo_set_source_surface( c, self->cache_surface, x, y );
78 cairo_paint( c );
80 ox += x;
81 oy += y;
83 cairo_pattern_t *pt = cairo_pattern_create_radial(xc, yc, 0, xc, yc, sx > sy ? sx/2 : sy/2);
85 float value = self->led_value;
87 if(self->led_mode >= 4 && self->led_mode <= 5 && value > 1.f) {
88 value = 1.f;
90 switch (self->led_mode) {
91 default:
92 case 0:
93 // blue-on/off
94 cairo_pattern_add_color_stop_rgb(pt, 0.0, value > 0.f ? 0.2 : 0.0, value > 0.f ? 1.0 : 0.25, value > 0.f ? 1.0 : 0.35);
95 cairo_pattern_add_color_stop_rgb(pt, 0.5, value > 0.f ? 0.1 : 0.0, value > 0.f ? 0.6 : 0.15, value > 0.f ? 0.75 : 0.2);
96 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, value > 0.f ? 0.3 : 0.1, value > 0.f ? 0.5 : 0.1);
97 break;
98 case 1:
99 // red-on/off
100 cairo_pattern_add_color_stop_rgb(pt, 0.0, value > 0.f ? 1.0 : 0.35, value > 0.f ? 0.5 : 0.0, value > 0.f ? 0.2 : 0.0);
101 cairo_pattern_add_color_stop_rgb(pt, 0.5, value > 0.f ? 0.80 : 0.2, value > 0.f ? 0.2 : 0.0, value > 0.f ? 0.1 : 0.0);
102 cairo_pattern_add_color_stop_rgb(pt, 1.0, value > 0.f ? 0.65 : 0.1, value > 0.f ? 0.1 : 0.0, 0.0);
103 break;
104 case 2:
105 case 4:
106 // blue-dynamic (limited)
107 cairo_pattern_add_color_stop_rgb(pt, 0.0, value * 0.2, value * 0.75 + 0.25, value * 0.65 + 0.35);
108 cairo_pattern_add_color_stop_rgb(pt, 0.5, value * 0.1, value * 0.45 + 0.15, value * 0.55 + 0.2);
109 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, value * 0.2 + 0.1, value * 0.4 + 0.1);
110 break;
111 case 3:
112 case 5:
113 // red-dynamic (limited)
114 cairo_pattern_add_color_stop_rgb(pt, 0.0, value * 0.65 + 0.35, value * 0.5, value * 0.2);
115 cairo_pattern_add_color_stop_rgb(pt, 0.5, value * 0.6 + 0.2, value * 0.2, value * 0.1);
116 cairo_pattern_add_color_stop_rgb(pt, 1.0, value * 0.66 + 0.1, value * 0.1, 0.0);
117 break;
118 case 6:
119 // blue-dynamic with red peak at >= 1.f
120 if(value < 1.0) {
121 cairo_pattern_add_color_stop_rgb(pt, 0.0, value * 0.2, value * 0.75 + 0.25, value * 0.65 + 0.35);
122 cairo_pattern_add_color_stop_rgb(pt, 0.5, value * 0.1, value * 0.45 + 0.15, value * 0.55 + 0.2);
123 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, value * 0.2 + 0.1, value * 0.4 + 0.1);
124 } else {
125 cairo_pattern_add_color_stop_rgb(pt, 0.0, 1.0, 0.5, 0.2);
126 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.80, 0.2, 0.1);
127 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.66, 0.1, 0.0);
129 break;
130 case 7:
131 // off @ 0.0, blue < 1.0, red @ 1.0
132 if(value < 1.f and value > 0.f) {
133 // blue
134 cairo_pattern_add_color_stop_rgb(pt, 0.0, 0.2, 1.0, 1.0);
135 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.1, 0.6, 0.75);
136 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, 0.3, 0.5);
137 } else if(value == 0.f) {
138 // off
139 cairo_pattern_add_color_stop_rgb(pt, 0.0, 0.0, 0.25, 0.35);
140 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.0, 0.15, 0.2);
141 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, 0.1, 0.1);
142 } else {
143 // red
144 cairo_pattern_add_color_stop_rgb(pt, 0.0, 1.0, 0.5, 0.2);
145 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.80, 0.2, 0.1);
146 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.66, 0.1, 0.0);
148 break;
151 cairo_rectangle(c, ox + 1, oy + 1, sx - 2, sy - 2);
152 cairo_set_source (c, pt);
153 cairo_fill_preserve(c);
155 pt = cairo_pattern_create_linear (ox, oy, ox, oy + sy);
156 cairo_pattern_add_color_stop_rgba (pt, 0, 1, 1, 1, 0.4);
157 cairo_pattern_add_color_stop_rgba (pt, 0.4, 1, 1, 1, 0.1);
158 cairo_pattern_add_color_stop_rgba (pt, 0.401, 0, 0, 0, 0.0);
159 cairo_pattern_add_color_stop_rgba (pt, 1, 0, 0, 0, 0.2);
160 cairo_set_source (c, pt);
161 cairo_fill(c);
162 cairo_pattern_destroy(pt);
164 cairo_destroy(c);
166 return TRUE;
169 static void
170 calf_led_size_request (GtkWidget *widget,
171 GtkRequisition *requisition)
173 g_assert(CALF_IS_LED(widget));
174 CalfLed *self = CALF_LED(widget);
175 requisition->width = self->size ? 24 : 19;
176 requisition->height = self->size ? 18 : 14;
179 static void
180 calf_led_size_allocate (GtkWidget *widget,
181 GtkAllocation *allocation)
183 g_assert(CALF_IS_LED(widget));
184 CalfLed *led = CALF_LED(widget);
186 widget->allocation = *allocation;
188 if( led->cache_surface )
189 cairo_surface_destroy( led->cache_surface );
190 led->cache_surface = NULL;
192 if (GTK_WIDGET_REALIZED(widget))
193 gdk_window_move_resize(widget->window, allocation->x, allocation->y, allocation->width, allocation->height );
196 static gboolean
197 calf_led_button_press (GtkWidget *widget, GdkEventButton *event)
199 return TRUE;
202 static void
203 calf_led_class_init (CalfLedClass *klass)
205 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
206 widget_class->expose_event = calf_led_expose;
207 widget_class->size_request = calf_led_size_request;
208 widget_class->size_allocate = calf_led_size_allocate;
209 widget_class->button_press_event = calf_led_button_press;
210 gtk_widget_class_install_style_property(
211 widget_class, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
212 0, 24, 4, GParamFlags(G_PARAM_READWRITE)));
213 gtk_widget_class_install_style_property(
214 widget_class, g_param_spec_float("bevel", "Bevel", "Bevel the object",
215 -2, 2, 0.2, GParamFlags(G_PARAM_READWRITE)));
218 static void
219 calf_led_init (CalfLed *self)
221 GtkWidget *widget = GTK_WIDGET(self);
222 // GtkWidget *widget = GTK_WIDGET(self);
223 // GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
224 self->led_value = 0.f;
225 self->cache_surface = NULL;
226 widget->requisition.width = self->size ? 24 : 19;
227 widget->requisition.height = self->size ? 18 : 14;
228 gtk_widget_set_has_window(widget, FALSE);
231 void calf_led_set_value(CalfLed *led, float value)
233 if (value != led->led_value)
235 float old_value = led->led_value;
236 led->led_value = value;
237 if (led->led_mode >= 2 || (old_value > 0) != (value > 0))
239 GtkWidget *widget = GTK_WIDGET (led);
240 if (GTK_WIDGET_REALIZED(widget))
241 gtk_widget_queue_draw (widget);
246 gboolean calf_led_get_value(CalfLed *led)
248 return led->led_value;
251 GType
252 calf_led_get_type (void)
254 static GType type = 0;
255 if (!type) {
256 static const GTypeInfo type_info = {
257 sizeof(CalfLedClass),
258 NULL, /* base_init */
259 NULL, /* base_finalize */
260 (GClassInitFunc)calf_led_class_init,
261 NULL, /* class_finalize */
262 NULL, /* class_data */
263 sizeof(CalfLed),
264 0, /* n_preallocs */
265 (GInstanceInitFunc)calf_led_init
268 for (int i = 0; ; i++) {
269 const char *name = "CalfLed";
270 //char *name = g_strdup_printf("CalfLed%u%d",
271 //((unsigned int)(intptr_t)calf_led_class_init) >> 16, i);
272 if (g_type_from_name(name)) {
273 //free(name);
274 continue;
276 type = g_type_register_static(GTK_TYPE_DRAWING_AREA,
277 name,
278 &type_info,
279 (GTypeFlags)0);
280 //free(name);
281 break;
284 return type;