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