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 #include "brightoninternals.h"
23 
24 extern void bvgRenderInt(brightonWindow *, char *, brightonBitmap *);
25 
26 #define MY_CALL 0x01
27 struct {
28 	unsigned int flags;
29 	int px, py;
30 	brightonBitmap frame;
31 	brightonPanel *panel;
32 } window;
33 
34 void
brightonCreatePanel(int x,int y,char * image)35 brightonCreatePanel(int x, int y, char *image)
36 {
37 	window.px = x;
38 	window.py = y;
39 
40 	window.flags |= MY_CALL;
41 }
42 
43 int
brightonDevUndraw(brightonWindow * bwin,brightonBitmap * dest,int ix,int iy,int w,int h)44 brightonDevUndraw(brightonWindow *bwin, brightonBitmap *dest, int ix, int iy,
45 int w, int h)
46 {
47 	int x, y, z, dy, s = dest->width * dest->height;
48 
49 /*printf("undraw %x %x %x, %i %i %i %i\n", */
50 /*bwin, dest, dest->pixels, ix, iy, w, h); */
51 
52 	for (y = iy; y <= (iy + h - 1); y++)
53 	{
54 		dy = y * dest->width;
55 
56 		for (x = ix; x <= (ix + w - 1); x++)
57 		{
58 			if (((z = dy + x) < 0) || (z > s))
59 				continue;
60 			dest->pixels[z] = -1;
61 		}
62 	}
63 	return(0);
64 }
65 
66 void
brightonPanelLocation(brightonWindow * bwin,int panel,int index,int x,int y,int width,int height)67 brightonPanelLocation(brightonWindow *bwin, int panel, int index,
68 int x, int y, int width, int height)
69 {
70 	bwin->app->resources[panel].devlocn[index].ax = x;
71 	bwin->app->resources[panel].devlocn[index].ay = y;
72 	bwin->app->resources[panel].devlocn[index].aw = width;
73 	bwin->app->resources[panel].devlocn[index].ah = height;
74 }
75 
76 static brightonILocations *ldid = 0;
77 
78 static int
configurePanel(brightonWindow * bwin,brightonIResource * panel,brightonEvent * event)79 configurePanel(brightonWindow *bwin, brightonIResource *panel,
80 	brightonEvent *event)
81 {
82 	int dev;
83 	brightonILocations *device;
84 
85 	/* printf("configure panel: %i\n", event->command); */
86 
87 	if (event->command == BRIGHTON_PARAMCHANGE)
88 	{
89 		if (event->type == BRIGHTON_EXPOSE)
90 		{
91 			if (event->intvalue)
92 			{
93 //printf("	REQ EXPOSE %x %x\n", (size_t) event, (size_t) panel);
94 				panel->flags &= ~BRIGHTON_WITHDRAWN;
95 
96 				event->command = BRIGHTON_RESIZE;
97 
98 				event->x = panel->sx;
99 				event->y = panel->sy;
100 				event->w = panel->sw;
101 				event->h = panel->sh;
102 
103 				brightonDevUndraw(bwin, bwin->dlayer,
104 					event->x, event->y, event->w, event->h);
105 				brightonDevUndraw(bwin, bwin->slayer,
106 					event->x, event->y, event->w, event->h);
107 
108 				/*
109 				 * We should also go through all the tools in the panel and
110 				 * rerender their shadow.
111 				 */
112 				for (dev = 0; dev < panel->ndevices; dev++)
113 				{
114 					if (panel->devlocn[dev].type == 0)
115 						brightonRenderShadow(
116 							(brightonDevice *) panel->devlocn[dev].dev, 0);
117 				}
118 			} else {
119 //printf("	REQ UNEXPOSE %x %x\n", (size_t) event, (size_t) panel);
120 				panel->flags |= BRIGHTON_WITHDRAWN;
121 				/*
122 				 * On unexpose events we dont do any redraws? Conceptually we
123 				 * only have overlapping panels, and EXPOSE/UNEXPOSE go in
124 				 * pairs - the next event on another panel will draw over the
125 				 * top of me.
126 				 */
127 				return(0);
128 			}
129 		} else
130 			return(0);
131 	}
132 
133 	if (event->command == BRIGHTON_RESIZE)
134 	{
135 		panel->sx = event->x;
136 		panel->sy = event->y;
137 		panel->sw = event->w;
138 		panel->sh = event->h;
139 
140 		/*
141 		 * We need to configure our size and render any image and blueprints for
142 		 * this panel. Then we need to call all our devices and make sure they
143 		 * are also configured for their location within this panel.
144 		 */
145 		if (panel->canvas)
146 			brightonFreeBitmap(bwin, panel->canvas);
147 
148 		panel->canvas = brightonCreateBitmap(bwin, event->w, event->h);
149 
150 		if (panel->flags & BRIGHTON_WITHDRAWN)
151 		{
152 			/*
153 			 * NOTE:
154 			 * this was a fix for incorrect shadow rendering if panels are
155 			 * resized whilst withdrawn.
156 			 */
157 			for (dev = 0; dev < panel->ndevices; dev++)
158 			{
159 				if (panel->devlocn[dev].type == -1)
160 					continue;
161 
162 				event->x = (int) panel->devlocn[dev].x * panel->sw / 1000;
163 				event->y = (int) panel->devlocn[dev].y * panel->sh / 1000;
164 				event->w = (int) panel->devlocn[dev].width * panel->sw / 1000;
165 				event->h = (int) panel->devlocn[dev].height * panel->sh / 1000;
166 
167 				brightonPanelLocation(bwin,
168 					panel->devlocn[dev].panel, panel->devlocn[dev].index,
169 					event->x, event->y, event->w, event->h);
170 
171 				((brightonDevice *) panel->devlocn[dev].dev)->configure(
172 					panel->devlocn[dev].dev, event);
173 			}
174 			return(0);
175 		}
176 
177 		/*
178 		 * Render our panel canvas.
179 		 */
180 		if (panel->surface == NULL) {
181 			/*
182 			 * A few panels do not use a surface. This works, it gets filled as
183 			 * 'Blue' and never gets rendered. It caused problems with the
184 			 * prealiasing code since unless a surface is rendered then we
185 			 * cannot do the antialiasing. To overcome this we paint the actual
186 			 * content of the parent into the panel surface.
187 			 * This is not as trivial as it seems as we actually want a window
188 			 * into the backing store, most of which can be resolved by correct
189 			 * placement of these elements in the image stacking order.
190 			 */
191 			brightonTesselate(bwin, bwin->canvas, panel->canvas, 0, 0,
192 				panel->sw, panel->sh, panel->flags);
193 		} else {
194 			if (panel->flags & BRIGHTON_STRETCH)
195 				brightonStretch(bwin, panel->surface, panel->canvas, 0, 0,
196 					panel->sw, panel->sh, panel->flags);
197 			else
198 				brightonTesselate(bwin, panel->surface, panel->canvas, 0, 0,
199 					panel->sw, panel->sh, panel->flags);
200 		}
201 
202 		/*
203 		 * This should be done with antialiasing since when it is scaled it
204 		 * can look rather grizzly. Also, if we don't have a surface then we
205 		 * should create a dummy one to allow for antialiasing.
206 		 */
207 		if ((bwin->display->flags & BRIGHTON_ANTIALIAS_5)
208 			|| (bwin->display->flags & BRIGHTON_ANTIALIAS_2))
209 			brightonStretchAlias(bwin, panel->image, panel->canvas, 0, 0,
210 				panel->sw, panel->sh, 0.2);
211 		else
212 			brightonStretch(bwin, panel->image, panel->canvas, 0, 0,
213 				panel->sw, panel->sh, 0);
214 
215 		if (panel->image)
216 			bvgRenderInt(bwin, rindex(panel->image->name, '/'), panel->canvas);
217 
218 		/*
219 		 * And then render it onto the window cavas area
220 		 */
221 		brightonStretch(bwin, panel->canvas, bwin->canvas, panel->sx, panel->sy,
222 			panel->sw, panel->sh, BRIGHTON_ANTIALIAS);
223 
224 		brightonFinalRender(bwin, panel->sx, panel->sy, panel->sw, panel->sh);
225 
226 		for (dev = 0; dev < panel->ndevices; dev++)
227 		{
228 			if (panel->devlocn[dev].type == -1)
229 				continue;
230 
231 			event->x = (int) panel->devlocn[dev].x * panel->sw / 1000;
232 			event->y = (int) panel->devlocn[dev].y * panel->sh / 1000;
233 			event->w = (int) panel->devlocn[dev].width * panel->sw / 1000;
234 			event->h = (int) panel->devlocn[dev].height * panel->sh / 1000;
235 
236 			brightonPanelLocation(bwin,
237 				panel->devlocn[dev].panel, panel->devlocn[dev].index,
238 				event->x, event->y, event->w, event->h);
239 
240 			((brightonDevice *) panel->devlocn[dev].dev)->configure(
241 				panel->devlocn[dev].dev, event);
242 		}
243 
244 		return(0);
245 	}
246 
247 	device = brightonDeviceLocator(panel,
248 		event->x - panel->sx, event->y - panel->sy);
249 
250 	if ((panel->flags & BRIGHTON_KEY_PANEL) || ldid)
251 	{
252 		brightonEvent nEv;
253 
254 //printf("keypanel\n");
255 		/*
256 		 * We may have to reinterpret some events. We want to have motion
257 		 * tracking to move from key to key which means if the device ID changes
258 		 * then send a BUTTONRELEASE on the previous ID and a BUTTONPRESS on
259 		 * the new one.
260 		 */
261 		if (device != ldid)
262 		{
263 //printf("release button\n");
264 			memcpy(&nEv, event, sizeof(brightonEvent));
265 
266 			nEv.command = BRIGHTON_BUTTONRELEASE;
267 
268 			nEv.x -= panel->sx;
269 			nEv.y -= panel->sy;
270 
271 			if (bwin->activedev)
272 				((brightonDevice *) bwin->activedev->dev)->configure
273 					(bwin->activedev->dev, &nEv);
274 		}
275 		if ((panel->flags & BRIGHTON_KEY_PANEL) && device)
276 		{
277 			if (ldid != device)
278 			{
279 //printf("press button\n");
280 				memcpy(&nEv, event, sizeof(brightonEvent));
281 
282 				nEv.command = BRIGHTON_BUTTONPRESS;
283 
284 				nEv.x = event->x - panel->sx;
285 				nEv.y = event->y - panel->sy;
286 
287 				ldid = bwin->activedev = device;
288 
289 				((brightonDevice *) device->dev)->configure
290 					(device->dev, &nEv);
291 
292 				return(0);
293 			}
294 		} else {
295 			ldid = 0;
296 			bwin->activedev = 0;
297 		}
298 	}
299 
300 	if (event->command == BRIGHTON_BUTTONRELEASE)
301 	{
302 		/*printf("panel button release: %i\n", bwin->activedev); */
303 
304 		if (bwin->activedev == 0)
305 			return(0);
306 
307 		/* This should be simplified to Deliver the Event */
308 		if ((bwin->app->resources[bwin->activedev->panel].devlocn[
309 			bwin->activedev->index].flags & BRIGHTON_CENTER)
310 			|| (bwin->app->resources[bwin->activedev->panel].devlocn[
311 				bwin->activedev->index].type == 5))
312 		{
313 			/*
314 			 * Deliver the event.
315 			 */
316 			event->x -= panel->sx;
317 			event->y -= panel->sy;
318 
319 			((brightonDevice *) bwin->activedev->dev)->configure
320 				(bwin->activedev->dev, event);
321 		} else if (device == bwin->activedev) {
322 			/*
323 			 * Deliver the event.
324 			 */
325 			event->x -= panel->sx;
326 			event->y -= panel->sy;
327 
328 			((brightonDevice *) bwin->activedev->dev)->configure
329 				(bwin->activedev->dev, event);
330 		} else {
331 			/*
332 			 * Deliver the event.
333 			 */
334 			event->x -= panel->sx;
335 			event->y -= panel->sy;
336 
337 			((brightonDevice *) bwin->activedev->dev)->configure
338 				(bwin->activedev->dev, event);
339 		}
340 
341 		bwin->activedev = 0;
342 
343 		return(0);
344 	}
345 
346 	if ((event->command == BRIGHTON_BUTTONPRESS)
347 		|| (event->command == BRIGHTON_BUTTONRELEASE))
348 	{
349 		/*printf("panel button press\n"); */
350 
351 		if ((bwin->activedev = device) == 0)
352 			return(0);
353 
354 		/*
355 		 * Deliver the event.
356 		 */
357 		event->x -= panel->sx;
358 		event->y -= panel->sy;
359 
360 		((brightonDevice *) bwin->activedev->dev)->configure
361 			(bwin->activedev->dev, event);
362 
363 		return(0);
364 	}
365 
366 	if (event->command == BRIGHTON_MOTION)
367 	{
368 		if (bwin->activedev)
369 		{
370 			/*
371 			 * Deliver the event.
372 			 */
373 			event->x -= panel->sx;
374 			event->y -= panel->sy;
375 
376 			if (bwin->activedev->flags & BRIGHTON_CHECKBUTTON)
377 			{
378 				if (device != bwin->activedev)
379 				{
380 					event->command = BRIGHTON_LEAVE;
381 					((brightonDevice *) bwin->activedev->dev)->configure
382 						(bwin->activedev->dev, event);
383 				} else {
384 					event->command = BRIGHTON_ENTER;
385 					((brightonDevice *) bwin->activedev->dev)->configure
386 						(bwin->activedev->dev, event);
387 				}
388 			} else {
389 				((brightonDevice *) bwin->activedev->dev)->configure
390 					(bwin->activedev->dev, event);
391 			}
392 		}
393 /*
394 			else {
395 			if (device->flags & BRIGHTON_TRACKING)
396 			{
397 					event->command = BRIGHTON_ENTER;
398 					device->configure(device, event);
399 			}
400 		}
401 */
402 		return(0);
403 	}
404 
405 	if (event->command == BRIGHTON_KEYRELEASE)
406 	{
407 		/*
408 		 * Deliver the event.
409 		 */
410 		event->x -= panel->sx;
411 		event->y -= panel->sy;
412 
413 		if (bwin->activedev)
414 		{
415 			((brightonDevice *) bwin->activedev->dev)->configure
416 				(bwin->activedev->dev, event);
417 			return(0);
418 		}
419 
420 		if (device == 0)
421 			return(0);
422 
423 		((brightonDevice *) device->dev)->configure(device->dev, event);
424 	}
425 
426 	if (event->command == BRIGHTON_KEYPRESS)
427 	{
428 		/*
429 		 * Deliver the event.
430 		 */
431 		event->x -= panel->sx;
432 		event->y -= panel->sy;
433 
434 		if (bwin->activedev)
435 		{
436 			((brightonDevice *) bwin->activedev->dev)->configure
437 				(bwin->activedev->dev, event);
438 			return(0);
439 		}
440 
441 		if (device == 0)
442 			return(0);
443 
444 		((brightonDevice *) device->dev)->configure(device->dev, event);
445 	}
446 	return(0);
447 }
448 
449 static int
brightonCreateDevices(brightonWindow * bwin,brightonResource * res,int index)450 brightonCreateDevices(brightonWindow *bwin, brightonResource *res, int index)
451 {
452 	int i;
453 	brightonLocations *dev = res->devlocn;
454 
455 /*printf("brightonCreateDevices(%x, %x, %i)\n", bwin, res, index); */
456 
457 	bwin->app->resources[index].devlocn = (brightonILocations *)
458 		brightonmalloc(res->ndevices * sizeof(brightonILocations));
459 
460 	for (i = 0; i < res->ndevices; i++)
461 	{
462 		/*printf("		%s %i (%f,%f)/(%f,%f)\n		%s, %s\n", */
463 		/*	dev[i].name, dev[i].device, */
464 		/*	dev[i].x, dev[i].y, dev[i].width, dev[i].height, */
465 		/*	dev[i].image, dev[i].image2); */
466 
467 		bwin->app->resources[index].devlocn[i].type = dev[i].device;
468 		bwin->app->resources[index].devlocn[i].index = i;
469 		bwin->app->resources[index].devlocn[i].panel = index;
470 		bwin->app->resources[index].devlocn[i].x = dev[i].x;
471 		bwin->app->resources[index].devlocn[i].y = dev[i].y;
472 		bwin->app->resources[index].devlocn[i].width = dev[i].width;
473 		bwin->app->resources[index].devlocn[i].height = dev[i].height;
474 
475 		bwin->app->resources[index].devlocn[i].from = dev[i].from;
476 		bwin->app->resources[index].devlocn[i].to = dev[i].to;
477 
478 		if (dev[i].device == -1)
479 			continue;
480 
481 		bwin->app->resources[index].devlocn[i].callback = dev[i].callback;
482 		bwin->app->resources[index].devlocn[i].flags = dev[i].flags;
483 
484 		bwin->app->resources[index].devlocn[i].image =
485 			brightonReadImage(bwin, dev[i].image);
486 
487 		if (dev[i].image2 != 0)
488 		{
489 			bwin->app->resources[index].devlocn[i].image2 =
490 				brightonReadImage(bwin, dev[i].image2);
491 		}
492 
493 		bwin->app->resources[index].devlocn[i].dev =
494 			(struct brightonDevice *)
495 			brightonCreateDevice(bwin, dev[i].device, index, i, dev[i].image);
496 	}
497 	return(0);
498 }
499 
500 int
brightonCreateInterface(brightonWindow * bwin,brightonApp * app)501 brightonCreateInterface(brightonWindow *bwin, brightonApp *app)
502 {
503 	int i;
504 	brightonResource *res;
505 
506 	if (app == 0)
507 		return(0);
508 
509 /*printf("brightonCreateInterface(%x, %x)\n", bwin, app); */
510 
511 	bwin->template = app;
512 	bwin->app = (brightonIApp *) brightonmalloc(sizeof(brightonIApp));
513 
514 	bwin->app->nresources = app->nresources;
515 	bwin->app->flags = app->flags;
516 	bwin->app->init = app->init;
517 
518 /*	if (bwin->app->init) */
519 /*		bwin->app->init(bwin); */
520 	bwin->app->resources = (brightonIResource *)
521 		brightonmalloc(bwin->app->nresources * sizeof(brightonIResource));
522 
523 	/*
524 	 * Go through each panel on the app panels list, generate them, then do the
525 	 * same for each device on each panel.
526 	 */
527 	for (i = 0; i < app->nresources; i++)
528 	{
529 		res = &app->resources[i];
530 
531 		/*printf("%s (%i,%i)/(%i,%i)\n	%s, %s\n", res->name, */
532 		/*	res->x, res->y, res->width, res->height, */
533 		/*	res->image, res->surface); */
534 
535 		bwin->app->resources[i].x = res->x;
536 		bwin->app->resources[i].y = res->y;
537 		bwin->app->resources[i].width = res->width;
538 		bwin->app->resources[i].height = res->height;
539 		bwin->app->resources[i].flags = res->flags | BRIGHTON_ACTIVE;
540 
541 		bwin->app->resources[i].image = brightonReadImage(bwin, res->image);
542 		bwin->app->resources[i].surface = brightonReadImage(bwin, res->surface);
543 
544 		/*
545 		 * We need to calculate our size, and then create a backgorund canvas
546 		 * for panel rendering. This will only happen when the first configure
547 		 * notify arrives.
548 		 */
549 		bwin->app->resources[i].init = res->init;
550 		bwin->app->resources[i].configure = configurePanel;
551 		bwin->app->resources[i].callback = res->callback;
552 
553 		bwin->app->resources[i].ndevices = res->ndevices;
554 
555 		brightonCreateDevices(bwin, res, i);
556 	}
557 	return(0);
558 }
559 
560 static int
brightonDestroyDevices(brightonWindow * bwin,brightonIResource * res)561 brightonDestroyDevices(brightonWindow *bwin, brightonIResource *res)
562 {
563 	int i;
564 	brightonILocations *dev = res->devlocn;
565 	brightonDevice *device = (brightonDevice *) dev->dev;
566 
567 	for (i = 0; i < res->ndevices; i++)
568 	{
569 		device = (brightonDevice *) dev[i].dev;
570 
571 		if ((device == 0) || (device->device == -1))
572 			continue;
573 
574 		brightonFreeBitmap(bwin, device->image);
575 		brightonFreeBitmap(bwin, device->image2);
576 
577 		brightonFreeBitmap(bwin,
578 			bwin->app->resources[device->panel].devlocn[device->index].image);
579 		brightonFreeBitmap(bwin,
580 			bwin->app->resources[device->panel].devlocn[device->index].image2);
581 
582 /*		brightoneDestroyDevice(bwin, dev->device); */
583 	}
584 
585 	brightonfree(res->devlocn);
586 
587 	return(0);
588 }
589 
590 int
brightonDestroyInterface(brightonWindow * bwin)591 brightonDestroyInterface(brightonWindow *bwin)
592 {
593 	int i;
594 
595 	printf("brightonDestroyInterface(%p): %i\n", bwin, bwin->app->nresources);
596 
597 	for (i = 0; i < bwin->app->nresources; i++)
598 	{
599 		/*
600 		 * Since we are going to wipe out this interface, prevent any further
601 		 * rendering.
602 		 */
603 		bwin->app->resources[i].flags |= BRIGHTON_WITHDRAWN;
604 
605 		brightonDestroyDevices(bwin, &bwin->app->resources[i]);
606 
607 		brightonFreeBitmap(bwin, bwin->app->resources[i].image);
608 		brightonFreeBitmap(bwin, bwin->app->resources[i].surface);
609 	}
610 
611 	brightonfree(bwin->app->resources);
612 	brightonfree(bwin->app);
613 
614 	return(0);
615 }
616 
617