brewpanel/sdlgui.c

changeset 409
cdf68044adaf
child 410
e3f8a51b566a
equal deleted inserted replaced
408:ec507c1f1df7 409:cdf68044adaf
1 /*****************************************************************************
2 * Copyright (C) 2015
3 *
4 * Michiel Broek <mbroek at mbse dot eu>
5 *
6 * This file is part of the mbsePi-apps emulator
7 *
8 * The gui code is based on the gui from the emulator ARAnyM,
9 * Copyright (c) 2004 Petr Stehlik of ARAnyM dev team
10 *
11 * This progrm is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2, or (at your option) any
14 * later version.
15 *
16 * mbsePi-apps is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with mbsePi-apps; see the file COPYING. If not, write to the Free
23 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 *****************************************************************************/
25
26 #include "brewpanel.h"
27 #include "sdlgui.h"
28 #include "lcdfont10x16.h"
29
30
31 static SDL_Surface *pSdlGuiScrn; /* Pointer to the actual main SDL screen surface */
32 static SDL_Surface *pFontGfx = NULL; /* The LCD font graphics */
33 static int fontwidth, fontheight; /* Width & height of the actual font */
34 TTF_Font *pFont = NULL; /* TTF font for buttons etc. */
35
36 extern int my_shutdown;
37
38
39 /*-----------------------------------------------------------------------*/
40 /*
41 * Load an 1 plane XBM into a 8 planes SDL_Surface.
42 */
43 static SDL_Surface *SDLGui_LoadXBM(int w, int h, const char *pXbmBits)
44 {
45 SDL_Surface *bitmap;
46 Uint8 *dstbits;
47 const Uint8 *srcbits;
48 int x, y, srcpitch, mask;
49
50 srcbits = (Uint8 *)pXbmBits;
51
52 /* Allocate the bitmap */
53 if ((bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0)) == NULL) {
54 syslog(LOG_NOTICE, "Failed to allocate bitmap: %s", SDL_GetError());
55 return NULL;
56 }
57
58 srcpitch = ((w + 7) / 8);
59 dstbits = (Uint8 *)bitmap->pixels;
60 mask = 1;
61
62 /* Copy the pixels */
63 for (y = 0 ; y < h ; y++) {
64 for (x = 0 ; x < w ; x++) {
65 dstbits[x] = (srcbits[x / 8] & mask) ? 1 : 0;
66 mask <<= 1;
67 mask |= (mask >> 8);
68 mask &= 0xFF;
69 }
70 dstbits += bitmap->pitch;
71 srcbits += srcpitch;
72 }
73
74 return bitmap;
75 }
76
77
78
79 /*
80 * Initialize the GUI.
81 */
82 int SDLGui_Init(void)
83 {
84 char *Pt = NULL;
85
86 SDL_Color blackWhiteColors[2] = {{255, 255, 255, 0}, {0, 0, 0, 0}};
87
88 /*
89 * Initialize the LCD font graphics:
90 */
91 pFontGfx = SDLGui_LoadXBM(lcdfont10x16_width, lcdfont10x16_height, lcdfont10x16_bits);
92 if (pFontGfx == NULL) {
93 syslog(LOG_NOTICE, "Error: Can not init font graphics!");
94 return -1;
95 }
96
97 /* Set color palette of the LCD font graphics: */
98 SDL_SetColors(pFontGfx, blackWhiteColors, 0, 2);
99
100 /* Set font color 0 as transparent: */
101 SDL_SetColorKey(pFontGfx, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);
102
103 if (TTF_Init() == -1) {
104 syslog(LOG_NOTICE, "Could not init SDL_ttf");
105 return -1;
106 }
107
108 /*
109 * Load TTF font for the dialogs
110 */
111 Pt = calloc(1024, sizeof(char));
112 sprintf(Pt, "%s", "/usr/share/fonts/TTF/DejaVuSans.ttf");
113 if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
114 sprintf(Pt, "%s", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
115 if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
116 sprintf(Pt, "%s", "/usr/share/fonts/truetype/freefont/DejaVuSans.ttf");
117 if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
118 syslog(LOG_NOTICE, "Could not load DejaVuSans.ttf");
119 return -1;
120 }
121 }
122 }
123 syslog(LOG_NOTICE, "Using ttf font: %s\n", Pt);
124 free(Pt);
125 Pt = NULL;
126
127 return 0;
128 }
129
130
131
132 /*
133 * Uninitialize the GUI.
134 */
135 int SDLGui_UnInit(void)
136 {
137 if (pFont)
138 TTF_CloseFont(pFont);
139 pFont = NULL;
140
141 if (pFontGfx)
142 SDL_FreeSurface(pFontGfx);
143 pFontGfx = NULL;
144
145 return 0;
146 }
147
148
149
150 /*
151 * Inform the SDL-GUI about the actual SDL_Surface screen pointer and
152 * prepare the font to suit the actual resolution.
153 */
154 int SDLGui_SetScreen(SDL_Surface *pScrn)
155 {
156 pSdlGuiScrn = pScrn;
157
158 if (pFontGfx == NULL) {
159 syslog(LOG_NOTICE, "Error: A problem with the font occured!");
160 return -1;
161 }
162
163 /* Get the font width and height: */
164 fontwidth = pFontGfx->w/16;
165 fontheight = pFontGfx->h/16;
166
167 return 0;
168 }
169
170
171
172 /*
173 * Center a dialog so that it appears in the middle of the screen.
174 * Note: We only store the coordinates in the root box of the dialog,
175 * all other objects in the dialog are positioned relatively to this one.
176 */
177 void SDLGui_CenterDlg(SGOBJ *dlg)
178 {
179 dlg[0].x = (pSdlGuiScrn->w/1-dlg[0].w)/2;
180 dlg[0].y = (pSdlGuiScrn->h/1-dlg[0].h)/2;
181 }
182
183
184
185 /*
186 * Draw a text string using TTF
187 */
188 static void SDLGui_TTF(int x, int y, const char *txt)
189 {
190 SDL_Rect offset;
191 SDL_Color textColor = { 0, 0, 0 };
192 SDL_Surface* message = NULL;
193
194 message = TTF_RenderText_Solid(pFont, txt, textColor);
195 offset.x = x;
196 offset.y = y;
197 SDL_BlitSurface(message, NULL, pSdlGuiScrn, &offset);
198 SDL_FreeSurface(message);
199 message = NULL;
200 }
201
202
203
204 /*
205 * Draw a dialog TTF text object.
206 */
207 static void SDLGui_DrawTTF(const SGOBJ *tdlg, int objnum)
208 {
209 int x, y;
210
211 x = (tdlg[0].x + tdlg[objnum].x);
212 y = (tdlg[0].y + tdlg[objnum].y);
213 SDLGui_TTF(x, y, tdlg[objnum].txt);
214 }
215
216
217
218 /*
219 * Draw a text string.
220 */
221 static void SDLGui_Text(int x, int y, const char *txt)
222 {
223 int i;
224 char c;
225 SDL_Rect sr, dr;
226
227 for (i=0; txt[i]!=0; i++) {
228 c = txt[i];
229 sr.x=fontwidth*(c%16);
230 sr.y=fontheight*(c/16);
231 sr.w=fontwidth;
232 sr.h=fontheight;
233 dr.x=x+i*(fontwidth+2);
234 dr.y=y;
235 dr.w=fontwidth;
236 dr.h=fontheight;
237 SDL_BlitSurface(pFontGfx, &sr, pSdlGuiScrn, &dr);
238 }
239 }
240
241
242
243 /*
244 * Draw a dialog text object.
245 */
246 static void SDLGui_DrawText(const SGOBJ *tdlg, int objnum)
247 {
248 int x, y;
249
250 x = (tdlg[0].x + tdlg[objnum].x);
251 y = (tdlg[0].y + tdlg[objnum].y);
252 SDLGui_Text(x, y, tdlg[objnum].txt);
253 }
254
255
256
257 /*
258 * Draw a dialog LCD object.
259 */
260 static void SDLGui_DrawLCD(const SGOBJ *bdlg, int objnum)
261 {
262 SDL_Rect rect;
263 int x, y, w, h, offset, border = 4;
264 Uint32 bg0 = SDL_MapRGB(pSdlGuiScrn->format, 94,147, 69);
265 Uint32 bg1 = SDL_MapRGB(pSdlGuiScrn->format,156,235, 4);
266 Uint32 bc = SDL_MapRGB(pSdlGuiScrn->format, 32, 32, 32);
267 Uint32 bg;
268
269 /*
270 * Width and height are given in character columns and rows,
271 * so calculate the display size in pixels.
272 */
273 w = bdlg[objnum].w * (fontwidth + 2) + 10;
274 h = bdlg[objnum].h * (fontheight + 2) + 4;
275
276 if (bdlg[objnum].x == -1) {
277 /*
278 * Auto center
279 */
280 x = (bdlg[0].w - w) / 2;
281 } else {
282 x = bdlg[objnum].x;
283 }
284 y = bdlg[objnum].y;
285 if (objnum > 0) { /* Since the root object is a box, too, */
286 /* we have to look for it now here and only */
287 x += bdlg[0].x; /* add its absolute coordinates if we need to */
288 y += bdlg[0].y;
289 }
290
291 if (bdlg[objnum].state & SG_SELECTED) {
292 bg = bg1;
293 } else {
294 bg = bg0;
295 }
296
297 /* The root box should be bigger than the screen, so we disable the offset there: */
298 if (objnum != 0)
299 offset = border;
300 else
301 offset = 0;
302
303 /* Draw background: */
304 rect.x = x;
305 rect.y = y;
306 rect.w = w;
307 rect.h = h;
308 SDL_FillRect(pSdlGuiScrn, &rect, bg);
309
310 /* Draw upper border: */
311 rect.x = x - offset;
312 rect.y = y - offset;
313 rect.w = w + offset + offset;
314 rect.h = border;
315 SDL_FillRect(pSdlGuiScrn, &rect, bc);
316
317 /* Draw left border: */
318 rect.x = x - offset;
319 rect.y = y;
320 rect.w = border;
321 rect.h = h;
322 SDL_FillRect(pSdlGuiScrn, &rect, bc);
323
324 /* Draw bottom border: */
325 rect.x = x - offset;
326 rect.y = y + h - border + offset;
327 rect.w = w + offset + offset;
328 rect.h = border;
329 SDL_FillRect(pSdlGuiScrn, &rect, bc);
330
331 /* Draw right border: */
332 rect.x = x + w - border + offset;
333 rect.y = y;
334 rect.w = border;
335 rect.h = h;
336 SDL_FillRect(pSdlGuiScrn, &rect, bc);
337 }
338
339
340
341 /*
342 * Draw a dialog box object.
343 */
344 static void SDLGui_DrawBox(const SGOBJ *bdlg, int objnum)
345 {
346 SDL_Rect rect;
347 int x, y, w, h, offset, shade = 2;
348 Uint32 grey = SDL_MapRGB(pSdlGuiScrn->format,192,192,192);
349 Uint32 upleftc, downrightc;
350
351 x = bdlg[objnum].x;
352 y = bdlg[objnum].y;
353 if (objnum > 0) { /* Since the root object is a box, too, */
354 /* we have to look for it now here and only */
355 x += bdlg[0].x; /* add its absolute coordinates if we need to */
356 y += bdlg[0].y;
357 }
358 w = bdlg[objnum].w;
359 h = bdlg[objnum].h;
360
361 if (bdlg[objnum].state & SG_SELECTED) {
362 upleftc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
363 downrightc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
364 } else {
365 upleftc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
366 downrightc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
367 }
368
369 /* The root box should be bigger than the screen, so we disable the offset there: */
370 if (objnum != 0)
371 offset = shade;
372 else
373 offset = 0;
374
375 /* Draw background: */
376 rect.x = x;
377 rect.y = y;
378 rect.w = w;
379 rect.h = h;
380 SDL_FillRect(pSdlGuiScrn, &rect, grey);
381
382 /* Draw upper border: */
383 rect.x = x;
384 rect.y = y - offset;
385 rect.w = w;
386 rect.h = shade;
387 SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
388
389 /* Draw left border: */
390 rect.x = x - offset;
391 rect.y = y;
392 rect.w = shade;
393 rect.h = h;
394 SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
395
396 /* Draw bottom border: */
397 rect.x = x;
398 rect.y = y + h - shade + offset;
399 rect.w = w;
400 rect.h = shade;
401 SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
402
403 /* Draw right border: */
404 rect.x = x + w - shade + offset;
405 rect.y = y;
406 rect.w = shade;
407 rect.h = h;
408 SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
409 }
410
411
412
413 /*
414 * Draw a normal button.
415 */
416 static void SDLGui_DrawButton(const SGOBJ *bdlg, int objnum)
417 {
418 int x, y, w, h;
419
420 SDLGui_DrawBox(bdlg, objnum);
421 /*
422 * Use bold text and get outer dimensions of the text
423 */
424 TTF_SetFontStyle(pFont, TTF_STYLE_BOLD);
425 TTF_SizeText(pFont, bdlg[objnum].txt, &w, &h);
426 x = bdlg[0].x + bdlg[objnum].x + (bdlg[objnum].w - w) / 2;
427 y = bdlg[0].y + bdlg[objnum].y + (bdlg[objnum].h - h) / 2;
428
429 if (bdlg[objnum].state & SG_SELECTED) {
430 x += 1;
431 y += 1;
432 }
433
434 if ((bdlg[objnum].flags & SG_HIDE) == 0)
435 SDLGui_TTF(x, y, bdlg[objnum].txt);
436 TTF_SetFontStyle(pFont, TTF_STYLE_NORMAL);
437 }
438
439
440
441 /*
442 * Draw a whole dialog.
443 */
444 void SDLGui_DrawDialog(const SGOBJ *dlg)
445 {
446 int i;
447
448 for (i = 0; dlg[i].type != -1; i++) {
449 switch (dlg[i].type) {
450 case SGBOX:
451 SDLGui_DrawBox(dlg, i);
452 break;
453 case SGLCD:
454 SDLGui_DrawLCD(dlg, i);
455 break;
456 case SGTEXT:
457 SDLGui_DrawText(dlg, i);
458 break;
459 case SGTTF:
460 SDLGui_DrawTTF(dlg, i);
461 break;
462 case SGBUTTON:
463 SDLGui_DrawButton(dlg, i);
464 break;
465 }
466 }
467
468 SDL_UpdateRect(pSdlGuiScrn, 0,0,0,0);
469 }
470
471
472
473 /*
474 * Search an object at a certain position.
475 */
476 static int SDLGui_FindObj(const SGOBJ *dlg, int fx, int fy)
477 {
478 int len, i, ob = -1, xpos, ypos;
479
480 len = 0;
481 while (dlg[len].type != -1)
482 len++;
483
484 xpos = fx;
485 ypos = fy;
486 /* Now search for the object: */
487 for (i = len; i >= 0; i--) {
488 if (xpos >= dlg[0].x + dlg[i].x && ypos >= dlg[0].y + dlg[i].y &&
489 xpos < dlg[0].x + dlg[i].x + dlg[i].w && ypos < dlg[0].y + dlg[i].y + dlg[i].h) {
490 ob = i;
491 break;
492 }
493 }
494
495 return ob;
496 }
497
498
499
500 /*
501 * Search a button with a special flag (e.g. SG_DEFAULT or SG_CANCEL).
502 */
503 static int SDLGui_SearchFlaggedButton(const SGOBJ *dlg, int flag)
504 {
505 int i = 0;
506
507 while (dlg[i].type != -1) {
508 if (dlg[i].flags & flag)
509 return i;
510 i++;
511 }
512
513 return 0;
514 }
515
516
517
518 /*
519 * Show and process a dialog. Returns the button number that has been
520 * pressed or SDLGUI_UNKNOWNEVENT if an unsupported event occured (will be
521 * stored in parameter pEventOut).
522 */
523 int SDLGui_DoDialog(SGOBJ *dlg, SDL_Event *pEventOut)
524 {
525 int obj = 0, oldbutton = 0, retbutton = 0, i, j, b;
526 SDL_Event sdlEvent;
527 SDL_Surface *pBgSurface;
528 SDL_Rect dlgrect, bgrect;
529
530 // if (pSdlGuiScrn->h / fontheight < dlg[0].h)
531 // {
532 // syslog(LOG_NOTICE, "Screen size too small for dialog!");
533 // return SDLGUI_ERROR;
534 // }
535
536 dlgrect.x = dlg[0].x;
537 dlgrect.y = dlg[0].y;
538 dlgrect.w = dlg[0].w;
539 dlgrect.h = dlg[0].h;
540
541 bgrect.x = bgrect.y = 0;
542 bgrect.w = dlgrect.w;
543 bgrect.h = dlgrect.h;
544
545 /*
546 * Save background
547 */
548 pBgSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, dlgrect.w, dlgrect.h, pSdlGuiScrn->format->BitsPerPixel,
549 pSdlGuiScrn->format->Rmask, pSdlGuiScrn->format->Gmask, pSdlGuiScrn->format->Bmask, pSdlGuiScrn->format->Amask);
550 if (pSdlGuiScrn->format->palette != NULL) {
551 SDL_SetColors(pBgSurface, pSdlGuiScrn->format->palette->colors, 0, pSdlGuiScrn->format->palette->ncolors-1);
552 }
553
554 if (pBgSurface != NULL) {
555 SDL_BlitSurface(pSdlGuiScrn, &dlgrect, pBgSurface, &bgrect);
556 } else {
557 syslog(LOG_NOTICE, "SDLGUI_DoDialog: CreateRGBSurface failed: %s", SDL_GetError());
558 }
559
560 /* (Re-)draw the dialog */
561 SDLGui_DrawDialog(dlg);
562
563 /*
564 * Is the left mouse button still pressed? Yes -> Handle TOUCHEXIT objects here
565 */
566 SDL_PumpEvents();
567 b = SDL_GetMouseState(&i, &j);
568 obj = SDLGui_FindObj(dlg, i, j);
569 if (obj > 0 && (dlg[obj].flags & SG_TOUCHEXIT) ) {
570 oldbutton = obj;
571 if (b & SDL_BUTTON(1)) {
572 dlg[obj].state |= SG_SELECTED;
573 retbutton = obj;
574 }
575 }
576
577 /* The main loop */
578 while (retbutton == 0 && !my_shutdown) {
579 if (SDL_WaitEvent(&sdlEvent) == 1) /* Wait for events */
580 switch (sdlEvent.type) {
581 case SDL_QUIT:
582 retbutton = SDLGUI_QUIT;
583 break;
584
585 case SDL_MOUSEBUTTONDOWN:
586 if (sdlEvent.button.button != SDL_BUTTON_LEFT) {
587 /* Not left mouse button -> unsupported event */
588 if (pEventOut)
589 retbutton = SDLGUI_UNKNOWNEVENT;
590 break;
591 }
592 /* It was the left button: Find the object under the mouse cursor */
593 obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
594 if (obj > 0) {
595 if (dlg[obj].type == SGBUTTON) {
596 dlg[obj].state |= SG_SELECTED;
597 SDLGui_DrawButton(dlg, obj);
598 SDL_UpdateRect(pSdlGuiScrn, dlg[0].x + dlg[obj].x - 2, dlg[0].y + dlg[obj].y - 2, dlg[obj].w + 4, dlg[obj].h + 4);
599 oldbutton=obj;
600 }
601 if ( dlg[obj].flags & SG_TOUCHEXIT ) {
602 dlg[obj].state |= SG_SELECTED;
603 retbutton = obj;
604 }
605 }
606 break;
607
608 case SDL_MOUSEBUTTONUP:
609 if (sdlEvent.button.button != SDL_BUTTON_LEFT) {
610 /* Not left mouse button -> unsupported event */
611 if (pEventOut)
612 retbutton = SDLGUI_UNKNOWNEVENT;
613 break;
614 }
615 /* It was the left button: Find the object under the mouse cursor */
616 obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
617 if (obj > 0) {
618 switch (dlg[obj].type) {
619 case SGBUTTON:
620 if (oldbutton==obj)
621 retbutton=obj;
622 break;
623 }
624 }
625 if (oldbutton > 0) {
626 dlg[oldbutton].state &= ~SG_SELECTED;
627 SDLGui_DrawButton(dlg, oldbutton);
628 SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[oldbutton].x)*fontwidth-2, (dlg[0].y+dlg[oldbutton].y)*fontheight-2,
629 dlg[oldbutton].w*fontwidth+4, dlg[oldbutton].h*fontheight+4);
630 oldbutton = 0;
631 }
632 if (obj >= 0 && (dlg[obj].flags & SG_EXIT)) {
633 retbutton = obj;
634 }
635 break;
636
637 case SDL_MOUSEMOTION:
638 break;
639
640 case SDL_KEYDOWN: /* Key pressed */
641 if (sdlEvent.key.keysym.sym == SDLK_RETURN || sdlEvent.key.keysym.sym == SDLK_KP_ENTER) {
642 retbutton = SDLGui_SearchFlaggedButton(dlg, SG_DEFAULT);
643 } else if (sdlEvent.key.keysym.sym == SDLK_ESCAPE) {
644 retbutton = SDLGui_SearchFlaggedButton(dlg, SG_CANCEL);
645 } else if (pEventOut) {
646 retbutton = SDLGUI_UNKNOWNEVENT;
647 }
648 break;
649
650 default:
651 if (pEventOut)
652 retbutton = SDLGUI_UNKNOWNEVENT;
653 break;
654 }
655 }
656
657 /* Restore background */
658 if (pBgSurface) {
659 SDL_BlitSurface(pBgSurface, &bgrect, pSdlGuiScrn, &dlgrect);
660 SDL_FreeSurface(pBgSurface);
661 }
662
663 /* Copy event data of unsupported events if caller wants to have it */
664 if (retbutton == SDLGUI_UNKNOWNEVENT && pEventOut)
665 memcpy(pEventOut, &sdlEvent, sizeof(SDL_Event));
666
667 if (retbutton == SDLGUI_QUIT)
668 my_shutdown = TRUE;
669
670 return retbutton;
671 }
672
673
674
675 void SDLGui_LCDwrite(SGOBJ *dlg, int x, int y, Uint8 c, int lcdindex)
676 {
677 int i, index;
678
679 fprintf(stdout, "SDLGui_LCDwrite( , %d, %d, %c, %d)\n", x, y, c, lcdindex);
680
681 i = index = 0;
682 for (;;) {
683 if (dlg[i].type == -1) {
684 syslog(LOG_NOTICE, "SDLGui_LCDwrite() lcdindex=%d not found", lcdindex);
685 return;
686 }
687 if (dlg[i].type == SGLCD) {
688 if (index == lcdindex)
689 break;
690 index++;
691 }
692 i++;
693 }
694 fprintf(stdout, "SDLGui_LCDwrite i=%d LCD=%dx%d\n", i, dlg[i].w, dlg[i].h);
695
696 }
697
698

mercurial