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