[Git]Ignore work files.
[synaesthesia.git] / ui.cc
blobaeefc94861243b4c017252a2746060208cdc99b7
1 #include "font.h"
2 #include "icons.h"
3 #include "syna.h"
4 #include <math.h>
5 #include <stdlib.h>
6 #include <stdio.h>
8 void putChar(unsigned char character,int x,int y,int red,int blue) {
9 unsigned short *ptr = ((unsigned short *)output) + x + y*outWidth;
10 unsigned short put = (blue<<8)+red;
11 int i,j;
12 for(i=0;i<8;i++,ptr += outWidth-8)
13 for(j=0;j<8;j++,ptr++)
14 if (font[character*8+i] & (128>>j))
15 *ptr = put;
18 void putString(char *string,int x,int y,int red,int blue) {
19 if (x < 0 || y < 0 || y >= outHeight-8)
20 return;
21 for(;*string && x <= outWidth-8;string++,x+=8)
22 putChar((unsigned char)(*string),x,y,red,blue);
25 struct UIObject {
26 UIObject *next;
28 int visibleMask, activeMask;
29 double x,y,width,height;
30 bool active;
32 virtual int go(bool mouseDown,bool mouseClick,bool mouseOver,
33 double x, double y, double scale, char &hotKey, int &action)
34 = 0;
36 virtual void handleKey(char key, int &action) = 0;
39 struct Button : public UIObject {
40 int icon;
41 char hotKey;
43 bool passive, bright;
45 Button(int _am,int _vm,double _x,double _y,
46 double _size,int _icon,char _key = 0,
47 bool _passive = false, bool _bright = false) {
48 activeMask = _am; visibleMask = _vm;
49 x = _x; y = _y; width = height = _size;
50 icon = _icon; hotKey = _key; passive = _passive; bright = _bright;
53 int go(bool mouseDown,bool mouseClick,bool mouseOver,
54 double _x, double _y, double scale, char &_hotKey, int &action) {
55 polygonEngine.icon(
56 Icons[icon],
57 (bright ? 0x0404 : 0x0200),
58 x*scale,y*scale,width*scale,height*scale);
60 if (mouseOver && !passive)
61 polygonEngine.icon(
62 Icons[icon],
63 0x0004,
64 (x-IconWidths[icon]*width/2)*scale,
65 (y-height/2)*scale,width*scale*2,height*scale*2);
67 if (mouseOver && mouseClick && !passive)
68 action = icon;
70 if (mouseOver && !passive && hotKey)
71 _hotKey = hotKey;
73 return 0;
76 void handleKey(char key, int &action) {
77 if (key == hotKey && !passive)
78 action = icon;
82 struct PopperUpper : public UIObject {
83 int maskAdd;
85 PopperUpper(int _am,int _vm,double _x,double _y,
86 double _width,double _height, int _maskAdd) {
87 activeMask = _am; visibleMask = _vm;
88 x = _x; y = _y; width = _width; height = _height;
89 maskAdd = _maskAdd;
92 int go(bool mouseDown,bool mouseClick,bool mouseOver,
93 double _x, double _y, double scale, char &_hotKey, int &action) {
94 polygonEngine.icon(
95 Icons[Box],
96 0x0200,
97 x*scale,y*scale,width*scale,height*scale);
99 return mouseOver ? maskAdd : 0;
102 void handleKey(char key, int &action) { }
105 #define BarWidth 0.1
106 struct SliderBar : public UIObject {
107 double *value;
108 char leftKey, rightKey;
110 typedef void (*Callback)(double v);
111 Callback callback;
113 SliderBar(int _am,int _vm,double _x,double _y,
114 double _width,double _height, double *_value,
115 Callback _callback, char _leftKey, char _rightKey) {
116 activeMask = _am; visibleMask = _vm;
117 x = _x; y = _y; width = _width; height = _height;
118 value = _value; callback = _callback;
119 leftKey = _leftKey; rightKey = _rightKey;
122 int go(bool mouseDown,bool mouseClick,bool mouseOver,
123 double _x, double _y, double scale, char &_hotKey, int &action) {
124 polygonEngine.icon(
125 Icons[Bar],
126 0x0100,
127 x*scale,y*scale,width*scale,height*scale);
128 polygonEngine.icon(
129 Icons[Slider],
130 0x0400,
131 (x+*value*width-IconWidths[Slider]*height/2)*scale,
132 y*scale,height*scale,height*scale);
134 if (mouseOver) {
135 double newValue = (_x)/(width);
136 if (newValue < 0.0) newValue = 0.0;
137 if (newValue > 1.0) newValue = 1.0;
139 polygonEngine.icon(
140 Icons[Selector],
141 0x0004,
142 (x+newValue*width-IconWidths[Selector]*height/2)*scale,
143 y*scale,height*scale,height*scale);
145 if (mouseDown) {
146 *value = newValue;
148 if (callback)
149 callback(*value);
152 if (mouseOver)
153 _hotKey = (newValue < *value ? leftKey : rightKey);
156 return 0;
159 void handleKey(char key, int &action) {
160 if (key == leftKey || key == rightKey) {
161 if (key == leftKey) {
162 if (*value == 0.0) return;
163 *value -= 0.05;
164 if (*value < 0.0) *value = 0.0;
165 } else {
166 if (*value == 1.0) return;
167 *value += 0.05;
168 if (*value > 1.0) *value = 1.0;
171 if (callback)
172 callback(*value);
177 //Dodgy, uses some globals
178 struct TrackSelector : public UIObject {
179 int position;
181 TrackSelector(int _am,int _vm,double _x,double _y,
182 double _width,double _height) {
183 activeMask = _am; visibleMask = _vm;
184 x = _x; y = _y; width = _width; height = _height;
187 int go(bool mouseDown,bool mouseClick,bool mouseOver,
188 double _x, double _y, double scale, char &_hotKey, int &action) {
189 int count = cdGetTrackCount();
190 if (count == 0) return 0;
192 position = -1;
193 if (mouseOver) {
194 position = int(_x/width*count)+1;
196 if (mouseClick)
197 action = -position;
199 if (position < 10)
200 _hotKey = '0' + position;
201 else if (position == 10)
202 _hotKey = '0';
205 for(int i=0;i<count;i++)
206 polygonEngine.icon(
207 Icons[TrackSelect],
208 (i+1==position?0x0003:(i+1==track?0x0202:0x0100)),
209 x*scale+i*width*scale/count,
210 y*scale,
211 width*scale/count/IconWidths[TrackSelect],
212 height*scale);
214 return 0;
217 void handleKey(char key, int &action) {
218 if (key >= '1' && key <= '9')
219 action = -(key-'0');
220 else if (key == '0')
221 action = -10;
225 static UIObject *uiObjects;
226 static Button *stateButton, *starsButton, *waveButton, *flameButton,
227 *starButton, *diamondButton;
228 static TrackSelector *trackSelector;
229 static int mouseButtons;
231 void setupPalette(double dummy=0.0) {
232 #define BOUND(x) ((x) > 255 ? 255 : (x))
233 #define PEAKIFY(x) int(BOUND((x) - (x)*(255-(x))/255/2))
234 #define MAX(x,y) ((x) > (y) ? (x) : (y))
235 int i;
236 unsigned char palette[768];
238 double scale, fgRed, fgGreen, fgBlue, bgRed, bgGreen, bgBlue;
239 fgRed = fgRedSlider;
240 fgGreen = fgGreenSlider;
241 fgBlue = 1.0 - MAX(fgRedSlider,fgGreenSlider);
242 //scale = MAX(MAX(fgRed,fgGreen),fgBlue);
243 scale = (fgRed+fgGreen+fgBlue)/2.0;
244 fgRed /= scale;
245 fgGreen /= scale;
246 fgBlue /= scale;
248 bgRed = bgRedSlider;
249 bgGreen = bgGreenSlider;
250 bgBlue = 1.0 - MAX(bgRedSlider,bgGreenSlider);
251 //scale = MAX(MAX(bgRed,bgGreen),bgBlue);
252 scale = (bgRed+bgGreen+bgBlue)/2.0;
253 bgRed /= scale;
254 bgGreen /= scale;
255 bgBlue /= scale;
257 for(i=0;i<256;i++) {
258 int f = i&15, b = i/16;
259 //palette[i*3+0] = PEAKIFY(b*bgRed*16+f*fgRed*16);
260 //palette[i*3+1] = PEAKIFY(b*bgGreen*16+f*fgGreen*16);
261 //palette[i*3+2] = PEAKIFY(b*bgBlue*16+f*fgBlue*16);
263 double red = b*bgRed*16+f*fgRed*16;
264 double green = b*bgGreen*16+f*fgGreen*16;
265 double blue = b*bgBlue*16+f*fgBlue*16;
267 double excess = 0.0;
268 for(int j=0;j<5;j++) {
269 red += excess / 3;
270 green += excess / 3;
271 blue += excess / 3;
272 excess = 0.0;
273 if (red > 255) { excess += red-255; red = 255; }
274 if (green > 255) { excess += green-255; green = 255; }
275 if (blue > 255) { excess += blue-255; blue = 255; }
278 double scale = (0.5 + (red+green+blue)/768.0) / 1.5;
279 red *= scale;
280 green *= scale;
281 blue *= scale;
283 palette[i*3+0] = BOUND(int(red));
284 palette[i*3+1] = BOUND(int(green));
285 palette[i*3+2] = BOUND(int(blue));
287 screen->setPalette(palette);
290 void setTrackProgress(double progress) {
291 int interval = cdGetTrackFrame(track+1)-cdGetTrackFrame(track);
292 if (interval <= 0) return;
293 cdPlay(cdGetTrackFrame(track)+int(interval*progress));
296 //Visible mask
297 #define ALL 1
298 #define BUTTONBAR 2
299 #define TRACKBAR 4
300 #define DIALBAR 8
301 #define VOLUMEBAR 16
303 //Active mask
304 //#define ALL 1
305 #define PLAYING 2
306 #define PAUSED 4
307 #define STOPPED 8
308 #define NOCD 32
309 #define OPEN 64
311 static int visibleMask, cdCheckCountDown;
312 static int mouseX, mouseY, lastX, lastY, countDown;
314 void addUI(UIObject *obj) {
315 obj->next = uiObjects;
316 uiObjects = obj;
319 #define IconSize 0.2
320 #define SliderSize 0.125
321 void interfaceInit() {
322 double x,y;
323 uiObjects = 0;
324 //addUI(new Button(ALL,0.025,0.525,IconSize, 0, 'x'));
325 addUI(new PopperUpper(ALL,ALL,0,0,0.25,0.25, BUTTONBAR));
326 addUI(stateButton = new Button(ALL,ALL,0.05,0.025,IconSize, 0, 0, true, false));
328 addUI(new PopperUpper(ALL,BUTTONBAR,x=0.25,y=0,1.375,0.25, BUTTONBAR));
329 x += 0.1; y += 0.025;
330 addUI(new Button(PLAYING|PAUSED,BUTTONBAR,x,y,IconSize, SkipBack, '['));
331 addUI(new Button(PAUSED|STOPPED|OPEN,BUTTONBAR,x += IconSize,y,IconSize, Play, 'p'));
332 addUI(new Button(PLAYING,BUTTONBAR,x,y,IconSize, Pause, 'p'));
333 addUI(new Button(PLAYING|PAUSED|OPEN,BUTTONBAR,x += IconSize,y,IconSize, Stop, 's'));
334 addUI(new Button(PLAYING|PAUSED,BUTTONBAR,x += IconSize,y,IconSize, SkipFwd, ']'));
335 addUI(new Button(PLAYING|PAUSED|STOPPED|NOCD, BUTTONBAR,
336 x += IconSize,y,IconSize, Open, 'e'));
337 addUI(new Button(ALL, BUTTONBAR,x += IconSize,y,IconSize, Exit, 'q'));
339 addUI(new PopperUpper(PLAYING|PAUSED|STOPPED, ALL,0,0.25,0.25,0.25, TRACKBAR));
340 addUI(new PopperUpper(PLAYING|PAUSED|STOPPED, TRACKBAR,x=0.25,y=0.25,1.0,0.625, TRACKBAR));
341 x += 0.1; y += 0.1;
342 addUI(trackSelector = new TrackSelector(PLAYING|PAUSED|STOPPED, TRACKBAR,x,y,0.75,0.25));
343 addUI(new SliderBar(PLAYING|PAUSED, TRACKBAR,x,y+=0.25,0.75,0.25,
344 &trackProgress,setTrackProgress,'{','}'));
346 addUI(new PopperUpper(ALL,ALL,0,0.5,0.25,0.25, DIALBAR));
347 addUI(new Button(ALL,ALL,0.05,0.525,IconSize, Bulb, 0, true, false));
349 addUI(new PopperUpper(ALL,DIALBAR,x=0.25,y=0.0,1.25,1.0, DIALBAR));
350 x += 0.05; y += 0.025;
352 addUI(starsButton = new Button(ALL,DIALBAR,x,y,IconSize, Stars, 'd'));
353 addUI(waveButton = new Button(ALL,DIALBAR,x+IconSize,y,IconSize, Wave, 'f'));
354 addUI(flameButton = new Button(ALL,DIALBAR,x+IconSize*2.5,y,IconSize, Flame, 'g'));
356 addUI(starButton = new Button(ALL,DIALBAR,x+IconSize*3.5,y,IconSize, Star, 'h'));
357 addUI(diamondButton = new Button(ALL,DIALBAR,x+IconSize*4.5,y,IconSize, Diamond, 'j'));
359 addUI(new Button(ALL,DIALBAR,x+0.4,y+0.8,IconSize, Save, '?'));
360 addUI(new Button(ALL,DIALBAR,x+0.65,y+0.8,IconSize, Reset, '/'));
362 y += IconSize*1.3;
364 addUI(new Button(ALL,DIALBAR,x,y-0.05,IconSize, Bulb, 0, true));
365 addUI(new SliderBar(ALL,DIALBAR,
366 x+IconSize,y, 0.75, SliderSize, &brightnessTwiddler, 0, 'z', 'x'));
368 addUI(new Button(ALL,DIALBAR,x,y+SliderSize*1,IconSize, Size, 'x', true));
369 addUI(new SliderBar(ALL,DIALBAR,
370 x+IconSize,y+SliderSize, 0.75, SliderSize, &starSize, setStarSize, 'c','v'));
372 addUI(new Button(ALL,DIALBAR,x+0.5,y+SliderSize*2-0.025,IconSize, FgColor, 0, true));
373 addUI(new SliderBar(ALL,DIALBAR,
374 x,y+SliderSize*2, 0.45, SliderSize, &fgRedSlider, setupPalette, 'b','n'));
375 addUI(new SliderBar(ALL,DIALBAR,
376 x+0.5+SliderSize,y+SliderSize*2, 0.45, SliderSize, &fgGreenSlider, setupPalette, 'm',','));
379 addUI(new Button(ALL,DIALBAR,x+0.5,y+SliderSize*3,IconSize, BgColor, 0, true));
380 addUI(new SliderBar(ALL,DIALBAR,
381 x,y+SliderSize*3, 0.45, SliderSize, &bgRedSlider, setupPalette, 'B','N'));
382 addUI(new SliderBar(ALL,DIALBAR,
383 x+0.5+SliderSize,y+SliderSize*3, 0.45, SliderSize, &bgGreenSlider, setupPalette, 'M','<'));
385 addUI(new PopperUpper(ALL,ALL,0,0.75,0.25,0.25, VOLUMEBAR));
386 addUI(new Button(ALL,ALL,0.05,0.775,IconSize, Speaker, 0, true, false));
388 addUI(new PopperUpper(ALL,VOLUMEBAR,x=0.25,y=0.75,1.0,0.25, VOLUMEBAR));
389 x += 0.1;// y += 0.0625;
390 addUI(new SliderBar(ALL,VOLUMEBAR,x,y, 0.75, 0.25, &volume, setVolume, '-','+'));
391 //static double value = 0.5;
392 //addUI(new SliderBar(ALL,0,0.75,1.0,0.25,&value));
394 //addUI(new Button(BUTTONBAR,x,y,IconSize, 1, 'x'));
395 //addUI(new Button(BUTTONBAR,x += IconSize,y,IconSize, 2, 'x'));
396 //addUI(new Button(BUTTONBAR,x += IconSize,y,IconSize, 3, 'x'));
398 visibleMask = ALL;
399 cdCheckCountDown = 0;
400 mouseX = -1;
401 mouseY = -1;
402 lastY = -1;
403 lastY = -1;
404 countDown = 0;
405 mouseButtons = 0;
407 interfaceSyncToState();
410 void interfaceSyncToState() {
411 starsButton->bright = (fadeMode == Stars);
412 flameButton->bright = (fadeMode == Flame);
413 waveButton->bright = (fadeMode == Wave);
415 starButton->bright = !pointsAreDiamonds;
416 diamondButton->bright = pointsAreDiamonds;
418 setupPalette();
421 int changeState(int transitionSymbol) {
422 if (transitionSymbol < 0) {
423 cdPlay(cdGetTrackFrame(-transitionSymbol));
424 return 0;
427 int retVal = 0;
428 switch(transitionSymbol) {
429 case Play :
430 if (state == Open) {
431 cdCloseTray();
432 state = NoCD;
433 cdGetStatus(track, frames, state);
435 if (state == Pause) cdResume(); else cdPlay(cdGetTrackFrame(1));
436 break;
437 case Pause :
438 cdPause(); break;
439 case Stop :
440 if (state == Open) {
441 cdCloseTray();
442 state = NoCD;
444 cdStop();
445 break;
446 case Open :
447 cdEject();
448 state = Open;
449 break;
450 case SkipBack :
451 cdPlay(cdGetTrackFrame(track-1));
452 break;
453 case SkipFwd :
454 cdPlay(cdGetTrackFrame(track+1));
455 break;
457 case Flame :
458 starsButton->bright = false;
459 flameButton->bright = true;
460 waveButton->bright = false;
461 fadeMode = Flame;
462 setStarSize(starSize);
463 break;
464 case Wave :
465 starsButton->bright = false;
466 flameButton->bright = false;
467 waveButton->bright = true;
468 fadeMode = Wave;
469 setStarSize(starSize);
470 break;
471 case Stars :
472 starsButton->bright = true;
473 flameButton->bright = false;
474 waveButton->bright = false;
475 fadeMode = Stars;
476 setStarSize(starSize);
477 break;
479 case Star :
480 pointsAreDiamonds = false;
481 starButton->bright = true;
482 diamondButton->bright = false;
483 break;
484 case Diamond :
485 pointsAreDiamonds = true;
486 starButton->bright = false;
487 diamondButton->bright = true;
488 break;
490 case Save :
491 saveConfig();
492 break;
493 case Reset :
494 setStateToDefaults();
495 interfaceSyncToState();
496 setStarSize(starSize);
497 break;
499 case Exit :
500 retVal = 1; break;
502 return retVal;
505 bool interfaceGo() {
506 int newVisibleMask = ALL;
507 char keyHit;
508 bool quit = false;
509 int action = NotASymbol;
510 int oldButtons = mouseButtons;
512 screen->inputUpdate(mouseX,mouseY,mouseButtons,keyHit); //may also resize output
514 bool mouseClick = (mouseButtons && !oldButtons);
516 if ((mouseX != lastX || mouseY != lastY) &&
517 lastX > 0 && lastY > 0 &&
518 lastX < outWidth && lastY < outHeight)
519 countDown = 40;
521 int activeMask = ALL;
522 switch(state) {
523 case Play : activeMask |= PLAYING; break;
524 case Pause : activeMask |= PAUSED; break;
525 case Stop : activeMask |= STOPPED; break;
526 case NoCD : activeMask |= NOCD; break;
527 case Open : activeMask |= OPEN; break;
528 default : break;
531 if (countDown) {
532 countDown--;
534 double scale =
535 (outWidth*0.625 < outHeight ? outWidth*0.625 : outHeight);
536 double scaledX = mouseX / scale;
537 double scaledY = mouseY / scale;
539 char hotKey = 0;
541 polygonEngine.clear();
543 stateButton->icon = state;
546 for(UIObject *i=uiObjects;i;i = i->next) {
547 if ((i->visibleMask & visibleMask) && (i->activeMask & activeMask))
548 newVisibleMask |= i->go(mouseButtons,mouseClick,
549 (scaledX >= i->x &&
550 scaledY >= i->y &&
551 scaledX < i->x+i->width &&
552 scaledY < i->y+i->height),
553 scaledX - i->x,
554 scaledY - i->y,
555 scale,
556 hotKey,
557 action);
560 if (activeMask & (PLAYING|PAUSED|STOPPED)) {
561 int trackNumber = (activeMask&(PLAYING|PAUSED) ? track : -1);
562 unsigned short trackColor = 0x0100;
563 if ((visibleMask&TRACKBAR) && trackSelector->position != -1) {
564 trackNumber = trackSelector->position;
565 trackColor = 0x0003;
568 if (trackNumber != -1) {
569 if (trackNumber > 9)
570 polygonEngine.icon(Icons[Zero+trackNumber/10%10],trackColor,
571 scale*0.03125,scale*0.25,scale*0.25,scale*0.25);
573 polygonEngine.icon(Icons[Zero+trackNumber%10],trackColor,
574 scale*0.125,scale*0.25,scale*0.25,scale*0.25);
578 visibleMask = newVisibleMask;
579 if (visibleMask != 1)
580 countDown = 20;
582 polygonEngine.icon(Icons[Pointer],0x0303,mouseX,mouseY,50,50);
584 polygonEngine.apply(outputBmp.data);
586 char hint[2] = " ";
587 hint[0] = hotKey;
588 putString(hint,mouseX+6,mouseY+7,0,0);
591 if (keyHit)
592 for(UIObject *i=uiObjects;i;i = i->next)
593 if (i->activeMask & activeMask)
594 i->handleKey(keyHit,action);
597 lastX = mouseX;
598 lastY = mouseY;
600 if (action != NotASymbol)
601 quit = quit || changeState(action);
603 if (state != Plug && (action != NotASymbol || cdCheckCountDown < 0)) {
604 SymbolID oldState = state;
605 cdGetStatus(track, frames, state);
606 if (action == NotASymbol &&
607 (oldState == Play || oldState == Open || oldState == NoCD) &&
608 state == Stop) {
609 if (playListLength == 0)
610 cdPlay(cdGetTrackFrame(1));
611 else {
612 int track = atoi(playList[playListPosition]);
613 playListPosition = (playListPosition+1) % playListLength;
614 cdPlay(cdGetTrackFrame(track),cdGetTrackFrame(track+1));
618 int interval = cdGetTrackFrame(track+1)-cdGetTrackFrame(track);
619 if (interval > 0)
620 trackProgress = double(frames)/interval;
621 else
622 trackProgress = 0.0;
624 cdCheckCountDown = 100;
625 } else
626 cdCheckCountDown -= (countDown ? 10 : 1);
628 if (mouseClick && action == NotASymbol && !(visibleMask&~ALL)) {
629 screen->toggleFullScreen();
630 screen->inputUpdate(mouseX,mouseY,mouseButtons,keyHit);
631 lastX = mouseX;
632 lastY = mouseY;
635 return quit;
638 void interfaceEnd() {
639 while(uiObjects) {
640 UIObject *next = uiObjects->next;
641 delete uiObjects;
642 uiObjects = next;