+ JACK host: fix compilation with LASH (thanks Joeboy&drobilla) and printf format...
[calf.git] / src / ctl_led.cpp
bloba3d7b3fae23b8e72f50a353653dd922ff1941a4a
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 <malloc.h>
26 GtkWidget *
27 calf_led_new()
29 GtkWidget *widget = GTK_WIDGET( g_object_new (CALF_TYPE_LED, NULL ));
30 return widget;
33 static gboolean
34 calf_led_expose (GtkWidget *widget, GdkEventExpose *event)
36 g_assert(CALF_IS_LED(widget));
38 CalfLed *self = CALF_LED(widget);
39 GdkWindow *window = widget->window;
40 cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(window));
41 GtkStyle *style = gtk_widget_get_style(widget);
43 int ox = 4;
44 int oy = 3;
45 int sx = widget->allocation.width - ox * 2;
46 int sy = widget->allocation.height - oy * 2;
47 int xc = widget->allocation.width / 2;
48 int yc = widget->allocation.height / 2;
49 int pad, rad;
51 if( self->cache_surface == NULL ) {
52 // looks like its either first call or the widget has been resized.
53 // create the cache_surface.
54 cairo_surface_t *window_surface = cairo_get_target( c );
55 self->cache_surface = cairo_surface_create_similar( window_surface,
56 CAIRO_CONTENT_COLOR,
57 widget->allocation.width,
58 widget->allocation.height );
59 cairo_t *cache_cr = cairo_create( self->cache_surface );
61 // if(widget->style->bg_pixmap[0] == NULL) {
62 gdk_cairo_set_source_color(cache_cr,&style->bg[GTK_STATE_NORMAL]);
63 // } else {
64 // gdk_cairo_set_source_pixbuf(cache_cr, GDK_PIXBUF(&style->bg_pixmap[0]), widget->allocation.x, widget->allocation.y + 20);
65 // }
66 cairo_paint(cache_cr);
68 // outer (light)
69 pad = 0;
70 rad = 6;
71 cairo_arc(cache_cr, rad + pad, rad + pad, rad, 0, 2 * M_PI);
72 cairo_arc(cache_cr, ox * 2 + sx - rad - pad, rad + pad, rad, 0, 2 * M_PI);
73 cairo_arc(cache_cr, rad + pad, oy * 2 + sy - rad - pad, rad, 0, 2 * M_PI);
74 cairo_arc(cache_cr, ox * 2 + sx - rad - pad, oy * 2 + sy - rad - pad, rad, 0, 2 * M_PI);
75 cairo_rectangle(cache_cr, pad, rad + pad, sx + ox * 2 - pad * 2, sy + oy * 2 - rad * 2 - pad * 2);
76 cairo_rectangle(cache_cr, rad + pad, pad, sx + ox * 2 - rad * 2 - pad * 2, sy + oy * 2 - pad * 2);
77 cairo_pattern_t *pat2 = cairo_pattern_create_linear (0, 0, 0, sy + oy * 2 - pad * 2);
78 cairo_pattern_add_color_stop_rgba (pat2, 0, 0, 0, 0, 0.3);
79 cairo_pattern_add_color_stop_rgba (pat2, 1, 1, 1, 1, 0.6);
80 cairo_set_source (cache_cr, pat2);
81 cairo_fill(cache_cr);
83 // inner (black)
84 pad = 1;
85 rad = 5;
86 cairo_arc(cache_cr, rad + pad, rad + pad, rad, 0, 2 * M_PI);
87 cairo_arc(cache_cr, ox * 2 + sx - rad - pad, rad + pad, rad, 0, 2 * M_PI);
88 cairo_arc(cache_cr, rad + pad, oy * 2 + sy - rad - pad, rad, 0, 2 * M_PI);
89 cairo_arc(cache_cr, ox * 2 + sx - rad - pad, oy * 2 + sy - rad - pad, rad, 0, 2 * M_PI);
90 cairo_rectangle(cache_cr, pad, rad + pad, sx + ox * 2 - pad * 2, sy + oy * 2 - rad * 2 - pad * 2);
91 cairo_rectangle(cache_cr, rad + pad, pad, sx + ox * 2 - rad * 2 - pad * 2, sy + oy * 2 - pad * 2);
92 pat2 = cairo_pattern_create_linear (0, 0, 0, sy + oy * 2 - pad * 2);
93 cairo_pattern_add_color_stop_rgba (pat2, 0, 0.23, 0.23, 0.23, 1);
94 cairo_pattern_add_color_stop_rgba (pat2, 0.5, 0, 0, 0, 1);
95 cairo_set_source (cache_cr, pat2);
96 //cairo_set_source_rgb(cache_cr, 0, 0, 0);
97 cairo_fill(cache_cr);
99 cairo_rectangle(cache_cr, ox, oy, sx, sy);
100 cairo_set_source_rgb (cache_cr, 0, 0, 0);
101 cairo_fill(cache_cr);
103 cairo_destroy( cache_cr );
106 cairo_set_source_surface( c, self->cache_surface, 0,0 );
107 cairo_paint( c );
110 cairo_pattern_t *pt = cairo_pattern_create_radial(xc, yc, 0, xc, yc, xc > yc ? xc : yc);
112 float value = self->led_value;
114 if(self->led_mode >= 4 && self->led_mode <= 5 && value > 1.f) {
115 value = 1.f;
117 switch (self->led_mode) {
118 default:
119 case 0:
120 // blue-on/off
121 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.5);
122 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.3);
123 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, value > 0.f ? 0.3 : 0.1, value > 0.f ? 0.5 : 0.2);
124 break;
125 case 1:
126 // red-on/off
127 cairo_pattern_add_color_stop_rgb(pt, 0.0, value > 0.f ? 1.0 : 0.5, value > 0.f ? 0.5 : 0.0, value > 0.f ? 0.2 : 0.0);
128 cairo_pattern_add_color_stop_rgb(pt, 0.5, value > 0.f ? 0.75 : 0.3, value > 0.f ? 0.2 : 0.0, value > 0.f ? 0.1 : 0.0);
129 cairo_pattern_add_color_stop_rgb(pt, 1.0, value > 0.f ? 0.5 : 0.2, value > 0.f ? 0.1 : 0.0, 0.0);
130 break;
131 case 2:
132 case 4:
133 // blue-dynamic (limited)
134 cairo_pattern_add_color_stop_rgb(pt, 0.0, value * 0.2, value * 0.75 + 0.25, value * 0.5 + 0.5);
135 cairo_pattern_add_color_stop_rgb(pt, 0.5, value * 0.1, value * 0.45 + 0.15, value * 0.45 + 0.3);
136 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, value * 0.2 + 0.1, value * 0.3 + 0.2);
137 break;
138 case 3:
139 case 5:
140 // red-dynamic (limited)
141 cairo_pattern_add_color_stop_rgb(pt, 0.0, value * 0.5 + 0.5, value * 0.5, value * 0.2);
142 cairo_pattern_add_color_stop_rgb(pt, 0.5, value * 0.45 + 0.3, value * 0.2, value * 0.1);
143 cairo_pattern_add_color_stop_rgb(pt, 1.0, value * 0.3 + 0.2, value * 0.1, 0.0);
144 break;
145 case 6:
146 // blue-dynamic with red peak at >= 1.f
147 if(value < 1.0) {
148 cairo_pattern_add_color_stop_rgb(pt, 0.0, value * 0.2, value * 0.75 + 0.25, value * 0.5 + 0.5);
149 cairo_pattern_add_color_stop_rgb(pt, 0.5, value * 0.1, value * 0.45 + 0.15, value * 0.45 + 0.3);
150 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, value * 0.2 + 0.1, value * 0.3 + 0.2);
151 } else {
152 cairo_pattern_add_color_stop_rgb(pt, 0.0, 1.0, 0.5, 0.2);
153 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.75, 0.2, 0.1);
154 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.5, 0.1, 0.0);
156 break;
157 case 7:
158 // off @ 0.0, blue < 1.0, red @ 1.0
159 if(value < 1.f and value > 0.f) {
160 // blue
161 cairo_pattern_add_color_stop_rgb(pt, 0.0, 0.2, 1.0, 1.0);
162 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.1, 0.6, 0.75);
163 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, 0.3, 0.5);
164 } else if(value == 0.f) {
165 // off
166 cairo_pattern_add_color_stop_rgb(pt, 0.0, 0.0, 0.25, 0.5);
167 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.0, 0.15, 0.3);
168 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.0, 0.1, 0.2);
169 } else {
170 // red
171 cairo_pattern_add_color_stop_rgb(pt, 0.0, 1.0, 0.5, 0.2);
172 cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.75, 0.2, 0.1);
173 cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.5, 0.1, 0.0);
175 break;
178 cairo_rectangle(c, ox + 1, oy + 1, sx - 2, sy - 2);
179 cairo_set_source (c, pt);
180 cairo_fill_preserve(c);
181 pt = cairo_pattern_create_linear (ox, oy, ox, ox + sy);
182 cairo_pattern_add_color_stop_rgba (pt, 0, 1, 1, 1, 0.4);
183 cairo_pattern_add_color_stop_rgba (pt, 0.4, 1, 1, 1, 0.1);
184 cairo_pattern_add_color_stop_rgba (pt, 0.401, 0, 0, 0, 0.0);
185 cairo_pattern_add_color_stop_rgba (pt, 1, 0, 0, 0, 0.2);
186 cairo_set_source (c, pt);
187 cairo_fill(c);
188 cairo_pattern_destroy(pt);
190 cairo_destroy(c);
192 return TRUE;
195 static void
196 calf_led_realize(GtkWidget *widget)
198 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
200 GdkWindowAttr attributes;
201 attributes.event_mask = GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
202 attributes.x = widget->allocation.x;
203 attributes.y = widget->allocation.y;
204 attributes.width = widget->allocation.width;
205 attributes.height = widget->allocation.height;
206 attributes.wclass = GDK_INPUT_OUTPUT;
207 attributes.window_type = GDK_WINDOW_CHILD;
209 widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), &attributes, GDK_WA_X | GDK_WA_Y);
211 gdk_window_set_user_data(widget->window, widget);
212 widget->style = gtk_style_attach(widget->style, widget->window);
215 static void
216 calf_led_size_request (GtkWidget *widget,
217 GtkRequisition *requisition)
219 g_assert(CALF_IS_LED(widget));
221 requisition->width = 24;
222 requisition->height = 18;
225 static void
226 calf_led_size_allocate (GtkWidget *widget,
227 GtkAllocation *allocation)
229 g_assert(CALF_IS_LED(widget));
230 CalfLed *led = CALF_LED(widget);
232 widget->allocation = *allocation;
234 if( led->cache_surface )
235 cairo_surface_destroy( led->cache_surface );
236 led->cache_surface = NULL;
238 if (GTK_WIDGET_REALIZED(widget))
239 gdk_window_move_resize(widget->window, allocation->x, allocation->y, allocation->width, allocation->height );
242 static gboolean
243 calf_led_button_press (GtkWidget *widget, GdkEventButton *event)
245 return TRUE;
248 static void
249 calf_led_class_init (CalfLedClass *klass)
251 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
252 widget_class->realize = calf_led_realize;
253 widget_class->expose_event = calf_led_expose;
254 widget_class->size_request = calf_led_size_request;
255 widget_class->size_allocate = calf_led_size_allocate;
256 widget_class->button_press_event = calf_led_button_press;
259 static void
260 calf_led_init (CalfLed *self)
262 GtkWidget *widget = GTK_WIDGET(self);
263 // GtkWidget *widget = GTK_WIDGET(self);
264 // GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
265 self->led_value = 0.f;
266 widget->requisition.width = 24;
267 widget->requisition.height = 18;
270 void calf_led_set_value(CalfLed *led, float value)
272 if (value != led->led_value)
274 led->led_value = value;
275 GtkWidget *widget = GTK_WIDGET (led);
276 if (GTK_WIDGET_REALIZED(widget))
277 gtk_widget_queue_draw (widget);
281 gboolean calf_led_get_value(CalfLed *led)
283 return led->led_value;
286 GType
287 calf_led_get_type (void)
289 static GType type = 0;
290 if (!type) {
291 static const GTypeInfo type_info = {
292 sizeof(CalfLedClass),
293 NULL, /* base_init */
294 NULL, /* base_finalize */
295 (GClassInitFunc)calf_led_class_init,
296 NULL, /* class_finalize */
297 NULL, /* class_data */
298 sizeof(CalfLed),
299 0, /* n_preallocs */
300 (GInstanceInitFunc)calf_led_init
303 for (int i = 0; ; i++) {
304 char *name = g_strdup_printf("CalfLed%u%d",
305 ((unsigned int)(intptr_t)calf_led_class_init) >> 16, i);
306 if (g_type_from_name(name)) {
307 free(name);
308 continue;
310 type = g_type_register_static(GTK_TYPE_WIDGET,
311 name,
312 &type_info,
313 (GTypeFlags)0);
314 free(name);
315 break;
318 return type;