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