1 /*
2
3 This widget provides lamps
4
5 (c) Fraser Stuart 2009
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 */
22
23 #include "stdlib.h"
24 #include "string.h"
25 #include "widgets.h"
26 #include "lamp.h"
27
28 static void inv_lamp_class_init(InvLampClass *klass);
29 static void inv_lamp_init(InvLamp *lamp);
30 static void inv_lamp_size_request(GtkWidget *widget, GtkRequisition *requisition);
31 static void inv_lamp_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
32 static void inv_lamp_realize(GtkWidget *widget);
33 static gboolean inv_lamp_expose(GtkWidget *widget,GdkEventExpose *event);
34 static void inv_lamp_paint(GtkWidget *widget, gint mode);
35 static void inv_lamp_destroy(GtkObject *object);
36 static void inv_lamp_colour(GtkWidget *widget, float value, struct colour *rc, struct colour *cc);
37
38
39 GtkType
inv_lamp_get_type(void)40 inv_lamp_get_type(void)
41 {
42 static GType inv_lamp_type = 0;
43 char *name;
44 int i;
45
46
47 if (!inv_lamp_type)
48 {
49 static const GTypeInfo type_info = {
50 sizeof(InvLampClass),
51 NULL, /* base_init */
52 NULL, /* base_finalize */
53 (GClassInitFunc)inv_lamp_class_init,
54 NULL, /* class_finalize */
55 NULL, /* class_data */
56 sizeof(InvLamp),
57 0, /* n_preallocs */
58 (GInstanceInitFunc)inv_lamp_init
59 };
60 for (i = 0; ; i++) {
61 name = g_strdup_printf("InvLamp-%p-%d",inv_lamp_class_init, i);
62 if (g_type_from_name(name)) {
63 free(name);
64 continue;
65 }
66 inv_lamp_type = g_type_register_static(GTK_TYPE_WIDGET,name,&type_info,(GTypeFlags)0);
67 free(name);
68 break;
69 }
70 }
71 return inv_lamp_type;
72 }
73
74 void
inv_lamp_set_scale(InvLamp * lamp,float num)75 inv_lamp_set_scale(InvLamp *lamp, float num)
76 {
77 lamp->scale = num;
78 }
79
80 void
inv_lamp_set_value(InvLamp * lamp,float num)81 inv_lamp_set_value(InvLamp *lamp, float num)
82 {
83 lamp->value = num;
84 if(lamp->value != lamp->lastValue) {
85 if(GTK_WIDGET_REALIZED(lamp))
86 inv_lamp_paint(GTK_WIDGET(lamp),INV_LAMP_DRAW_DATA);
87 }
88 }
89
inv_lamp_set_tooltip(InvLamp * lamp,gchar * tip)90 void inv_lamp_set_tooltip(InvLamp *lamp, gchar *tip)
91 {
92 gtk_widget_set_tooltip_markup(GTK_WIDGET(lamp),tip);
93 }
94
95
inv_lamp_new()96 GtkWidget * inv_lamp_new()
97 {
98 return GTK_WIDGET(gtk_type_new(inv_lamp_get_type()));
99 }
100
101
102 static void
inv_lamp_class_init(InvLampClass * klass)103 inv_lamp_class_init(InvLampClass *klass)
104 {
105 GtkWidgetClass *widget_class;
106 GtkObjectClass *object_class;
107
108
109 widget_class = (GtkWidgetClass *) klass;
110 object_class = (GtkObjectClass *) klass;
111
112 widget_class->realize = inv_lamp_realize;
113 widget_class->size_request = inv_lamp_size_request;
114 widget_class->size_allocate = inv_lamp_size_allocate;
115 widget_class->expose_event = inv_lamp_expose;
116
117 object_class->destroy = inv_lamp_destroy;
118 }
119
120
121 static void
inv_lamp_init(InvLamp * lamp)122 inv_lamp_init(InvLamp *lamp)
123 {
124 lamp->scale = 1;
125 lamp->value = 0;
126 lamp->lastValue=0;
127
128 lamp->l0_r.R =0.1; lamp->l0_r.G =0.0; lamp->l0_r.B =0.0;
129 lamp->l0_c.R =0.2; lamp->l0_c.G =0.0; lamp->l0_c.B =0.0;
130
131 lamp->l1_r.R =0.2; lamp->l1_r.G =0.0; lamp->l1_r.B =0.0;
132 lamp->l1_c.R =1.0; lamp->l1_c.G =0.0; lamp->l1_c.B =0.0;
133
134 lamp->l2_r.R =0.3; lamp->l2_r.G =0.0; lamp->l2_r.B =0.0;
135 lamp->l2_c.R =1.0; lamp->l2_c.G =0.5; lamp->l2_c.B =0.0;
136
137 lamp->l3_r.R =0.4; lamp->l3_r.G =0.0; lamp->l3_r.B =0.0;
138 lamp->l3_c.R =1.0; lamp->l3_c.G =1.0; lamp->l3_c.B =0.0;
139
140 lamp->l4_r.R =0.5; lamp->l4_r.G =0.0; lamp->l4_r.B =0.0;
141 lamp->l4_c.R =1.0; lamp->l4_c.G =1.0; lamp->l4_c.B =0.5;
142 }
143
144
145 static void
inv_lamp_size_request(GtkWidget * widget,GtkRequisition * requisition)146 inv_lamp_size_request(GtkWidget *widget,
147 GtkRequisition *requisition)
148 {
149 g_return_if_fail(widget != NULL);
150 g_return_if_fail(INV_IS_LAMP(widget));
151 g_return_if_fail(requisition != NULL);
152
153 requisition->width = 32;
154 requisition->height = 32;
155 }
156
157
158 static void
inv_lamp_size_allocate(GtkWidget * widget,GtkAllocation * allocation)159 inv_lamp_size_allocate(GtkWidget *widget,
160 GtkAllocation *allocation)
161 {
162 g_return_if_fail(widget != NULL);
163 g_return_if_fail(INV_IS_LAMP(widget));
164 g_return_if_fail(allocation != NULL);
165
166 widget->allocation = *allocation;
167
168 if (GTK_WIDGET_REALIZED(widget)) {
169 gdk_window_move_resize(
170 widget->window,
171 allocation->x, allocation->y,
172 allocation->width, allocation->height
173 );
174 }
175 }
176
177
178 static void
inv_lamp_realize(GtkWidget * widget)179 inv_lamp_realize(GtkWidget *widget)
180 {
181 GdkWindowAttr attributes;
182 guint attributes_mask;
183
184 g_return_if_fail(widget != NULL);
185 g_return_if_fail(INV_IS_LAMP(widget));
186
187 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
188
189 attributes.window_type = GDK_WINDOW_CHILD;
190 attributes.x = widget->allocation.x;
191 attributes.y = widget->allocation.y;
192 attributes.width = 32;
193 attributes.height = 32;
194
195 attributes.wclass = GDK_INPUT_OUTPUT;
196 attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
197
198 attributes_mask = GDK_WA_X | GDK_WA_Y;
199
200 widget->window = gdk_window_new(
201 gtk_widget_get_parent_window (widget),
202 & attributes, attributes_mask
203 );
204
205 gdk_window_set_user_data(widget->window, widget);
206
207 widget->style = gtk_style_attach(widget->style, widget->window);
208 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
209 }
210
211
212 static gboolean
inv_lamp_expose(GtkWidget * widget,GdkEventExpose * event)213 inv_lamp_expose(GtkWidget *widget, GdkEventExpose *event)
214 {
215 g_return_val_if_fail(widget != NULL, FALSE);
216 g_return_val_if_fail(INV_IS_LAMP(widget), FALSE);
217 g_return_val_if_fail(event != NULL, FALSE);
218
219 inv_lamp_paint(widget,INV_LAMP_DRAW_ALL);
220
221 return FALSE;
222 }
223
224
225 static void
inv_lamp_paint(GtkWidget * widget,gint mode)226 inv_lamp_paint(GtkWidget *widget, gint mode)
227 {
228 cairo_t *cr;
229 float xc,yc,r;
230 struct colour rc,cc;
231 GtkStyle *style;
232 cairo_pattern_t *pat;
233
234 style = gtk_widget_get_style(widget);
235
236 float scale = INV_LAMP(widget)->scale;
237 float value = INV_LAMP(widget)->value;
238
239 cr = gdk_cairo_create(widget->window);
240
241 xc=16.0;
242 yc=16.0;
243 r=9.5;
244
245 switch(mode) {
246 case INV_LAMP_DRAW_ALL:
247
248 cairo_arc(cr,xc,yc,13,0,2*INV_PI);
249 cairo_set_source_rgb(cr, 0, 0, 0);
250 cairo_fill_preserve(cr);
251
252 pat = cairo_pattern_create_linear (0.0, 0.0, 32.0, 32.0);
253 cairo_pattern_add_color_stop_rgba (pat, 0.0, 1.00, 1.00, 1.00, 1);
254 cairo_pattern_add_color_stop_rgba (pat, 0.2, 0.91, 0.89, 0.83, 1);
255 cairo_pattern_add_color_stop_rgba (pat, 0.5, 0.43, 0.32, 0.26, 1);
256 cairo_pattern_add_color_stop_rgba (pat, 0.8, 0.10, 0.05, 0.04, 1);
257 cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.00, 0.00, 0.00, 1);
258 cairo_set_source (cr, pat);
259 cairo_set_line_width(cr,5);
260
261 cairo_stroke(cr);
262
263 case INV_LAMP_DRAW_DATA:
264
265 pat = cairo_pattern_create_radial (xc-1, yc-1, 1.5,
266 xc, yc, r);
267 inv_lamp_colour(widget, value*scale, &rc, &cc);
268 cairo_pattern_add_color_stop_rgba (pat, 0.0, cc.R, cc.G, cc.B, 1);
269 cairo_pattern_add_color_stop_rgba (pat, 0.7, rc.R, rc.G, rc.B, 1);
270 cairo_pattern_add_color_stop_rgba (pat, 0.9, 0.1, 0.0, 0.0, 1);
271 cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.1, 0.0, 0.0, 0);
272 cairo_set_source (cr, pat);
273 cairo_arc(cr,xc,yc,r,0,2*INV_PI);
274 cairo_fill(cr);
275 INV_LAMP(widget)->lastValue = value;
276
277 break;
278
279
280 }
281
282 cairo_destroy(cr);
283 }
284
285
286 static void
inv_lamp_destroy(GtkObject * object)287 inv_lamp_destroy(GtkObject *object)
288 {
289 InvLamp *lamp;
290 InvLampClass *klass;
291
292 g_return_if_fail(object != NULL);
293 g_return_if_fail(INV_IS_LAMP(object));
294
295 lamp = INV_LAMP(object);
296
297 klass = gtk_type_class(gtk_widget_get_type());
298
299 if (GTK_OBJECT_CLASS(klass)->destroy) {
300 (* GTK_OBJECT_CLASS(klass)->destroy) (object);
301 }
302 }
303
304 static void
inv_lamp_colour(GtkWidget * widget,float value,struct colour * rc,struct colour * cc)305 inv_lamp_colour(GtkWidget *widget, float value, struct colour *rc, struct colour *cc)
306 {
307 float f1,f2;
308 struct colour *r0;
309 struct colour *c0;
310 struct colour *r1;
311 struct colour *c1;
312
313 if(value <= 0)
314 {
315 rc->R=INV_LAMP(widget)->l0_r.R;
316 rc->G=INV_LAMP(widget)->l0_r.G;
317 rc->B=INV_LAMP(widget)->l0_r.B;
318
319 cc->R=INV_LAMP(widget)->l0_c.R;
320 cc->G=INV_LAMP(widget)->l0_c.G;
321 cc->B=INV_LAMP(widget)->l0_c.B;
322 }
323 else if (value < 1)
324 {
325 r0=&(INV_LAMP(widget)->l0_r);
326 c0=&(INV_LAMP(widget)->l0_c);
327
328 r1=&(INV_LAMP(widget)->l1_r);
329 c1=&(INV_LAMP(widget)->l1_c);
330
331 f1=1-value;
332 f2=value;
333
334 rc->R=(f1 * r0->R) + (f2 * r1->R);
335 rc->G=(f1 * r0->G) + (f2 * r1->G);
336 rc->B=(f1 * r0->B) + (f2 * r1->B);
337
338 cc->R=(f1 * c0->R) + (f2 * c1->R);
339 cc->G=(f1 * c0->G) + (f2 * c1->G);
340 cc->B=(f1 * c0->B) + (f2 * c1->B);
341 }
342 else if (value < 2)
343 {
344 r0=&(INV_LAMP(widget)->l1_r);
345 c0=&(INV_LAMP(widget)->l1_c);
346
347 r1=&(INV_LAMP(widget)->l2_r);
348 c1=&(INV_LAMP(widget)->l2_c);
349
350 f1=2-value;
351 f2=value-1;
352
353 rc->R=(f1 * r0->R) + (f2 * r1->R);
354 rc->G=(f1 * r0->G) + (f2 * r1->G);
355 rc->B=(f1 * r0->B) + (f2 * r1->B);
356
357 cc->R=(f1 * c0->R) + (f2 * c1->R);
358 cc->G=(f1 * c0->G) + (f2 * c1->G);
359 cc->B=(f1 * c0->B) + (f2 * c1->B);
360 }
361 else if (value < 3)
362 {
363 r0=&(INV_LAMP(widget)->l2_r);
364 c0=&(INV_LAMP(widget)->l2_c);
365
366 r1=&(INV_LAMP(widget)->l3_r);
367 c1=&(INV_LAMP(widget)->l3_c);
368
369 f1=3-value;
370 f2=value-2;
371
372 rc->R=(f1 * r0->R) + (f2 * r1->R);
373 rc->G=(f1 * r0->G) + (f2 * r1->G);
374 rc->B=(f1 * r0->B) + (f2 * r1->B);
375
376 cc->R=(f1 * c0->R) + (f2 * c1->R);
377 cc->G=(f1 * c0->G) + (f2 * c1->G);
378 cc->B=(f1 * c0->B) + (f2 * c1->B);
379 }
380 else if (value < 4)
381 {
382 r0=&(INV_LAMP(widget)->l3_r);
383 c0=&(INV_LAMP(widget)->l3_c);
384
385 r1=&(INV_LAMP(widget)->l4_r);
386 c1=&(INV_LAMP(widget)->l4_c);
387
388 f1=4-value;
389 f2=value-3;
390
391 rc->R=(f1 * r0->R) + (f2 * r1->R);
392 rc->G=(f1 * r0->G) + (f2 * r1->G);
393 rc->B=(f1 * r0->B) + (f2 * r1->B);
394
395 cc->R=(f1 * c0->R) + (f2 * c1->R);
396 cc->G=(f1 * c0->G) + (f2 * c1->G);
397 cc->B=(f1 * c0->B) + (f2 * c1->B);
398 }
399 else
400 {
401 rc->R=INV_LAMP(widget)->l4_r.R;
402 rc->G=INV_LAMP(widget)->l4_r.G;
403 rc->B=INV_LAMP(widget)->l4_r.B;
404
405 cc->R=INV_LAMP(widget)->l4_c.R;
406 cc->G=INV_LAMP(widget)->l4_c.G;
407 cc->B=INV_LAMP(widget)->l4_c.B;
408 }
409 }
410
411
412
413