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  * This will be a linear potmeter. Takes a bitmap and locates it according to
23  * input from the mouse/keyboard. Previous positions need to be unmapped, since
24  * there is total repositioning of the image bitmap.
25  */
26 
27 #include "brightoninternals.h"
28 
29 int
destroyLever(brightonDevice * dev)30 destroyLever(brightonDevice *dev)
31 {
32 	printf("destroyLever()\n");
33 
34 	if (dev->image)
35 		brightonFreeBitmap(dev->bwin, dev->image);
36 	dev->image = NULL;
37 
38 	return(0);
39 }
40 
41 static int
displaylever(brightonDevice * dev)42 displaylever(brightonDevice *dev)
43 {
44 	brightonIResource *panel;
45 	float displayvalue;
46 
47 	if (dev->bwin->app->resources[dev->panel].flags & BRIGHTON_WITHDRAWN)
48 		return(0);
49 
50 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
51 		& BRIGHTON_WITHDRAWN)
52 		return(0);
53 
54 	panel = &dev->bwin->app->resources[dev->panel];
55 
56 	/*
57 	 * Build up a smooth position for the pot. We may need to adjust this based
58 	 * on the to/from values.
59 	 */
60 
61 	if (dev->value == dev->lastvalue)
62 		return(0);
63 
64 	displayvalue = dev->value;
65 
66 /*
67 	brightonFinalRender(dev->bwin,
68 		dev->x + dev->bwin->app->resources[dev->panel].sx,
69 		dev->y + dev->lastposition + dev->bwin->app->resources[dev->panel].sy,
70 		dev->width, dev->height / 4);
71 */
72 
73 	/*
74 	 * This seems odd, the vertical flag refers to the scrolled item, not the
75 	 * direction of movement. Perhaps that should change as the direction of
76 	 * movement is counterintuitive
77 	 */
78 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
79 		& BRIGHTON_VERTICAL)
80 	{
81 		if (dev->lastposition >= 0)
82 		{
83 			brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
84 				dev->x + ((int) dev->lastposition)
85 					+ dev->bwin->app->resources[dev->panel].sx,
86 				dev->y + dev->bwin->app->resources[dev->panel].sy,
87 				dev->width / 8, dev->height);
88 			brightonRenderShadow(dev, 1);
89 		}
90 
91 		dev->position = displayvalue * (dev->width - dev->width / 4);
92 
93 		/*
94 		 * Only draw fixed number of steps. Panned. Just draw it.....
95 		 */
96 		brightonStretch(dev->bwin, dev->image,
97 			dev->bwin->dlayer,
98 			(int)(dev->x + dev->position
99 				+ dev->bwin->app->resources[dev->panel].sx),
100 			dev->y + dev->bwin->app->resources[dev->panel].sy,
101 			dev->width / 8, dev->height,
102 			1);
103 
104 		brightonRenderShadow(dev, 0);
105 
106 		/*
107 		 * And request the panel to put this onto the respective image.
108 		 */
109 		if (dev->position > dev->lastposition)
110 		{
111 			/*
112 			 * We have to render from the last position up to the current one
113 			 * adding in bits for shade.
114 			 */
115 			brightonFinalRender(dev->bwin,
116 				dev->x + dev->lastposition
117 					+ dev->bwin->app->resources[dev->panel].sx,
118 				dev->y + dev->bwin->app->resources[dev->panel].sy,
119 				dev->position - dev->lastposition + (dev->width >> 2),
120 				dev->height + 5);
121 		} else {
122 			brightonFinalRender(dev->bwin,
123 				dev->x + dev->position
124 					+ dev->bwin->app->resources[dev->panel].sx,
125 				dev->y + dev->bwin->app->resources[dev->panel].sy,
126 				dev->lastposition - dev->position + (dev->width >> 2),
127 				dev->height + 5);
128 		}
129 	} else {
130 		brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
131 			dev->x + dev->bwin->app->resources[dev->panel].sx,
132 			dev->y + dev->bwin->app->resources[dev->panel].sy,
133 			dev->width, dev->height + 2);
134 		brightonRenderShadow(dev, 1);
135 
136 		dev->position = displayvalue * (dev->height - dev->height / 4);
137 
138 		/*
139 		 * Only draw fixed number of steps. Panned. Just draw it.....
140 		brightonStretch(dev->bwin, dev->image,
141 			dev->bwin->dlayer,
142 			dev->x + dev->bwin->app->resources[dev->panel].sx,
143 			(int)(dev->y + dev->position
144 				+ dev->bwin->app->resources[dev->panel].sy),
145 			dev->width, dev->height / 4,
146 			0);
147 		 *
148 		 * If we are greater than 1/2 then stretch the image from 3/8 up to
149 		 * 5/8 + value * 3/8.
150 		 * If we are less than 1/2 then stretch (bitmap2) from value * 3/8
151 		 * up to 5/8.
152 		 */
153 		if (displayvalue < 0.5)
154 			brightonStretch(dev->bwin, dev->image2 == 0?
155 				dev->image: dev->image2,
156 				dev->bwin->dlayer,
157 				dev->x + dev->bwin->app->resources[dev->panel].sx,
158 				(int) (dev->y + dev->bwin->app->resources[dev->panel].sy
159 					+ (dev->height * 6 / 8) * displayvalue),
160 				dev->width,
161 				(int) (dev->height * 1 / 4 +
162 					dev->height * 6 / 8 * (0.5 - displayvalue))
163 					- dev->height * (0.5 - displayvalue) / 2,
164 				0);
165 		else
166 			brightonStretch(dev->bwin, dev->image, dev->bwin->dlayer,
167 				dev->x + dev->bwin->app->resources[dev->panel].sx,
168 				(int) (dev->y + dev->bwin->app->resources[dev->panel].sy
169 					+ dev->height * 3 / 8)
170 					+ dev->height * (displayvalue - 0.5) / 2,
171 				dev->width,
172 				dev->height * displayvalue - dev->height * 2 / 8
173 					- dev->height * (displayvalue - 0.5) * 6 / 8,
174 				0);
175 
176 		brightonRenderShadow(dev, 0);
177 
178 		/*
179 		 * And request the panel to put this onto the respective image.
180 		 */
181 		brightonFinalRender(dev->bwin,
182 			dev->x + dev->bwin->app->resources[dev->panel].sx,
183 			dev->y + dev->bwin->app->resources[dev->panel].sy,
184 			dev->width * 2 + 1,
185 			dev->height + dev->height / 4);
186 	}
187 
188 	dev->lastvalue = dev->value;
189 	dev->lastposition = dev->position;
190 
191 	return(0);
192 }
193 
194 static void
considercallback(brightonDevice * dev)195 considercallback(brightonDevice *dev)
196 {
197 	brightonIResource *panel = &dev->bwin->app->resources[dev->panel];
198 	float callvalue;
199 
200 	if (dev->bwin->flags & BRIGHTON_NO_DRAW)
201 		return;
202 
203 	if (dev->value > 1.0)
204 		dev->value = 1.0;
205 	else if (dev->value < 0)
206 		dev->value = 0.0;
207 
208 	/*
209 	 * Due to the co-ordinate system, if we do NOT have the reverse flags
210 	 * then we need to reverse the value.
211 	 */
212 	if ((dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
213 		& BRIGHTON_REVERSE) == 0)
214 		callvalue = 1.0 - dev->value;
215 	else
216 		callvalue = dev->value;
217 
218 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to != 1.0)
219 	{
220 		callvalue =
221 			(callvalue
222 			* dev->bwin->app->resources[dev->panel].devlocn[dev->index].to);
223 
224 		if ((callvalue - ((int) callvalue)) > 0.5)
225 			callvalue = ((float) ((int) callvalue) + 1);
226 		else
227 			callvalue = ((float) ((int) callvalue));
228 	}
229 
230 	if (dev->lastvalue != dev->value)
231 	{
232 		if (panel->devlocn[dev->index].callback)
233 		{
234 			panel->devlocn[dev->index].callback(dev->bwin, dev->panel,
235 				dev->index, callvalue);
236 		} else {
237 			if (panel->callback)
238 				panel->callback(dev->bwin, dev->panel, dev->index, callvalue);
239 		}
240 	}
241 }
242 
243 static int cx, cy;
244 static float sval;
245 
246 static int
configure(brightonDevice * dev,brightonEvent * event)247 configure(brightonDevice *dev, brightonEvent *event)
248 {
249 /*	printf("configureLever(%i, %f)\n", event->command, event->value); */
250 
251 	if (event->command == -1)
252 		return(-1);
253 
254 	if (event->command == BRIGHTON_RESIZE)
255 	{
256 		dev->originx = event->x;
257 		dev->originy = event->y;
258 
259 		dev->x = event->x;
260 		dev->y = event->y;
261 		dev->width = event->w;
262 		dev->height = event->h;
263 
264 		/*
265 		 * We should now rework our parent understanding of our window, since
266 		 * it will have altered. NOT NECESSARY FOR SCALE.
267 		brightonPanelLocation(dev->bwin,
268 			dev->panel, dev->index, dev->x, dev->y, dev->width, dev->height);
269 
270 		considercallback(dev);
271 		 */
272 
273 		/*
274 		 * Highlights need to be rendered dynamically in displaylever().
275 		 */
276 
277 		dev->lastvalue = -1;
278 		displaylever(dev);
279 
280 		return(0);
281 	}
282 
283 	if (event->command == BRIGHTON_KEYRELEASE)
284 	{
285 		/*
286 		 * This is a little bit 'happens they work'. We should fix these key
287 		 * mappings for keycodes.
288 		 */
289 		switch(event->key) {
290 			default:
291 				break;
292 			case 37:
293 			case 109:
294 			case 65508:
295 			case 65507:
296 				dev->flags &= ~BRIGHTON_CONTROLKEY;
297 				cx = cy = sval = -1;
298 				break;
299 			case 50:
300 			case 62:
301 			case 65505:
302 				dev->flags &= ~BRIGHTON_SHIFTKEY;
303 				break;
304 		}
305 	}
306 
307 	if (event->command == BRIGHTON_BUTTONPRESS)
308 	{
309 		/*
310 		 * This is hard coded, it calls back to the GUI. This is incorrect as
311 		 * the callback dispatcher should be requested by the GUI.
312 		 *
313 		 * Perhaps the MIDI code should actually be in the same library? Why
314 		 * does the GUI need to know about this?
315 		 */
316 		if (event->key == BRIGHTON_BUTTON2)
317 			brightonRegisterController(dev);
318 
319 		return(0);
320 	}
321 
322 	if (event->command == BRIGHTON_BUTTONRELEASE)
323 	{
324 		cx = cy = sval = -1;
325 		dev->flags &= ~BRIGHTON_CONTROLKEY;
326 
327 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
328 			& BRIGHTON_CENTER)
329 		{
330 			dev->value = 0.5;
331 
332 			considercallback(dev);
333 
334 			displaylever(dev);
335 		}
336 
337 		return(0);
338 	}
339 
340 	if (event->command == BRIGHTON_KEYPRESS)
341 	{
342 		switch(event->key) {
343 			default:
344 				break;
345 			case 37:
346 			case 109:
347 			case 65508:
348 			case 65507:
349 				cx = event->x;
350 				cy = event->y;
351 				sval = dev->value;
352 				dev->flags |= BRIGHTON_CONTROLKEY;
353 				break;
354 			case 50:
355 			case 62:
356 			case 65505:
357 				dev->flags |= BRIGHTON_SHIFTKEY;
358 				break;
359 			case 0x6a:
360 			case 0xff54:
361 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
362 				{
363 					if (dev->flags & BRIGHTON_SHIFTKEY)
364 						dev->value -= ((float) 256) / 16384;
365 					else
366 						dev->value -= ((float) 1) / 16384;
367 				} else {
368 					if (dev->flags & BRIGHTON_SHIFTKEY)
369 						dev->value += ((float) 256) / 16384;
370 					else
371 						dev->value += ((float) 1) / 16384;
372 				}
373 				break;
374 			case 0x6b:
375 			case 0xff52:
376 				/*if (dev->flags & BRIGHTON_VERTICAL) */
377 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
378 				{
379 					if (dev->flags & BRIGHTON_SHIFTKEY)
380 						dev->value += ((float) 256) / 16384;
381 					else
382 						dev->value += ((float) 1) / 16384;
383 				} else {
384 					if (dev->flags & BRIGHTON_SHIFTKEY)
385 						dev->value -= ((float) 256) / 16384;
386 					else
387 						dev->value -= ((float) 1) / 16384;
388 				}
389 				break;
390 		}
391 
392 		considercallback(dev);
393 
394 		displaylever(dev);
395 	}
396 
397 	if (event->command == BRIGHTON_MOTION)
398 	{
399 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
400 			& BRIGHTON_VERTICAL)
401 	 	{
402 			/*
403 			 * Need to add in an optional central dead spot. This should be a
404 			 * small fraction of either side of the pot. It will be where
405 			 * position deviates from mouse location.
406 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
407 				& BRIGHTON_NOTCH)
408 			{
409 			} else
410 			 */
411 			if (dev->flags & BRIGHTON_CONTROLKEY)
412 			{
413 				float deltax;
414 
415 				if (cx == -1)
416 				{
417 					sval = dev->value;
418 					cx = event->x;
419 					cy = event->y;
420 				}
421 
422 				deltax = ((float) (event->x - cx)) / 16383.0f;
423 
424 				dev->value = sval + deltax;
425 			} else if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_NOTCH)
426 			{
427 				/*
428 				 * When we are passing zero we should hold for a bit.
429 				 */
430 				dev->value = (((float) (event->x + 5 - dev->x - (dev->width / 8)))
431 					/ (dev->width - dev->width / 4));
432 
433 				if (dev->value > 0.6)
434 					dev->value -= 0.1;
435 				else if (dev->value < 0.4)
436 					dev->value += 0.1;
437 				else
438 					dev->value = 0.5;
439 			} else
440 				dev->value = (((float) (event->x + 5 - dev->x - (dev->width / 8)))
441 					/ (dev->width - dev->width / 4));
442 		} else {
443 			if (dev->flags & BRIGHTON_CONTROLKEY)
444 			{
445 				float deltax;
446 
447 				if (cx == -1)
448 				{
449 					sval = dev->value;
450 					cx = event->x;
451 					cy = event->y;
452 				}
453 
454 				deltax = ((float) (event->y - cy)) / 16383.0f;
455 
456 				dev->value = sval + deltax;
457 			} else if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_NOTCH)
458 			{
459 				dev->value = (((float) (event->y - dev->y - (dev->height / 8)))
460 					/ (dev->height - dev->height / 4));
461 
462 				if (dev->value > 0.6)
463 					dev->value -= 0.1;
464 				else if (dev->value < 0.4)
465 					dev->value += 0.1;
466 				else
467 					dev->value = 0.5;
468 			} else
469 				dev->value = (((float) (event->y - dev->y - (dev->height / 8)))
470 					/ (dev->height - dev->height / 4));
471 		}
472 
473 /*printf("lever motion %i %i, %i %i, %i %i: %f\n", */
474 /*event->x, event->y, dev->x, dev->y, dev->width, dev->height, dev->value); */
475 
476 		/*
477 		 * We now need to consider rounding this to the resolution of this
478 		 * device. If the max value is not 1.0 then we need to put fixed steps
479 		 * into our new device value.
480 		 */
481 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to != 1.0)
482 		{
483 			dev->value = (float) ((int)
484 				(dev->value
485 				* dev->bwin->app->resources[dev->panel].devlocn[dev->index].to))
486 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
487 		}
488 
489 		considercallback(dev);
490 
491 		displaylever(dev);
492 
493 		return(0);
494 	}
495 
496 	if (event->command == BRIGHTON_PARAMCHANGE)
497 	{
498 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
499 			& BRIGHTON_REVERSE)
500 			dev->value = event->value
501 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
502 		else {
503 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to
504 				!= 1.0)
505 			{
506 				dev->value =
507 					(dev->bwin->app->resources[dev->panel].devlocn[dev->index].to - event->value)
508 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
509 			} else {
510 				dev->value = (1.0 - event->value) /
511 					dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
512 			}
513 		}
514 
515 		considercallback(dev);
516 
517 		displaylever(dev);
518 
519 		return(0);
520 	}
521 	return(0);
522 }
523 
524 int *
createLever(brightonWindow * bwin,brightonDevice * dev,int index,char * bitmap)525 createLever(brightonWindow *bwin, brightonDevice *dev, int index, char *bitmap)
526 {
527 /*	printf("createLever(%s)\n", bitmap); */
528 
529 	dev->destroy = destroyLever;
530 	dev->configure = configure;
531 	dev->index = index;
532 
533 	dev->bwin = bwin;
534 
535 	if (bitmap == 0)
536 	{
537 		if (dev->image)
538 			brightonFreeBitmap(bwin, dev->image);
539 		/*
540 		 * Open the default bitmap
541 		 */
542 		if (bwin->app->resources[dev->panel].devlocn[dev->index].image != 0)
543 			dev->image =
544 				bwin->app->resources[dev->panel].devlocn[dev->index].image;
545 		else
546 			dev->image = brightonReadImage(bwin, "bitmaps/knobs/slider1.xpm");
547 
548 		if (bwin->app->resources[dev->panel].devlocn[dev->index].image2 != 0)
549 			dev->image2 = brightonReadImage(bwin,
550 			bwin->template->resources[dev->panel].devlocn[dev->index].image2);
551 	} else {
552 		if (dev->image)
553 			brightonFreeBitmap(bwin, dev->image);
554 		dev->image = brightonReadImage(bwin, bitmap);
555 
556 		if (bwin->app->resources[dev->panel].devlocn[dev->index].image2 != 0)
557 			dev->image2 = brightonReadImage(bwin,
558 			bwin->template->resources[dev->panel].devlocn[dev->index].image2);
559 	}
560 
561 	if (bwin->app->resources[dev->panel].devlocn[dev->index].flags &
562 		BRIGHTON_HSCALE)
563 	{
564 		if (dev->image2)
565 			brightonFreeBitmap(bwin, dev->image2);
566 		dev->image2 = brightonReadImage(bwin, "bitmaps/knobs/extend.xpm");
567 	}
568 
569 	/*
570 	 * These will force an update when we first display ourselves.
571 	 */
572 	if (bwin->app->resources[dev->panel].devlocn[dev->index].flags
573 		& BRIGHTON_CENTER)
574 		dev->value = 0.5;
575 	else
576 		dev->value = 0;
577 
578 	dev->value = 0.500001;
579 
580 	dev->lastvalue = -1;
581 	dev->lastposition = 0;
582 
583 	return(0);
584 }
585 
586