1 
2 /*
3  *  Diverse Bristol audio routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
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 3 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, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 /*
23  * This will be a simple pushbutton, initially it will function as 2 throw,
24  * but may incorporate capabilities to support pure contact switches.
25  * radio buttons will probably have to be separate.
26  */
27 
28 #include <math.h>
29 
30 #include "brightoninternals.h"
31 
32 extern int brightonPanelLocation();
33 
34 int
destroyButton(brightonDevice * dev)35 destroyButton(brightonDevice *dev)
36 {
37 	printf("destroyButton()\n");
38 
39 	if (dev->image)
40 		brightonFreeBitmap(dev->bwin, dev->image);
41 	if (dev->image2)
42 		brightonFreeBitmap(dev->bwin, dev->image2);
43 	dev->image = NULL;
44 	dev->image2 = NULL;
45 
46 	return(0);
47 }
48 
49 static void
displaybutton(brightonDevice * dev)50 displaybutton(brightonDevice *dev)
51 {
52 	int flags = dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags;
53 
54 	if (dev->bwin->app->resources[dev->panel].flags & BRIGHTON_WITHDRAWN)
55 		return;
56 
57 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
58 		& BRIGHTON_WITHDRAWN)
59 		return;
60 
61 	/*
62 	 * This is not needed except for moving parts - sliders primarily, but
63 	 * also touch panels. Rotary and buttons are located and stay that way.
64 	 */
65 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
66 		& BRIGHTON_REDRAW)
67 		brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
68 			dev->x + dev->bwin->app->resources[dev->panel].sx,
69 			dev->y + + dev->bwin->app->resources[dev->panel].sy,
70 			dev->width, dev->height);
71 
72 	brightonRenderShadow(dev, 1);
73 
74 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
75 		& (BRIGHTON_THREEWAY|BRIGHTON_FIVEWAY))
76 	{
77 		if ((dev->value >= 0) && (dev->value <= 0.5))
78 		{
79 			brightonStretch(dev->bwin, dev->imagec,
80 				dev->bwin->dlayer,
81 				dev->x + dev->bwin->app->resources[dev->panel].sx,
82 				dev->y + dev->bwin->app->resources[dev->panel].sy,
83 				dev->width, dev->height, flags);
84 		} else if ((dev->value > 0.5) && (dev->value <= 1.5)) {
85 			brightonStretch(dev->bwin, dev->image2,
86 				dev->bwin->dlayer,
87 				dev->x + dev->bwin->app->resources[dev->panel].sx,
88 				dev->y + dev->bwin->app->resources[dev->panel].sy,
89 				dev->width, dev->height, flags);
90 		} else if ((dev->value > 1.5) && (dev->value <= 2.5)) {
91 			brightonStretch(dev->bwin, dev->image,
92 				dev->bwin->dlayer,
93 				dev->x + dev->bwin->app->resources[dev->panel].sx,
94 				dev->y + dev->bwin->app->resources[dev->panel].sy,
95 				dev->width, dev->height, flags);
96 		} else if ((dev->value > 2.5) && (dev->value <= 3.5)) {
97 			brightonStretch(dev->bwin, dev->image3,
98 				dev->bwin->dlayer,
99 				dev->x + dev->bwin->app->resources[dev->panel].sx,
100 				dev->y + dev->bwin->app->resources[dev->panel].sy,
101 				dev->width, dev->height, flags);
102 		} else if ((dev->value > 3.5) && (dev->value <= 4.5)) {
103 			brightonStretch(dev->bwin, dev->image4,
104 				dev->bwin->dlayer,
105 				dev->x + dev->bwin->app->resources[dev->panel].sx,
106 				dev->y + dev->bwin->app->resources[dev->panel].sy,
107 				dev->width, dev->height, flags);
108 		}
109 	} else if (dev->image2) {
110 		if (dev->value)
111 			brightonStretch(dev->bwin, dev->image2,
112 				dev->bwin->dlayer,
113 				dev->x + dev->bwin->app->resources[dev->panel].sx,
114 				dev->y + dev->bwin->app->resources[dev->panel].sy,
115 				dev->width, dev->height,
116 				dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags);
117 		else
118 			brightonStretch(dev->bwin, dev->image,
119 				dev->bwin->dlayer,
120 				dev->x + dev->bwin->app->resources[dev->panel].sx,
121 				dev->y + dev->bwin->app->resources[dev->panel].sy,
122 				dev->width, dev->height,
123 				dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags);
124 	} else {
125 		if ((~dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
126 			& BRIGHTON_CHECKBUTTON))
127 		{
128 			if (dev->value == 0)
129 				flags = 0;
130 			else
131 				flags = BRIGHTON_REVERSE|BRIGHTON_HALF_REVERSE;
132 
133 			flags |= (BRIGHTON_VERTICAL
134 				& dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags);
135 		}
136 
137 		brightonStretch(dev->bwin, dev->image,
138 			/*dev->bwin->app->resources[dev->panel].canvas, */
139 			dev->bwin->dlayer,
140 			dev->x + dev->bwin->app->resources[dev->panel].sx,
141 			dev->y + dev->bwin->app->resources[dev->panel].sy,
142 			dev->width, dev->height, flags);
143 	}
144 
145 	brightonRenderShadow(dev, 0);
146 
147 	brightonFinalRender(dev->bwin,
148 		dev->x + dev->bwin->app->resources[dev->panel].sx,
149 		dev->y + dev->bwin->app->resources[dev->panel].sy,
150 		dev->width, dev->height);
151 
152 	dev->lastvalue = dev->value;
153 	dev->lastposition = dev->position;
154 }
155 
156 /*
157  * This will go into brighton render
158  */
159 static int
renderHighlights(brightonWindow * bwin,brightonDevice * dev)160 renderHighlights(brightonWindow *bwin, brightonDevice *dev)
161 {
162 	float d, streak, dx, dy;
163 	brightonCoord p[8];
164 
165 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags &
166 		(BRIGHTON_CHECKBUTTON|BRIGHTON_NOSHADOW|BRIGHTON_WITHDRAWN))
167 		return(0);
168 
169 	dx = dev->x - bwin->lightX;
170 	dy = dev->y - bwin->lightY;
171 
172 	d = sqrt((double) (dx * dx + dy * dy));
173 
174 	streak = (dev->width * 2.0 * d / bwin->lightH)
175 		/ (1 - dev->width * 2.0 / bwin->lightH);
176 
177 	p[0].x = dev->x;
178 	p[0].y = dev->y + dev->height;
179 	p[1].x = dev->x + dev->width;
180 	p[1].y = dev->y;
181 	p[2].x = dev->x + dx * streak / d;
182 	p[2].y = dev->y + dy * streak / d;
183 
184 /*	XFillPolygon(bwin->display, bwin->background, bwin->cheap_shade, */
185 /*		(XPoint *) &p, 3, Complex, CoordModeOrigin); */
186 	return(0);
187 }
188 
considercallback(brightonDevice * dev)189 static int considercallback(brightonDevice *dev)
190 {
191 	brightonIResource *panel = &dev->bwin->app->resources[dev->panel];
192 
193 	if (dev->bwin->flags & BRIGHTON_NO_DRAW)
194 		return(0);
195 
196 	if ((dev->lastvalue != dev->value)
197 			|| (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
198 			& BRIGHTON_CHECKBUTTON))
199 	{
200 		if (panel->devlocn[dev->index].callback)
201 		{
202 			panel->devlocn[dev->index].callback(dev->bwin, dev->panel,
203 				dev->index, dev->value);
204 		} else {
205 			if (panel->callback)
206 				panel->callback(dev->bwin, dev->panel, dev->index, dev->value);
207 		}
208 	}
209 	return(0);
210 }
211 
212 static int
configure(brightonDevice * dev,brightonEvent * event)213 configure(brightonDevice *dev, brightonEvent *event)
214 {
215 /*	printf("configureButton(%i, %f)\n", dev->index, dev->value); */
216 
217 	/*
218 	 * We had to do this for some withdrawn panels
219 	if (dev->bwin->app->resources[dev->panel].flags & BRIGHTON_WITHDRAWN)
220 		return(0);
221 	 */
222 
223 	if (event->command == -1)
224 		return(-1);
225 
226 	if (event->command == BRIGHTON_RESIZE)
227 	{
228 		dev->x = event->x;
229 		dev->y = event->y;
230 		dev->width = event->w;
231 		dev->height = event->h;
232 		/*
233 		 * We should consider altering the locations structure, so that
234 		 * event dispatching is correct.
235 		 */
236 		if ((dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
237 			& BRIGHTON_CHECKBUTTON) == 0)
238 			considercallback(dev);
239 
240 		brightonPanelLocation(dev->bwin,
241 			dev->panel, dev->index, dev->x, dev->y, dev->width, dev->height);
242 
243 		/*
244 		 * We need to build in some shadow, to prevent the button from looking
245 		 * like it is hanging in mid air.
246 		 */
247 		renderHighlights(dev->bwin, dev);
248 
249 		dev->lastvalue = -1;
250 		displaybutton(dev);
251 
252 		return(0);
253 	}
254 
255 	if (event->command == BRIGHTON_LEAVE)
256 	{
257 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
258 			& BRIGHTON_CHECKBUTTON)
259 		{
260 			dev->value = 0;
261 
262 			displaybutton(dev);
263 		}
264 		return(0);
265 	}
266 
267 	if (event->command == BRIGHTON_ENTER)
268 	{
269 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
270 			& BRIGHTON_CHECKBUTTON)
271 		{
272 			dev->value = 1;
273 
274 			displaybutton(dev);
275 		}
276 		return(0);
277 	}
278 
279 	if (event->command == BRIGHTON_BUTTONRELEASE)
280 	{
281 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
282 			& BRIGHTON_CHECKBUTTON)
283 		{
284 			dev->value = 0;
285 
286 			displaybutton(dev);
287 
288 			if ((event->x >= dev->x) && (event->y >= dev->y)
289 				&& (event->x < (dev->x + dev->width))
290 				&& (event->y < (dev->y + dev->height)))
291 				considercallback(dev);
292 		} else {
293 			brightonIResource *panel = &dev->bwin->app->resources[dev->panel];
294 
295 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
296 				& BRIGHTON_NO_TOGGLE)
297 			{
298 				if (dev->value == 0)
299 					dev->value = panel->devlocn[dev->index].to;
300 				else
301 					dev->value = panel->devlocn[dev->index].from;
302 
303 				considercallback(dev);
304 
305 				displaybutton(dev);
306 			}
307 		}
308 
309 		return(0);
310 	}
311 
312 	if (event->command == BRIGHTON_BUTTONPRESS)
313 	{
314 		brightonIResource *panel = &dev->bwin->app->resources[dev->panel];
315 
316 		if (event->key == BRIGHTON_BUTTON2)
317 		{
318 			brightonRegisterController(dev);
319 
320 			return(0);
321 		}
322 /*
323 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
324 			& BRIGHTON_CHECKBUTTON)
325 			return(0);
326 */
327 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags &
328 			BRIGHTON_THREEWAY)
329 		{
330 			if (--dev->value < 0)
331 				dev->value = 2;
332 		} else if
333 			(dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags &
334 			BRIGHTON_FIVEWAY)
335 		{
336 			if (--dev->value < 0)
337 				dev->value = 4;
338 		} else if (dev->value == 0)
339 			dev->value = panel->devlocn[dev->index].to;
340 		else
341 			dev->value = panel->devlocn[dev->index].from;
342 
343 		if ((dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
344 			& BRIGHTON_CHECKBUTTON) == 0)
345 			considercallback(dev);
346 
347 		displaybutton(dev);
348 
349 		return(0);
350 	}
351 
352 	if (event->command == BRIGHTON_KEYPRESS)
353 	{
354 		brightonIResource *panel = &dev->bwin->app->resources[dev->panel];
355 
356 		if (event->key == 0x20)
357 		{
358 			if (dev->value == 0)
359 				dev->value = panel->devlocn[dev->index].to;
360 			else
361 				dev->value = panel->devlocn[dev->index].from;
362 
363 			considercallback(dev);
364 
365 			displaybutton(dev);
366 
367 			return(0);
368 		}
369 		/*
370 		 * If this was not a space bar which we use to activate and de-activate
371 		 * any arbitrary button then it could be that we pressed some key that
372 		 * can otherwise be interpretted.
373 		 * This is awkward since here we are in a single button and I would
374 		 * like to use keypress to emulate a piano keyboard from the computer.
375 		 * These events would have to be delivered to the parent, not to the
376 		 * device, and the parent would then decide to which device the event
377 		 * should be delivered.
378 		 */
379 	}
380 
381 	if (event->command == BRIGHTON_KEYRELEASE)
382 	{
383 		/*
384 		 * This is just to clear the event and repaint the key, we should not
385 		 * be bothered with the callback.
386 		 */
387 		if (event->key == 0x20)
388 		{
389 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
390 				& BRIGHTON_CHECKBUTTON)
391 			{
392 				dev->value = 0;
393 
394 				displaybutton(dev);
395 
396 /*				considercallback(dev); */
397 			}
398 		}
399 		return(0);
400 	}
401 
402 	if (event->command == BRIGHTON_PARAMCHANGE)
403 	{
404 		dev->value = event->value;
405 		dev->lastvalue = -1;
406 
407 		if ((dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
408 			& BRIGHTON_CHECKBUTTON) == 0)
409 			considercallback(dev);
410 
411 		displaybutton(dev);
412 
413 		return(0);
414 	}
415 
416 	return(0);
417 }
418 
419 int *
createButton(brightonWindow * bwin,brightonDevice * dev,int index,char * bitmap)420 createButton(brightonWindow *bwin, brightonDevice *dev, int index, char *bitmap)
421 {
422 	brightonIResource *panel = &bwin->app->resources[dev->panel];
423 
424 /*printf("createButton(%s, %x)\n", bitmap, panel->devlocn[dev->index].image); */
425 
426 	dev->destroy = destroyButton;
427 	dev->configure = configure;
428 	dev->bwin = bwin;
429 
430 	if (bwin->app->resources[dev->panel].devlocn[dev->index].flags
431 		& BRIGHTON_THREEWAY)
432 	{
433 		char path[256];
434 
435 		if (dev->image)
436 			brightonFreeBitmap(bwin, dev->image);
437 		if (dev->image2)
438 			brightonFreeBitmap(bwin, dev->image2);
439 		if (dev->imagec)
440 			brightonFreeBitmap(bwin, dev->imagec);
441 
442 		sprintf(path, "bitmaps/buttons/%s1.xpm", bitmap);
443 		if ((dev->image = brightonReadImage(bwin, path)) != 0)
444 		{
445 			sprintf(path, "bitmaps/buttons/%s2.xpm", bitmap);
446 			if ((dev->image2 = brightonReadImage(bwin, path)) == 0)
447 				dev->image2 =
448 					brightonReadImage(bwin, "bitmaps/buttons/sw4.xpm");
449 			sprintf(path, "bitmaps/buttons/%s3.xpm", bitmap);
450 			if ((dev->imagec = brightonReadImage(bwin, path)) == 0)
451 				dev->image2 =
452 					brightonReadImage(bwin, "bitmaps/buttons/sw4.xpm");
453 		} else {
454 			dev->image = brightonReadImage(bwin, "bitmaps/buttons/sw5.xpm");
455 			dev->image2 = brightonReadImage(bwin, "bitmaps/buttons/sw4.xpm");
456 			dev->imagec = brightonReadImage(bwin, "bitmaps/buttons/sw3.xpm");
457 		}
458 	} else if (bwin->app->resources[dev->panel].devlocn[dev->index].flags
459 		& BRIGHTON_FIVEWAY)
460 	{
461 		char path[256];
462 
463 		if (dev->image)
464 			brightonFreeBitmap(bwin, dev->image);
465 		if (dev->image2)
466 			brightonFreeBitmap(bwin, dev->image2);
467 		if (dev->image3)
468 			brightonFreeBitmap(bwin, dev->image3);
469 		if (dev->image4)
470 			brightonFreeBitmap(bwin, dev->image4);
471 		if (dev->imagec)
472 			brightonFreeBitmap(bwin, dev->imagec);
473 
474 		sprintf(path, "bitmaps/buttons/%s1.xpm", bitmap);
475 
476 		if ((dev->image = brightonReadImage(bwin, path)) != 0)
477 		{
478 			sprintf(path, "bitmaps/buttons/%s2.xpm", bitmap);
479 			if ((dev->image2 = brightonReadImage(bwin, path)) == 0)
480 				dev->image2 =
481 					brightonReadImage(bwin, "bitmaps/buttons/sw2.xpm");
482 			sprintf(path, "bitmaps/buttons/%s3.xpm", bitmap);
483 			if ((dev->image3 = brightonReadImage(bwin, path)) == 0)
484 				dev->image3 =
485 					brightonReadImage(bwin, "bitmaps/buttons/sw3.xpm");
486 			sprintf(path, "bitmaps/buttons/%s4.xpm", bitmap);
487 			if ((dev->image4 = brightonReadImage(bwin, path)) == 0)
488 				dev->image4 =
489 					brightonReadImage(bwin, "bitmaps/buttons/sw4.xpm");
490 			sprintf(path, "bitmaps/buttons/%s5.xpm", bitmap);
491 			if ((dev->imagec = brightonReadImage(bwin, path)) == 0)
492 				dev->imagec =
493 					brightonReadImage(bwin, "bitmaps/buttons/sw5.xpm");
494 		} else {
495 			dev->image = brightonReadImage(bwin, "bitmaps/buttons/sw1.xpm");
496 			dev->image2 = brightonReadImage(bwin, "bitmaps/buttons/sw2.xpm");
497 			dev->image3 = brightonReadImage(bwin, "bitmaps/buttons/sw3.xpm");
498 			dev->image4 = brightonReadImage(bwin, "bitmaps/buttons/sw4.xpm");
499 			dev->imagec = brightonReadImage(bwin, "bitmaps/buttons/sw5.xpm");
500 		}
501 
502 	} else if (bitmap == NULL) {
503 		if (dev->image)
504 			brightonFreeBitmap(bwin, dev->image);
505 		/*
506 		 * If we have been passed a specific image name for this device then
507 		 * use it.
508 		 */
509 		if (panel->devlocn[dev->index].image != 0)
510 			dev->image =
511 				bwin->app->resources[dev->panel].devlocn[dev->index].image;
512 		else
513 			dev->image = brightonReadImage(bwin,
514 				"bitmaps/buttons/rockerred.xpm");
515 		if (panel->devlocn[dev->index].image2 != 0)
516 			dev->image2 =
517 				bwin->app->resources[dev->panel].devlocn[dev->index].image2;
518 		else
519 			dev->image =
520 				brightonReadImage(bwin, "bitmaps/buttons/rockerred.xpm");
521 	} else {
522 		if (dev->image)
523 			brightonFreeBitmap(bwin, dev->image);
524 
525 		if (panel->devlocn[dev->index].image != 0)
526 			dev->image =
527 				bwin->app->resources[dev->panel].devlocn[dev->index].image;
528 		else
529 			dev->image = brightonReadImage(bwin, bitmap);
530 
531 		if (dev->image2)
532 			brightonFreeBitmap(bwin, dev->image2);
533 
534 		dev->image2 = brightonReadImage(bwin,
535 			bwin->template->resources[dev->panel].devlocn[dev->index].image2);
536 
537 /*
538 		if (panel->devlocn[dev->index].image2 != 0)
539 			dev->image2 =
540 				bwin->app->resources[dev->panel].devlocn[dev->index].image2;
541 */
542 	}
543 
544 	/*
545 	 * These will force an update when we first display ourselves.
546 	 */
547 	dev->value = 0;
548 	dev->lastvalue = -1;
549 	dev->lastposition = -1;
550 
551 	return(0);
552 }
553 
554