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
destroyScale(brightonDevice * dev)30 destroyScale(brightonDevice *dev)
31 {
32 	printf("destroyScale()\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
displayscale(brightonDevice * dev)42 displayscale(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 - 5,
86 				dev->y + dev->bwin->app->resources[dev->panel].sy,
87 				dev->width / 8 + 5, 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 - 7,
118 				dev->y + dev->bwin->app->resources[dev->panel].sy,
119 				dev->position - dev->lastposition + (dev->width >> 2) + 5,
120 				dev->height + 9);
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 + 7);
128 		}
129 	} else {
130 		if (dev->lastposition >= 0)
131 		{
132 			brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
133 				dev->x + dev->bwin->app->resources[dev->panel].sx,
134 				dev->y + ((int) dev->lastposition)
135 					+ dev->bwin->app->resources[dev->panel].sy - 1,
136 				dev->width, dev->height / 4 + 1);
137 			brightonRenderShadow(dev, 1);
138 		}
139 
140 		dev->position = displayvalue * (dev->height - dev->height / 4);
141 
142 		/*
143 		 * Drawbars are only ever rendered vertically.
144 		 */
145 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
146 			& BRIGHTON_HSCALE)
147 		{
148 			brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
149 				dev->x + dev->bwin->app->resources[dev->panel].sx,
150 				dev->y + dev->bwin->app->resources[dev->panel].sy,
151 				dev->width, dev->height);
152 
153 			brightonStretch(dev->bwin, dev->image2,
154 				dev->bwin->dlayer,
155 				(int) (dev->x + dev->bwin->app->resources[dev->panel].sx),
156 				(int) (dev->y + dev->bwin->app->resources[dev->panel].sy),
157 				dev->width, (int) dev->position, 0);
158 
159 			brightonFinalRender(dev->bwin,
160 				dev->x + dev->bwin->app->resources[dev->panel].sx,
161 				dev->y + dev->bwin->app->resources[dev->panel].sy,
162 				dev->width, (int) dev->height);
163 		}
164 
165 		/*
166 		 * Only draw fixed number of steps. Panned. Just draw it.....
167 		 */
168 		brightonStretch(dev->bwin, dev->image,
169 			dev->bwin->dlayer,
170 			dev->x + dev->bwin->app->resources[dev->panel].sx,
171 			(int)(dev->y + dev->position
172 				+ dev->bwin->app->resources[dev->panel].sy),
173 			dev->width, dev->height / 4,
174 			0);
175 
176 		brightonRenderShadow(dev, 0);
177 
178 		/*
179 		 * And request the panel to put this onto the respective image.
180 		 */
181 		if (dev->position > dev->lastposition)
182 		{
183 			brightonFinalRender(dev->bwin,
184 				dev->x + dev->bwin->app->resources[dev->panel].sx - 1,
185 				dev->y + dev->lastposition
186 					+ dev->bwin->app->resources[dev->panel].sy - 1,
187 				dev->width * 2 + 1,
188 				dev->position - dev->lastposition + (dev->height >> 2)
189 					+ (dev->width >> 1) + 1);
190 		} else {
191 			brightonFinalRender(dev->bwin,
192 				dev->x + dev->bwin->app->resources[dev->panel].sx - 1,
193 				dev->y + dev->position
194 					+ dev->bwin->app->resources[dev->panel].sy,
195 				dev->width * 2 + 1,
196 				dev->lastposition - dev->position + (dev->height >> 2) + 1
197 					+ (dev->width >> 1));
198 		}
199 	}
200 
201 	dev->lastvalue = dev->value;
202 	dev->lastposition = dev->position;
203 
204 	return(0);
205 }
206 
207 static void
considercallback(brightonDevice * dev)208 considercallback(brightonDevice *dev)
209 {
210 	brightonIResource *panel = &dev->bwin->app->resources[dev->panel];
211 	float callvalue;
212 
213 	if (dev->bwin->flags & BRIGHTON_NO_DRAW)
214 		return;
215 
216 	if (dev->value > 1.0)
217 		dev->value = 1.0;
218 	else if (dev->value < 0)
219 		dev->value = 0.0;
220 
221 	/*
222 	 * Due to the co-ordinate system, if we do NOT have the reverse flags
223 	 * then we need to reverse the value.
224 	 */
225 	if ((dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
226 		& BRIGHTON_REVERSE) == 0)
227 		callvalue = 1.0 - dev->value;
228 	else
229 		callvalue = dev->value;
230 
231 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to != 1.0)
232 	{
233 		callvalue =
234 			(callvalue
235 			* dev->bwin->app->resources[dev->panel].devlocn[dev->index].to);
236 
237 		if ((callvalue - ((int) callvalue)) > 0.5)
238 			callvalue = ((float) ((int) callvalue) + 1);
239 		else
240 			callvalue = ((float) ((int) callvalue));
241 	}
242 
243 	if (dev->lastvalue != dev->value)
244 	{
245 		if (panel->devlocn[dev->index].callback)
246 		{
247 			panel->devlocn[dev->index].callback(dev->bwin, dev->panel,
248 				dev->index, callvalue);
249 		} else {
250 			if (panel->callback)
251 				panel->callback(dev->bwin, dev->panel, dev->index, callvalue);
252 		}
253 	}
254 }
255 
256 static int cx, cy;
257 static float sval;
258 
259 static int
configure(brightonDevice * dev,brightonEvent * event)260 configure(brightonDevice *dev, brightonEvent *event)
261 {
262 /*	printf("configureScale(%i, %f)\n", event->command, event->value); */
263 
264 	if (event->command == -1)
265 		return(-1);
266 
267 	if (event->command == BRIGHTON_RESIZE)
268 	{
269 		dev->originx = event->x;
270 		dev->originy = event->y;
271 
272 		dev->x = event->x;
273 		dev->y = event->y;
274 		dev->width = event->w;
275 		dev->height = event->h;
276 
277 		/*
278 		 * We should now rework our parent understanding of our window, since
279 		 * it will have altered. NOT NECESSARY FOR SCALE.
280 		brightonPanelLocation(dev->bwin,
281 			dev->panel, dev->index, dev->x, dev->y, dev->width, dev->height);
282 
283 		considercallback(dev);
284 		 */
285 
286 		/*
287 		 * Highlights need to be rendered dynamically in displayscale().
288 		 */
289 
290 		dev->lastvalue = -1;
291 		displayscale(dev);
292 
293 		return(0);
294 	}
295 
296 	if (event->command == BRIGHTON_KEYRELEASE)
297 	{
298 		/*
299 		 * This is a little bit 'happens they work'. We should fix these key
300 		 * mappings for keycodes.
301 		 */
302 		switch(event->key) {
303 			default:
304 				break;
305 			case 37:
306 			case 66:
307 			case 109:
308 			case 65508:
309 			case 65507:
310 				dev->flags &= ~BRIGHTON_CONTROLKEY;
311 				cx = cy = sval = -1;
312 				break;
313 			case 50:
314 			case 62:
315 			case 65505:
316 				dev->flags &= ~BRIGHTON_SHIFTKEY;
317 				break;
318 		}
319 	}
320 
321 	if (event->command == BRIGHTON_BUTTONPRESS)
322 	{
323 		/*
324 		 * This is hard coded, it calls back to the GUI. This is incorrect as
325 		 * the callback dispatcher should be requested by the GUI.
326 		 *
327 		 * Perhaps the MIDI code should actually be in the same library? Why
328 		 * does the GUI need to know about this?
329 		 */
330 		if (event->key == BRIGHTON_BUTTON2)
331 			brightonRegisterController(dev);
332 
333 		cx = event->x;
334 		cy = event->y;
335 
336 		return(0);
337 	}
338 
339 	if (event->command == BRIGHTON_BUTTONRELEASE)
340 	{
341 		cx = cy = sval = -1;
342 		dev->flags &= ~BRIGHTON_CONTROLKEY;
343 
344 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
345 			& BRIGHTON_CENTER)
346 		{
347 			dev->value = 0.5;
348 
349 			considercallback(dev);
350 
351 			displayscale(dev);
352 		}
353 
354 		return(0);
355 	}
356 
357 	if (event->command == BRIGHTON_KEYPRESS)
358 	{
359 		switch(event->key) {
360 			default:
361 				break;
362 			case 37:
363 			case 66:
364 			case 109:
365 			case 65508:
366 			case 65507:
367 				cx = event->x;
368 				cy = event->y;
369 				sval = dev->value;
370 				dev->flags |= BRIGHTON_CONTROLKEY;
371 				break;
372 			case 50:
373 			case 62:
374 			case 65505:
375 				dev->flags |= BRIGHTON_SHIFTKEY;
376 				break;
377 			case 0x6a:
378 			case 0xff54:
379 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
380 				{
381 					if (dev->flags & BRIGHTON_SHIFTKEY)
382 						dev->value -= ((float) 256) / 16384;
383 					else
384 						dev->value -= ((float) 1) / 16384;
385 				} else {
386 					if (dev->flags & BRIGHTON_SHIFTKEY)
387 						dev->value += ((float) 256) / 16384;
388 					else
389 						dev->value += ((float) 1) / 16384;
390 				}
391 				break;
392 			case 0x6b:
393 			case 0xff52:
394 				/*if (dev->flags & BRIGHTON_VERTICAL) */
395 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
396 				{
397 					if (dev->flags & BRIGHTON_SHIFTKEY)
398 						dev->value += ((float) 256) / 16384;
399 					else
400 						dev->value += ((float) 1) / 16384;
401 				} else {
402 					if (dev->flags & BRIGHTON_SHIFTKEY)
403 						dev->value -= ((float) 256) / 16384;
404 					else
405 						dev->value -= ((float) 1) / 16384;
406 				}
407 				break;
408 			case 0xff51:
409 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
410 				{
411 					if (dev->flags & BRIGHTON_SHIFTKEY)
412 						dev->value -= ((float) 2048) / 16384;
413 					else
414 						dev->value -= ((float) 32) / 16384;
415 				} else {
416 					if (dev->flags & BRIGHTON_SHIFTKEY)
417 						dev->value += ((float) 2048) / 16384;
418 					else
419 						dev->value += ((float) 32) / 16384;
420 				}
421 				break;
422 			case 0xff53:
423 				/*if (dev->flags & BRIGHTON_VERTICAL) */
424 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
425 				{
426 					if (dev->flags & BRIGHTON_SHIFTKEY)
427 						dev->value += ((float) 2048) / 16384;
428 					else
429 						dev->value += ((float) 32) / 16384;
430 				} else {
431 					if (dev->flags & BRIGHTON_SHIFTKEY)
432 						dev->value -= ((float) 2048) / 16384;
433 					else
434 						dev->value -= ((float) 32) / 16384;
435 				}
436 				break;
437 		}
438 
439 		considercallback(dev);
440 
441 		displayscale(dev);
442 	}
443 
444 	if (event->command == BRIGHTON_MOTION)
445 	{
446 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
447 			& BRIGHTON_VERTICAL)
448 	 	{
449 			/*
450 			 * Need to add in an optional central dead spot. This should be a
451 			 * small fraction of either side of the pot. It will be where
452 			 * position deviates from mouse location.
453 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
454 				& BRIGHTON_NOTCH)
455 			{
456 			} else
457 			 */
458 			if (dev->flags & BRIGHTON_CONTROLKEY)
459 			{
460 				float deltax;
461 
462 				if (cx == -1)
463 				{
464 					sval = dev->value;
465 					cx = event->x;
466 					cy = event->y;
467 				}
468 
469 				deltax = ((float) (event->x - cx)) / 16383.0f;
470 
471 				dev->value = sval + deltax;
472 			} else if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_NOTCH)
473 			{
474 				/*
475 				 * When we are passing zero we should hold for a bit.
476 				 */
477 				dev->value = (((float) (event->x + 5 - dev->x - (dev->width / 8)))
478 					/ (dev->width - dev->width / 4));
479 
480 				if (dev->value > 0.6)
481 					dev->value -= 0.1;
482 				else if (dev->value < 0.4)
483 					dev->value += 0.1;
484 				else
485 					dev->value = 0.5;
486 			} else {
487 				/* Fanning scaler controls */
488 				if ((event->y - dev->y) > dev->height) {
489 					dev->value = (((float)
490 						(cx - dev->x - (dev->width / 8)))
491 							/ (dev->width - dev->width / 4));
492 					dev->value += (event->x - cx)
493 						/ (16.0 * (1.0 + event->y - dev->y - dev->height/2));
494 				} else if ((event->y - dev->y) < -dev->height) {
495 					dev->value = (((float)
496 						(cx - dev->x - (dev->width / 8)))
497 							/ (dev->width - dev->width / 4));
498 					dev->value -= (event->x - cx)
499 						/ (16.0 * (1.0 + event->y - dev->y - dev->height/2));
500 				} else {
501 					cx = event->x;
502 
503 					dev->value = (((float)
504 						(event->x + 5 - dev->x - (dev->width / 8)))
505 							/ (dev->width - dev->width / 4));
506 				}
507 			}
508 		} else {
509 			if (dev->flags & BRIGHTON_CONTROLKEY)
510 			{
511 				float deltax;
512 
513 				if (cx == -1)
514 				{
515 					sval = dev->value;
516 					cx = event->x;
517 					cy = event->y;
518 				}
519 
520 				deltax = ((float) (event->y - cy)) / 16383.0f;
521 
522 				dev->value = sval + deltax;
523 			} else if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_NOTCH)
524 			{
525 				dev->value = (((float) (event->y - dev->y - (dev->height / 8)))
526 					/ (dev->height - dev->height / 4));
527 
528 				if (dev->value > 0.6)
529 					dev->value -= 0.1;
530 				else if (dev->value < 0.4)
531 					dev->value += 0.1;
532 				else
533 					dev->value = 0.5;
534 			} else {
535 				/* Fanning scaler controls */
536 //		} else if (dev->bwin->flags & BRIGHTON_ROTARY_UD) {
537 				if ((event->x - dev->x) > dev->width) {
538 					dev->value = (((float)
539 						(cy - dev->y - (dev->height / 8)))
540 							/ (dev->height - dev->height / 4));
541 					dev->value += (event->y - cy)
542 						/ (16.0 * (1.0 + event->x - dev->x - dev->width/2));
543 				} else if ((event->x - dev->x) < -dev->width) {
544 					dev->value = (((float)
545 						(cy - dev->y - (dev->height / 8)))
546 							/ (dev->height - dev->height / 4));
547 					dev->value -= (event->y - cy)
548 						/ (16.0 * (1.0 + event->x - dev->x - dev->width/2));
549 				} else {
550 					cy = event->y;
551 
552 					dev->value = (((float)
553 						(event->y - dev->y - (dev->height / 8)))
554 							/ (dev->height - dev->height / 4));
555 				}
556 			}
557 		}
558 
559 /*printf("scale motion %i %i, %i %i, %i %i: %f\n", */
560 /*event->x, event->y, dev->x, dev->y, dev->width, dev->height, dev->value); */
561 
562 		/*
563 		 * We now need to consider rounding this to the resolution of this
564 		 * device. If the max value is not 1.0 then we need to put fixed steps
565 		 * into our new device value.
566 		 */
567 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to != 1.0)
568 		{
569 			dev->value = (float) ((int)
570 				(dev->value
571 				* dev->bwin->app->resources[dev->panel].devlocn[dev->index].to))
572 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
573 		}
574 
575 		considercallback(dev);
576 
577 		displayscale(dev);
578 
579 		return(0);
580 	}
581 
582 	if (event->command == BRIGHTON_PARAMCHANGE)
583 	{
584 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
585 			& BRIGHTON_REVERSE)
586 			dev->value = event->value
587 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
588 		else {
589 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to
590 				!= 1.0)
591 			{
592 				dev->value =
593 					(dev->bwin->app->resources[dev->panel].devlocn[dev->index].to - event->value)
594 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
595 			} else {
596 				dev->value = (1.0 - event->value) /
597 					dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
598 			}
599 		}
600 
601 		considercallback(dev);
602 
603 		displayscale(dev);
604 
605 		return(0);
606 	}
607 	return(0);
608 }
609 
610 int *
createScale(brightonWindow * bwin,brightonDevice * dev,int index,char * bitmap)611 createScale(brightonWindow *bwin, brightonDevice *dev, int index, char *bitmap)
612 {
613 /*	printf("createScale(%s)\n", bitmap); */
614 
615 	dev->destroy = destroyScale;
616 	dev->configure = configure;
617 	dev->index = index;
618 
619 	dev->bwin = bwin;
620 
621 	if (bitmap == 0)
622 	{
623 		if (dev->image)
624 			brightonFreeBitmap(bwin, dev->image);
625 		/*
626 		 * Open the default bitmap
627 		 */
628 		if (bwin->app->resources[dev->panel].devlocn[dev->index].image != 0)
629 			dev->image =
630 				bwin->app->resources[dev->panel].devlocn[dev->index].image;
631 		else
632 			dev->image = brightonReadImage(bwin, "bitmaps/knobs/slider1.xpm");
633 	} else {
634 		if (dev->image)
635 			brightonFreeBitmap(bwin, dev->image);
636 		dev->image = brightonReadImage(bwin, bitmap);
637 	}
638 
639 	if (bwin->app->resources[dev->panel].devlocn[dev->index].flags &
640 		BRIGHTON_HSCALE)
641 	{
642 		if (dev->image2)
643 			brightonFreeBitmap(bwin, dev->image2);
644 		dev->image2 = brightonReadImage(bwin, "bitmaps/knobs/extend.xpm");
645 	}
646 
647 	/*
648 	 * These will force an update when we first display ourselves.
649 	 */
650 	if (bwin->app->resources[dev->panel].devlocn[dev->index].flags
651 		& BRIGHTON_CENTER)
652 		dev->value = 0.5;
653 	else
654 		dev->value = 0;
655 
656 	dev->value = 0.500001;
657 
658 	dev->lastvalue = -1;
659 	dev->lastposition = 0;
660 
661 	return(0);
662 }
663 
664