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