Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/modules/GUI/gui.c

1/*
2 * gui.c
3 *
4 *
5 * Created by Jasmin Fazlic on 18.12.08.
6 * Copyright 2008/09 Jasmin Fazlic All rights reserved.
7 * Copyright 2008/09 iNDi All rights reserved.
8 *
9 */
10
11/*
12 * cparm : cleaned
13 */
14
15/*
16 * cparm : add volume version detection
17 */
18#include "platform.h"
19#include "gui.h"
20#include "GUI_appleboot.h"
21#include "vers.h"
22#include "modules.h"
23#include "sl.h"
24
25#ifndef DEBUG_GUI
26#define DEBUG_GUI 0
27#endif
28
29#if DEBUG_GUI==2
30#define DBG(x...)printf(x);sleep(2)
31#elif DEBUG_GUI==1
32#define DBG(x...)printf(x)
33#else
34#define DBG(x...)
35#endif
36
37enum {
38kBackspaceKey= 0x08,
39kTabKey= 0x09,
40kReturnKey= 0x0d,
41kEscapeKey= 0x1b,
42kUpArrowkey= 0x4800,
43kDownArrowkey= 0x5000,
44kASCIIKeyMask= 0x7f,
45kF5Key= 0x3f00,
46kF10Key= 0x4400
47};
48
49static config_file_t themeConfig; // theme.plist
50
51themeList_t* themeList = NULL;
52
53static void (*showHelp)(void) = NULL;
54static char *(*getMemoryInfoString)(void) = NULL;
55
56
57gui_t gui;// gui structure
58font_t font_small;
59font_t font_console;
60
61
62#define IMG_REQUIRED -1
63#define THEME_NAME_DEFAULT"Default"
64const char* theme_name = THEME_NAME_DEFAULT;
65
66char dirsrc[22];
67
68#ifdef EMBED_THEME
69#include "art.h"
70#endif
71
72struct putc_info {
73 char * str;
74 char * last_str;
75};
76
77static int loadThemeImage(char *src, const char *image, int alt_image);
78static void loadBootGraphics(char *src);
79static void drawInfoMenuItems();
80static void drawProgressBar(pixmap_t *blendInto, uint16_t width, position_t p, uint8_t progress);
81static void animateProgressBar();
82static void makeRoundedCorners(pixmap_t *p);
83static void colorFont(font_t *font, uint32_t color);
84static int initFont(font_t *font, image_t *data);
85static void drawStrCenteredAt(char *text, font_t *font, pixmap_t *blendInto, position_t p);
86static position_t drawChar(unsigned char ch, font_t *font, pixmap_t *blendInto, position_t p);
87static void drawStr(char *ch, font_t *font, pixmap_t *blendInto, position_t p);
88#if DEBUG_GUI
89static int dprintf( window_t * window, const char * fmt, ...);
90#endif
91static void sputc(int c, struct putc_info * pi);
92
93static inline
94void vramwrite (void *data, int width);
95
96static void drawDeviceIcon(BVRef device, pixmap_t *buffer, position_t p, bool isSelected);
97static int startGUI(void);
98static void free_theme_list();
99static void add_theme(const char* theme, uint8_t nb);
100static int randomTheme(char *dirspec, const char **theme);
101static void loadThemeValues(config_file_t *theme);
102static void setupDeviceList(config_file_t *theme);
103static void fillPixmapWithColor(pixmap_t *pm, uint32_t color);
104static int freeWindowBuffer( window_t *window );
105static int createWindowBuffer( window_t *window );
106static int createBackBuffer( window_t *window );
107static int loadGraphics(char *src);
108#ifdef EMBED_THEME
109static int getEmbeddedImageIndexByName(const char *name);
110#endif
111static int getImageIndexByName(const char *name);
112
113static int destroyFont(font_t *font);
114static int unloadGraphics(void);
115static int freeBackBuffer( window_t *window );
116static bool is_image_loaded(int i);
117
118#define LOADPNG(src, img, alt_img) if (loadThemeImage(src, #img, alt_img) != 0) { return 1; }
119
120#ifndef MIN
121#define MIN(x, y) ((x) < (y) ? (x) : (y))
122#endif
123
124#ifndef MAX
125#define MAX(x, y) ((x) > (y) ? (x) : (y))
126#endif
127
128#define VIDEO(x) (((boot_args_common*)getBootArgs())->Video.v_ ## x)
129
130#define vram VIDEO(baseAddr)
131
132#define TAB_PIXELS_WIDTH (font->chars[0]->width * 4) // tab = 4 spaces
133
134int lasttime = 0; // we need this for animating maybe
135
136/*
137 * ATTENTION: the enum and the following array images[] MUST match !!!
138 */
139enum {
140 iBackground = 0,
141 iLogo,
142
143 iDeviceGeneric,
144 iDeviceGeneric_o,
145 iDeviceHFS,
146 iDeviceHFS_o,
147 iDeviceHFS_ML,
148 iDeviceHFS_ML_o,
149iDeviceHFS_Lion,
150 iDeviceHFS_Lion_o,
151iDeviceHFS_SL,
152 iDeviceHFS_SL_o,
153iDeviceHFS_Leo,
154 iDeviceHFS_Leo_o,
155iDeviceHFS_Tiger,
156 iDeviceHFS_Tiger_o,
157 iDeviceHFSRAID,
158 iDeviceHFSRAID_o,
159 iDeviceHFSRAID_ML,
160 iDeviceHFSRAID_ML_o,
161iDeviceHFSRAID_Lion,
162 iDeviceHFSRAID_Lion_o,
163iDeviceHFSRAID_SL,
164 iDeviceHFSRAID_SL_o,
165iDeviceHFSRAID_Leo,
166 iDeviceHFSRAID_Leo_o,
167iDeviceHFSRAID_Tiger,
168 iDeviceHFSRAID_Tiger_o,
169 iDeviceEXT3,
170 iDeviceEXT3_o,
171iDeviceFreeBSD,
172 iDeviceFreeBSD_o,
173 iDeviceOpenBSD,
174 iDeviceOpenBSD_o,
175iDeviceBEFS, /* Haiku detection and Icon credits to scorpius */
176iDeviceBEFS_o, /* Haiku detection and Icon credits to scorpius */
177 iDeviceFAT,
178 iDeviceFAT_o,
179 iDeviceFAT16,
180 iDeviceFAT16_o,
181 iDeviceFAT32,
182 iDeviceFAT32_o,
183 iDeviceNTFS,
184 iDeviceNTFS_o,
185 iDeviceCDROM,
186 iDeviceCDROM_o,
187
188 iSelection,
189 iDeviceScrollPrev,
190 iDeviceScrollNext,
191
192 iMenuBoot,
193 iMenuVerbose,
194 iMenuIgnoreCaches,
195 iMenuSingleUser,
196 iMenuMemoryInfo,
197 iMenuVideoInfo,
198 iMenuHelp,
199 iMenuVerboseDisabled,
200 iMenuIgnoreCachesDisabled,
201 iMenuSingleUserDisabled,
202 iMenuSelection,
203
204 iProgressBar,
205 iProgressBarBackground,
206
207 iTextScrollPrev,
208 iTextScrollNext,
209
210 iFontConsole,
211 iFontSmall,
212};
213
214image_t images[] = {
215 {.name = "background", .image = NULL},
216 {.name = "logo", .image = NULL},
217
218 {.name = "device_generic", .image = NULL},
219 {.name = "device_generic_o", .image = NULL},
220
221{.name = "device_hfsplus", .image = NULL},
222 {.name = "device_hfsplus_o", .image = NULL},
223{.name = "device_hfsplus_ml", .image = NULL},
224 {.name = "device_hfsplus_ml_o", .image = NULL},
225{.name = "device_hfsplus_lion", .image = NULL},
226 {.name = "device_hfsplus_lion_o", .image = NULL},
227{.name = "device_hfsplus_sl", .image = NULL},
228 {.name = "device_hfsplus_sl_o", .image = NULL},
229{.name = "device_hfsplus_leo", .image = NULL},
230 {.name = "device_hfsplus_leo_o", .image = NULL},
231{.name = "device_hfsplus_tiger", .image = NULL},
232 {.name = "device_hfsplus_tiger_o", .image = NULL},
233
234 {.name = "device_hfsraid", .image = NULL},
235 {.name = "device_hfsraid_o", .image = NULL},
236 {.name = "device_hfsraid_ml", .image = NULL},
237 {.name = "device_hfsraid_ml_o", .image = NULL},
238{.name = "device_hfsraid_lion", .image = NULL},
239 {.name = "device_hfsraid_lion_o", .image = NULL},
240{.name = "device_hfsraid_sl", .image = NULL},
241 {.name = "device_hfsraid_sl_o", .image = NULL},
242{.name = "device_hfsraid_leo", .image = NULL},
243 {.name = "device_hfsraid_leo_o", .image = NULL},
244{.name = "device_hfsraid_tiger", .image = NULL},
245 {.name = "device_hfsraid_tiger_o", .image = NULL},
246
247 {.name = "device_ext3", .image = NULL},
248 {.name = "device_ext3_o", .image = NULL},
249{.name = "device_freebsd", .image = NULL},
250 {.name = "device_freebsd_o", .image = NULL},
251 {.name = "device_openbsd", .image = NULL},
252 {.name = "device_openbsd_o", .image = NULL},
253{.name = "device_befs", .image = NULL}, /* Haiku detection and Icon credits to scorpius */
254{.name = "device_befs_o", .image = NULL}, /* Haiku detection and Icon credits to scorpius */
255 {.name = "device_fat", .image = NULL},
256 {.name = "device_fat_o", .image = NULL},
257 {.name = "device_fat16", .image = NULL},
258 {.name = "device_fat16_o", .image = NULL},
259 {.name = "device_fat32", .image = NULL},
260 {.name = "device_fat32_o", .image = NULL},
261 {.name = "device_ntfs", .image = NULL},
262 {.name = "device_ntfs_o", .image = NULL},
263 {.name = "device_cdrom", .image = NULL},
264 {.name = "device_cdrom_o", .image = NULL},
265
266 {.name = "device_selection", .image = NULL},
267 {.name = "device_scroll_prev", .image = NULL},
268 {.name = "device_scroll_next", .image = NULL},
269
270 {.name = "menu_boot", .image = NULL},
271 {.name = "menu_verbose", .image = NULL},
272 {.name = "menu_ignore_caches", .image = NULL},
273 {.name = "menu_single_user", .image = NULL},
274 {.name = "menu_memory_info", .image = NULL},
275 {.name = "menu_video_info", .image = NULL},
276 {.name = "menu_help", .image = NULL},
277 {.name = "menu_verbose_disabled", .image = NULL},
278 {.name = "menu_ignore_caches_disabled", .image = NULL},
279 {.name = "menu_single_user_disabled", .image = NULL},
280 {.name = "menu_selection", .image = NULL},
281
282 {.name = "progress_bar", .image = NULL},
283 {.name = "progress_bar_background", .image = NULL},
284
285 {.name = "text_scroll_prev", .image = NULL},
286 {.name = "text_scroll_next", .image = NULL},
287
288 {.name = "font_console", .image = NULL},
289 {.name = "font_small", .image = NULL},
290};
291
292//int imageCnt = 0;
293
294char prompt[BOOT_STRING_LEN];
295
296int prompt_pos=0;
297
298char prompt_text[] = "boot: ";
299
300menuitem_t infoMenuItems[] =
301{
302{ .text = "Boot" },
303{ .text = "Boot Verbose" },
304{ .text = "Boot Ignore Caches" },
305{ .text = "Boot Single User" },
306{ .text = "Memory Info" },
307{ .text = "Video Info" },
308{ .text = "Help" }
309};
310
311int infoMenuSelection = 0;
312int infoMenuItemsCount = sizeof(infoMenuItems)/sizeof(infoMenuItems[0]);
313
314bool infoMenuNativeBoot = false;
315
316unsigned long screen_params[4] = {DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 32, 0};// here we store the used screen resolution
317
318static void moveCursor( int col, int row )
319{
320 setCursorPosition( col, row, 0 );
321}
322
323/*
324 *
325 */
326
327bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
328{
329const char *val;
330
331 int size = 0;
332int sum = 0;
333
334bool negative = false;
335bool percentage = false;
336
337 config = resolveConfig(config);
338
339 if (getValueForKey(key, &val, &size, config))
340{
341if ( size )
342{
343if (*val == '-')
344{
345negative = true;
346val++;
347size--;
348}
349
350if (val[size-1] == '%')
351{
352percentage = true;
353size--;
354}
355
356// convert string to integer
357for (sum = 0; size > 0; size--)
358{
359if (*val < '0' || *val > '9')
360return false;
361
362sum = (sum * 10) + (*val++ - '0');
363}
364
365if (percentage)
366sum = ( dimension_max * sum ) / 100;
367
368// calculate offset from opposite origin
369if (negative)
370sum = ( ( dimension_max - object_size ) - sum );
371
372} else {
373
374// null value calculate center
375sum = ( dimension_max - object_size ) / 2;
376
377}
378
379*value = (uint16_t) sum;
380return true;
381}
382
383// key not found
384 return false;
385}
386
387static bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )
388{
389 const char *val;
390 int size;
391
392 config = resolveConfig(config);
393
394 if (getValueForKey(key, &val, &size, config))
395{
396if (*val == '#')
397{
398 val++;
399*value = strtol(val, NULL, 16);
400return true;
401 }
402 }
403 return false;
404}
405//==========================================================================
406
407/* Flush keyboard buffer; returns TRUE if any of the flushed
408 * characters was F8.
409 */
410
411static bool flushKeyboardBuffer(void)
412{
413 bool status = false;
414
415 while ( readKeyboardStatus() ) {
416 if (bgetc() == 0x4200) status = true;
417 }
418 return status;
419}
420
421static int getImageIndexByName(const char *name)
422{
423 int i;
424for (i = 0; (unsigned)i < sizeof(images) / sizeof(images[0]); i++)
425{
426 if (strcmp(name, images[i].name) == 0)
427 return i; // found the name
428}
429return -1;
430}
431
432#ifdef EMBED_THEME
433static int getEmbeddedImageIndexByName(const char *name)
434{
435int upperLimit = sizeof(embeddedImages) / sizeof(embeddedImages[0]) - 1;
436int lowerLimit = 0;
437int compareIndex = (upperLimit - lowerLimit) >> 1; // Midpoint
438int result;
439
440// NOTE: This algorithm assumes that the embeddedImages is sorted.
441// This is currently done using the make file. If the array is every
442// manualy generated, this *will* fail to work properly.
443while((result = strcmp(name, embeddedImages[compareIndex].name)) != 0)
444{
445if(result > 0)// We need to search a HIGHER index
446{
447if(compareIndex != lowerLimit)
448{
449lowerLimit = compareIndex;
450}
451else
452{
453return -1;
454}
455compareIndex = (upperLimit + lowerLimit + 1) >> 1;// Midpoint, round up
456}
457else // We Need to search a LOWER index
458{
459if(compareIndex != upperLimit)
460{
461upperLimit = compareIndex;
462}
463else
464{
465return -1;
466}
467compareIndex = (upperLimit + lowerLimit) >> 1;// Midpoint, round down
468}
469}
470return compareIndex;
471}
472#endif
473
474static int loadThemeImage(char* src, const char *image, int alt_image)
475{
476chardirspec[256];
477int i;
478#ifdef EMBED_THEME
479int e;
480#endif
481uint16_twidth;
482uint16_theight;
483uint8_t*imagedata;
484if ((unsigned)(strlen(image) + strlen(theme_name) + strlen(src) + (6+1) ) > sizeof(dirspec)) {
485
486DBG("Path of %s/%s/%s.png to long\n", src, theme_name, image);
487
488return 1;
489}
490
491 if ((i = getImageIndexByName(image)) >= 0)
492 {
493if (images[i].image == NULL) {
494images[i].image = malloc(sizeof(pixmap_t));
495if (images[i].image == NULL) {
496
497DBG("Unable to allocate memory for %s.png\n", image);
498
499return 1;
500}
501}
502 sprintf(dirspec, "%s/%s/%s.png", src, theme_name, image);
503
504 width = 0;
505 height = 0;
506 imagedata = NULL;
507 if ( strlen(theme_name) > 0 && (loadPngImage(dirspec, &width, &height, &imagedata)) == 0)
508 {
509 images[i].image->width = width;
510 images[i].image->height = height;
511 images[i].image->pixels = (pixel_t *)imagedata;
512 flipRB(images[i].image);
513
514DBG("[ %s ] succesfully loaded and registred !!\n", dirspec);
515
516 return 0;
517 }
518#ifdef EMBED_THEME
519 else if ((e = getEmbeddedImageIndexByName(image)) >= 0)
520 {
521 unsigned char *embed_data;
522 unsigned int embed_size;
523 embed_data = embeddedImages[e].pngdata;
524 embed_size = *embeddedImages[e].length;
525
526 if (loadEmbeddedPngImage(embed_data, embed_size, &width, &height, &imagedata) == 0)
527 {
528 images[i].image->width = width;
529 images[i].image->height = height;
530 images[i].image->pixels = (pixel_t *)imagedata;
531 flipRB(images[i].image);
532 return 0;
533 }
534
535 return 0;
536 }
537#endif
538 else if (alt_image != IMG_REQUIRED)
539 {
540if (images[alt_image].image->pixels != NULL) {
541
542// Using the passed alternate image for non-mandatory images.
543// We don't clone the already existing pixmap, but using its properties instead!
544images[i].image->width = images[alt_image].image->width;
545images[i].image->height = images[alt_image].image->height;
546images[i].image->pixels = images[alt_image].image->pixels;
547
548} else {
549
550DBG("Unable to load %s, this image not vital anyway, reseting and returning success !!\n", dirspec);
551
552free(images[i].image);
553images[i].image = NULL;
554}
555
556 return 0;
557 }
558 else
559 {
560#if DEBUG_GUI
561 printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
562sleep(2);
563#else
564#ifndef CONFIG_EMBED_THEME
565 printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
566sleep(2);
567#endif
568#endif
569free(images[i].image);
570images[i].image = NULL;
571return 1;
572
573 }
574
575 }
576
577#if DEBUG_GUI
578printf("[ %s/%s/%s.png ] not used in this version, skipped !!\n",src, theme_name, image);
579sleep(2);
580#endif
581return 1;
582}
583
584static int loadGraphics(char *src)
585{
586DBG("Loading image into memory....\n",theme_name);
587
588LOADPNG(src, background, IMG_REQUIRED);
589
590LOADPNG(src, logo, IMG_REQUIRED);
591
592LOADPNG(src, device_generic, IMG_REQUIRED);
593LOADPNG(src, device_generic_o, iDeviceGeneric);
594
595LOADPNG(src, device_hfsplus, iDeviceGeneric);
596LOADPNG(src, device_hfsplus_o, iDeviceHFS);
597 LOADPNG(src, device_hfsplus_ml, iDeviceHFS_ML);
598 LOADPNG(src, device_hfsplus_ml_o, iDeviceHFS_ML_o);
599LOADPNG(src, device_hfsplus_lion, iDeviceHFS_Lion);
600LOADPNG(src, device_hfsplus_lion_o, iDeviceHFS_Lion_o);
601LOADPNG(src, device_hfsplus_sl, iDeviceHFS_SL);
602LOADPNG(src, device_hfsplus_sl_o, iDeviceHFS_SL_o);
603LOADPNG(src, device_hfsplus_leo, iDeviceHFS_Leo);
604LOADPNG(src, device_hfsplus_leo_o, iDeviceHFS_Leo_o);
605LOADPNG(src, device_hfsplus_tiger, iDeviceHFS_Tiger);
606LOADPNG(src, device_hfsplus_tiger_o, iDeviceHFS_Tiger_o);
607
608LOADPNG(src, device_hfsraid, iDeviceGeneric);
609LOADPNG(src, device_hfsraid_o, iDeviceHFSRAID);
610 LOADPNG(src, device_hfsraid_ml, iDeviceHFSRAID_ML);
611 LOADPNG(src, device_hfsraid_ml_o, iDeviceHFSRAID_ML_o);
612LOADPNG(src, device_hfsraid_lion, iDeviceHFSRAID_Lion);
613LOADPNG(src, device_hfsraid_lion_o, iDeviceHFSRAID_Lion_o);
614LOADPNG(src, device_hfsraid_sl, iDeviceHFSRAID_SL);
615LOADPNG(src, device_hfsraid_sl_o, iDeviceHFSRAID_SL_o);
616LOADPNG(src, device_hfsraid_leo, iDeviceHFSRAID_Leo);
617LOADPNG(src, device_hfsraid_leo_o, iDeviceHFSRAID_Leo_o);
618LOADPNG(src, device_hfsraid_tiger, iDeviceHFSRAID_Tiger);
619LOADPNG(src, device_hfsraid_tiger_o, iDeviceHFSRAID_Tiger_o);
620
621LOADPNG(src, device_ext3, iDeviceGeneric);
622LOADPNG(src, device_ext3_o, iDeviceEXT3);
623LOADPNG(src, device_freebsd, iDeviceGeneric);
624LOADPNG(src, device_freebsd_o, iDeviceFreeBSD);
625LOADPNG(src, device_openbsd, iDeviceGeneric);
626LOADPNG(src, device_openbsd_o, iDeviceOpenBSD);
627LOADPNG(src, device_befs, iDeviceGeneric); /* Haiku detection and Icon credits to scorpius */
628LOADPNG(src, device_befs_o, iDeviceBEFS); /* Haiku detection and Icon credits to scorpius */
629LOADPNG(src, device_fat, iDeviceGeneric);
630LOADPNG(src, device_fat_o, iDeviceFAT);
631LOADPNG(src, device_fat16, iDeviceFAT);
632LOADPNG(src, device_fat16_o, iDeviceFAT_o);
633LOADPNG(src, device_fat32, iDeviceFAT);
634LOADPNG(src, device_fat32_o, iDeviceFAT_o);
635LOADPNG(src, device_ntfs, iDeviceGeneric);
636LOADPNG(src, device_ntfs_o, iDeviceNTFS);
637LOADPNG(src, device_cdrom, iDeviceGeneric);
638LOADPNG(src, device_cdrom_o, iDeviceCDROM);
639
640LOADPNG(src, device_selection, IMG_REQUIRED);
641LOADPNG(src, device_scroll_prev, IMG_REQUIRED);
642LOADPNG(src, device_scroll_next, IMG_REQUIRED);
643
644LOADPNG(src, menu_boot, IMG_REQUIRED);
645LOADPNG(src, menu_verbose, IMG_REQUIRED);
646LOADPNG(src, menu_ignore_caches, IMG_REQUIRED);
647LOADPNG(src, menu_single_user, IMG_REQUIRED);
648LOADPNG(src, menu_memory_info, IMG_REQUIRED);
649LOADPNG(src, menu_video_info, IMG_REQUIRED);
650LOADPNG(src, menu_help, IMG_REQUIRED);
651LOADPNG(src, menu_verbose_disabled, IMG_REQUIRED);
652LOADPNG(src, menu_ignore_caches_disabled, IMG_REQUIRED);
653LOADPNG(src, menu_single_user_disabled, IMG_REQUIRED);
654LOADPNG(src, menu_selection, IMG_REQUIRED);
655
656LOADPNG(src, progress_bar, IMG_REQUIRED);
657LOADPNG(src, progress_bar_background, IMG_REQUIRED);
658
659LOADPNG(src, text_scroll_prev, IMG_REQUIRED);
660LOADPNG(src, text_scroll_next, IMG_REQUIRED);
661
662LOADPNG(src, font_console, IMG_REQUIRED);
663LOADPNG(src, font_small, IMG_REQUIRED);
664
665DBG("Initializing font....\n",theme_name);
666
667initFont( &font_console, &images[iFontConsole]);
668initFont( &font_small, &images[iFontSmall]);
669
670DBG("Graphic objects successfully loaded !!\n",theme_name);
671
672return 0;
673}
674
675static int unloadGraphics(void)
676{
677 int i;
678
679 destroyFont(&font_console);
680 destroyFont(&font_small);
681for (i = 0; i < sizeof(images) / sizeof(images[0]); i++)
682{
683 if (images[i].image)
684 {
685 if (images[i].image->pixels) free(images[i].image->pixels);
686 free (images[i].image);
687 images[i].image = 0;
688 }
689}
690return 0;
691}
692
693static int freeBackBuffer( window_t *window )
694{
695if (gui.backbuffer && gui.backbuffer->pixels)
696 {
697free(gui.backbuffer->pixels);
698free(gui.backbuffer);
699gui.backbuffer = 0;
700return 0;
701}
702
703return 1;
704}
705
706#if UNUSED
707pixmap_t *getCroppedPixmapAtPosition( pixmap_t *from, position_t pos, uint16_t width, uint16_t height )
708{
709
710pixmap_t *cropped = malloc( sizeof( pixmap_t ) );
711if( !cropped )
712return 0;
713cropped->pixels = malloc( width * height * 4 );
714if ( !cropped->pixels )
715return 0;
716
717cropped->width = width;
718cropped->height = height;
719
720int destx = 0, desty = 0;
721int srcx = pos.x, srcy = pos.y;
722
723for( ; desty < height; desty++, srcy++)
724{
725for( destx = 0, srcx = pos.x; destx < width; destx++, srcx++ )
726{
727pixel( cropped, destx, desty ).value = pixel( from, srcx, srcy ).value;
728}
729}
730return cropped;
731}
732#endif
733
734static int createBackBuffer( window_t *window )
735{
736gui.backbuffer = malloc(sizeof(pixmap_t));
737if(!gui.backbuffer)
738{
739DBG("Unable to allocate memory for gui.backbuffer");
740return 1;
741}
742
743gui.backbuffer->pixels = malloc( window->width * window->height * 4 );
744if(!gui.backbuffer->pixels)
745{
746free(gui.backbuffer);
747gui.backbuffer = 0;
748DBG("Unable to allocate memory for gui.backbuffer->pixels");
749return 1;
750}
751
752gui.backbuffer->width = gui.screen.width;
753gui.backbuffer->height = gui.screen.height;
754
755return 0;
756}
757
758static int createWindowBuffer( window_t *window )
759{
760window->pixmap = malloc(sizeof(pixmap_t));
761if(!window->pixmap)
762{
763DBG("Unable to allocate memory for window->pixmap");
764return 1;
765}
766
767window->pixmap->pixels = malloc( window->width * window->height * 4 );
768if(!window->pixmap->pixels)
769{
770free(window->pixmap);
771window->pixmap = 0;
772DBG("Unable to allocate memory for window->pixmap->pixels");
773return 1;
774}
775
776window->pixmap->width = window->width;
777window->pixmap->height = window->height;
778
779return 0;
780}
781
782static int freeWindowBuffer( window_t *window )
783{
784if (window->pixmap && window->pixmap->pixels)
785 {
786free(window->pixmap->pixels);
787free(window->pixmap);
788return 0;
789}
790
791return 1;
792}
793
794static void fillPixmapWithColor(pixmap_t *pm, uint32_t color)
795{
796int x,y;
797
798// fill with given color AARRGGBB
799for( x=0; x < pm->width; x++ )
800for( y=0; y< pm->height; y++)
801pixel(pm,x,y).value = color;
802}
803
804void drawBackground()
805{
806// reset text cursor
807gui.screen.cursor.x = gui.screen.hborder;
808gui.screen.cursor.y = gui.screen.vborder;
809
810fillPixmapWithColor( gui.screen.pixmap, gui.screen.bgcolor);
811
812// draw background.png into background buffer
813blend( images[iBackground].image, gui.screen.pixmap, gui.background.pos );
814
815// draw logo.png into background buffer
816if (gui.logo.draw)
817{
818 blend( images[iLogo].image, gui.screen.pixmap, gui.logo.pos);
819}
820
821memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
822}
823
824static void setupDeviceList(config_file_t *theme)
825{
826unsigned int pixel;
827intalpha;// transparency level 0 (obligue) - 255 (transparent)
828uint32_t color;// color value formatted RRGGBB
829int val, len;
830const char *string;
831 int devcnt = (int)get_env(envgDeviceCount);
832
833if(getIntForKey("devices_max_visible", &val, theme ))
834gui.maxdevices = MIN( val, devcnt );
835
836if(getIntForKey("devices_iconspacing", &val, theme ))
837gui.devicelist.iconspacing = val;
838
839// check layout for horizontal or vertical
840gui.layout = HorizontalLayout;
841if(getValueForKey( "devices_layout", &string, &len, theme)) {
842if (!strcmp (string, "vertical")) {
843gui.layout = VerticalLayout;
844}
845}
846
847switch (gui.layout) {
848case VerticalLayout:
849gui.devicelist.height = ((images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing) * MIN(gui.maxdevices, devcnt) + (images[iDeviceScrollPrev].image->height + images[iDeviceScrollNext].image->height) + gui.devicelist.iconspacing);
850gui.devicelist.width = (images[iSelection].image->width + gui.devicelist.iconspacing);
851
852if(getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , images[iSelection].image->width ) )
853gui.devicelist.pos.x = pixel;
854
855if(getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , gui.devicelist.height ) )
856gui.devicelist.pos.y = pixel;
857break;
858
859case HorizontalLayout:
860default:
861gui.devicelist.width = ((images[iSelection].image->width + gui.devicelist.iconspacing) * MIN(gui.maxdevices, devcnt) + (images[iDeviceScrollPrev].image->width + images[iDeviceScrollNext].image->width) + gui.devicelist.iconspacing);
862gui.devicelist.height = (images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing);
863
864if(getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , gui.devicelist.width ) )
865gui.devicelist.pos.x = pixel;
866else
867gui.devicelist.pos.x = ( gui.screen.width - gui.devicelist.width ) / 2;
868
869if(getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , images[iSelection].image->height ) )
870gui.devicelist.pos.y = pixel;
871else
872gui.devicelist.pos.y = ( gui.screen.height - gui.devicelist.height ) / 2;
873break;
874}
875
876if(getColorForKey("devices_bgcolor", &color, theme))
877gui.devicelist.bgcolor = (color & 0x00FFFFFF);
878
879if(getIntForKey("devices_transparency", &alpha, theme))
880gui.devicelist.bgcolor = gui.devicelist.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
881
882if (gui.devicelist.pixmap)
883{
884 freeWindowBuffer(&gui.devicelist);
885 createWindowBuffer(&gui.devicelist);
886 }
887}
888
889static void loadThemeValues(config_file_t *theme)
890{
891unsigned int screen_width = gui.screen.width;
892unsigned int screen_height = gui.screen.height;
893unsigned int pixel;
894intalpha;// transparency level 0 (obligue) - 255 (transparent)
895uint32_t color;// color value formatted RRGGBB
896int val;
897
898/*
899 * Parse screen parameters
900 */
901if(getColorForKey("screen_bgcolor", &color, theme ))
902gui.screen.bgcolor = (color & 0x00FFFFFF);
903
904if(getIntForKey("screen_textmargin_h", &val, theme))
905gui.screen.hborder = MIN( gui.screen.width , val );
906
907if(getIntForKey("screen_textmargin_v", &val, theme))
908gui.screen.vborder = MIN( gui.screen.height , val );
909
910/*
911 * Parse background parameters
912 */
913if(getDimensionForKey("background_pos_x", &pixel, theme, screen_width , images[iBackground].image->width ) )
914gui.background.pos.x = pixel;
915
916if(getDimensionForKey("background_pos_y", &pixel, theme, screen_height , images[iBackground].image->height ) )
917gui.background.pos.y = pixel;
918
919/*
920 * Parse logo parameters
921 */
922if(getDimensionForKey("logo_pos_x", &pixel, theme, screen_width , images[iLogo].image->width ) )
923gui.logo.pos.x = pixel;
924
925if(getDimensionForKey("logo_pos_y", &pixel, theme, screen_height , images[iLogo].image->height ) )
926gui.logo.pos.y = pixel;
927
928/*
929 * Parse progress bar parameters
930 */
931if(getDimensionForKey("progressbar_pos_x", &pixel, theme, screen_width , 0 ) )
932gui.progressbar.pos.x = pixel;
933
934if(getDimensionForKey("progressbar_pos_y", &pixel, theme, screen_height , 0 ) )
935gui.progressbar.pos.y = pixel;
936
937/*
938 * Parse countdown text parameters
939 */
940if(getDimensionForKey("countdown_pos_x", &pixel, theme, screen_width , 0 ) )
941gui.countdown.pos.x = pixel;
942
943if(getDimensionForKey("countdown_pos_y", &pixel, theme, screen_height , 0 ) )
944gui.countdown.pos.y = pixel;
945
946 /*
947 * Parse devicelist parameters
948 */
949setupDeviceList(theme);
950
951/*
952 * Parse infobox parameters
953 */
954if(getIntForKey("infobox_width", &val, theme) && val >= 0)
955gui.infobox.width = MIN( screen_width ,(unsigned) val );
956
957if(getIntForKey("infobox_height", &val, theme) && val >= 0)
958gui.infobox.height = MIN( screen_height , (unsigned)val );
959
960if(getDimensionForKey("infobox_pos_x", &pixel, theme, screen_width , gui.infobox.width ) )
961gui.infobox.pos.x = pixel;
962
963if(getDimensionForKey("infobox_pos_y", &pixel, theme, screen_height , gui.infobox.height ) )
964gui.infobox.pos.y = pixel;
965
966if(getIntForKey("infobox_textmargin_h", &val, theme))
967gui.infobox.hborder = MIN( gui.infobox.width , val );
968
969if(getIntForKey("infobox_textmargin_v", &val, theme))
970gui.infobox.vborder = MIN( gui.infobox.height , val );
971
972if(getColorForKey("infobox_bgcolor", &color, theme))
973gui.infobox.bgcolor = (color & 0x00FFFFFF);
974
975if(getIntForKey("infobox_transparency", &alpha, theme))
976gui.infobox.bgcolor = gui.infobox.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
977
978/*
979 * Parse menu parameters
980 */
981if(getDimensionForKey("menu_width", &pixel, theme, gui.screen.width , 0 ) )
982gui.menu.width = pixel;
983else
984gui.menu.width = images[iMenuSelection].image->width;
985
986if(getDimensionForKey("menu_height", &pixel, theme, gui.screen.height , 0 ) )
987gui.menu.height = pixel;
988else
989gui.menu.height = (infoMenuItemsCount) * images[iMenuSelection].image->height;
990
991if(getDimensionForKey("menu_pos_x", &pixel, theme, screen_width , gui.menu.width ) )
992gui.menu.pos.x = pixel;
993
994if(getDimensionForKey("menu_pos_y", &pixel, theme, screen_height , gui.menu.height ) )
995gui.menu.pos.y = pixel;
996
997if(getIntForKey("menu_textmargin_h", &val, theme))
998gui.menu.hborder = MIN( gui.menu.width , val );
999
1000if(getIntForKey("menu_textmargin_v", &val, theme))
1001gui.menu.vborder = MIN( gui.menu.height , val );
1002
1003if(getColorForKey("menu_bgcolor", &color, theme))
1004gui.menu.bgcolor = (color & 0x00FFFFFF);
1005
1006if(getIntForKey("menu_transparency", &alpha, theme))
1007gui.menu.bgcolor = gui.menu.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
1008
1009/*
1010 * Parse bootprompt parameters
1011 */
1012if(getDimensionForKey("bootprompt_width", &pixel, theme, screen_width , 0 ) )
1013gui.bootprompt.width = pixel;
1014
1015if(getIntForKey("bootprompt_height", &val, theme) && val >= 0)
1016gui.bootprompt.height = MIN( screen_height , (unsigned)val );
1017
1018if(getDimensionForKey("bootprompt_pos_x", &pixel, theme, screen_width , gui.bootprompt.width ) )
1019gui.bootprompt.pos.x = pixel;
1020
1021if(getDimensionForKey("bootprompt_pos_y", &pixel, theme, screen_height , gui.bootprompt.height ) )
1022gui.bootprompt.pos.y = pixel;
1023
1024if(getIntForKey("bootprompt_textmargin_h", &val, theme) && val >= 0)
1025gui.bootprompt.hborder = MIN( gui.bootprompt.width , (unsigned)val );
1026
1027if(getIntForKey("bootprompt_textmargin_v", &val, theme) && val >= 0)
1028gui.bootprompt.vborder = MIN( gui.bootprompt.height , (unsigned)val );
1029
1030if(getColorForKey("bootprompt_bgcolor", &color, theme))
1031gui.bootprompt.bgcolor = (color & 0x00FFFFFF);
1032
1033if(getIntForKey("bootprompt_transparency", &alpha, theme))
1034gui.bootprompt.bgcolor = gui.bootprompt.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
1035
1036if(getColorForKey("font_small_color", &color, theme))
1037gui.screen.font_small_color = (color & 0x00FFFFFF);
1038
1039if(getColorForKey("font_console_color", &color, theme))
1040gui.screen.font_console_color = (color & 0x00FFFFFF);
1041}
1042
1043#define MAX_THEMES 255
1044
1045static void add_theme(const char* theme, uint8_t nb)
1046{
1047
1048themeList_t* new_theme = malloc(sizeof(themeList_t));
1049if (new_theme)
1050{
1051new_theme->next = themeList;
1052
1053themeList = new_theme;
1054
1055new_theme->nb = nb;
1056new_theme->theme = newString(theme);
1057}
1058}
1059
1060static void free_theme_list()
1061{
1062themeList_t* entry = themeList;
1063while(entry)
1064{
1065#if DEBUG_GUI
1066printf("freeing %s (nb = %d)\n", entry->theme, entry->nb);
1067#endif
1068
1069char *theme = entry->theme;
1070themeList_t* tmp = NULL;
1071
1072tmp = entry;
1073entry = entry->next;
1074
1075free(theme);
1076free(tmp);
1077
1078}
1079}
1080
1081
1082static int randomTheme(char *dirspec, const char **theme) {
1083
1084long ret, flags, time;
1085long long index;
1086int sta = 1;
1087const char * name;
1088index = 0;
1089uint8_t i=0;
1090
1091#ifdef EMBED_THEME
1092add_theme("", i);
1093i++;
1094#endif
1095
1096while (i < MAX_THEMES) {
1097ret = GetDirEntry(dirspec, &index, &name, &flags, &time);
1098if (ret == -1) break;
1099
1100// Make sure this is a directory.
1101if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
1102
1103add_theme(name, i);
1104
1105i++;
1106
1107}
1108#if DEBUG_GUI
1109themeList_t* debugentry = themeList;
1110printf("theme list: \n");
1111while(debugentry)
1112{
1113printf("* %s (nb = %d)\n", debugentry->theme, debugentry->nb);
1114debugentry = debugentry->next;
1115}
1116printf("\n");
1117#endif
1118
1119if (i) {
1120
1121uint8_t choosen = arc4random_uniform(i+1);
1122
1123themeList_t* entry = themeList;
1124
1125while(entry)
1126{
1127
1128if (entry->nb == choosen) break;
1129
1130entry = entry->next;
1131}
1132
1133if (entry) {
1134#if DEBUG_GUI
1135
1136printf("choosen theme %s (nb = %d)\n", entry->theme, entry->nb);
1137sleep(1);
1138#endif
1139*theme = entry->theme;
1140
1141sta = startGUI();
1142
1143
1144}
1145#if DEBUG_GUI
1146else {
1147goto out;
1148}
1149#endif
1150
1151
1152free_theme_list();
1153
1154}
1155#if DEBUG_GUI
1156else {
1157printf("No theme found !!\n");
1158
1159sleep(1);
1160}
1161#endif
1162return sta;
1163
1164#if DEBUG_GUI
1165out:
1166printf("random theme failed !!\n");
1167
1168sleep(1);
1169#endif
1170return sta;
1171
1172
1173}
1174
1175int initGUI(void)
1176{
1177bool dummybool = true;
1178int ret = 1;
1179bool theme_ran= false;
1180bool theme_name_set= false;
1181
1182getBoolForKey(kGUIKey, &dummybool, DEFAULT_BOOT_CONFIG);
1183if (!dummybool) {
1184return 1;
1185}
1186 getMemoryInfoString = (void*)lookup_all_symbols(SYMBOLS_BUNDLE,"_getMemoryInfoString");
1187 showHelp = (void*)lookup_all_symbols(SYMBOLS_BUNDLE,"_showHelp");
1188
1189
1190getBoolForKey("RandomTheme", &theme_ran, DEFAULT_BOOT_CONFIG);
1191
1192{
1193long flags;
1194long time;
1195long ret = -1;
1196int len;
1197
1198theme_name_set = getValueForKey( "Theme", &theme_name, &len, DEFAULT_BOOT_CONFIG );
1199
1200if (theme_ran)
1201{
1202retry:
1203ret = GetFileInfo("rd(0,0)/Extra/", "Themes", &flags, &time);
1204if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1205sprintf(dirsrc, "rd(0,0)/Extra/Themes");
1206
1207} else {
1208ret = GetFileInfo("/Extra/", "Themes", &flags, &time);
1209if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1210sprintf(dirsrc, "/Extra/Themes");
1211
1212} else {
1213ret = GetFileInfo("bt(0,0)/Extra/", "Themes", &flags, &time);
1214if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1215sprintf(dirsrc, "bt(0,0)/Extra/Themes");
1216
1217} else {
1218printf("Failed to find the /extra/Themes folder\n");
1219return 1;
1220}
1221}
1222
1223}
1224}
1225else if (theme_name_set)
1226{
1227ret = GetFileInfo("rd(0,0)/Extra/Themes/", theme_name, &flags, &time);
1228if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1229sprintf(dirsrc, "rd(0,0)/Extra/Themes");
1230
1231} else {
1232ret = GetFileInfo("/Extra/Themes/", theme_name, &flags, &time);
1233if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1234sprintf(dirsrc, "/Extra/Themes");
1235
1236} else {
1237ret = GetFileInfo("bt(0,0)/Extra/Themes/", theme_name, &flags, &time);
1238if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)) {
1239sprintf(dirsrc, "bt(0,0)/Extra/Themes");
1240
1241} else {
1242printf("Failed to find the /extra/Themes/%s folder\n",theme_name);
1243theme_name_set = false;
1244goto retry;
1245}
1246}
1247
1248}
1249}
1250}
1251
1252if (theme_ran)
1253{
1254
1255ret = randomTheme(dirsrc, &theme_name);
1256
1257if (ret) printf("randomTheme Failed !! \n");
1258#if DEBUG_GUI
1259else
1260 {
1261 DBG("Theme successfuly Choosen randomly !! \n");
1262 }
1263#endif
1264}
1265
1266if (ret)
1267{
1268if (theme_name_set == true)
1269{
1270ret = startGUI();
1271
1272if (ret) printf("Failed to load Theme : %s !! \n", theme_name);
1273
1274}
1275#ifdef EMBED_THEME
1276if (ret) {
1277theme_name = "";
1278ret = startGUI();
1279
1280if (ret) printf("Failed to load Embed Theme !! \n");
1281
1282}
1283#endif
1284if (ret && (strcmp(theme_name, THEME_NAME_DEFAULT) != 0)) {
1285theme_name = THEME_NAME_DEFAULT;
1286ret = startGUI();
1287
1288if (ret) printf("Failed to load Default Theme : %s !! \n", THEME_NAME_DEFAULT);
1289}
1290}
1291return ret;
1292}
1293
1294static int startGUI(void)
1295{
1296int val;
1297char dirspec[256];
1298
1299
1300if ((unsigned)(strlen(theme_name) + strlen(dirsrc) + strlen("theme.plist") + 2 ) > sizeof(dirspec)) {
1301
1302DBG("Path of %s/%s/theme.plist to long\n", dirsrc, theme_name);
1303return 1;
1304}
1305
1306sprintf(dirspec, "%s/%s/theme.plist", dirsrc ,theme_name);
1307
1308if (loadConfigFile(dirspec, &themeConfig) != 0) {
1309
1310#ifdef EMBED_THEME
1311if (strlen(theme_name) == 0) {
1312config_file_t *config;
1313
1314config = &themeConfig;
1315if (ParseXMLFile((char *)__theme_plist, &config->dictionary) != 0) {
1316
1317DBG("Unable to load embed theme plist datas.\n");
1318
1319return 1;
1320}
1321}
1322#else
1323
1324DBG("Unable to load %s theme plist.\n",theme_name);
1325
1326return 1;
1327
1328#endif
1329 }
1330
1331if (execute_hook("getResolution_hook", &screen_params[0], &screen_params[1], &screen_params[2], NULL, NULL, NULL) != EFI_SUCCESS)
1332{
1333// parse display size parameters
1334if (getIntForKey("screen_width", &val, &themeConfig) && val > 0) {
1335screen_params[0] = val;
1336}
1337if (getIntForKey("screen_height", &val, &themeConfig) && val > 0) {
1338screen_params[1] = val;
1339}
1340}
1341#if DEBUG_GUI
1342else
1343{
1344printf("No getResolution function hook installed, using default resolution.\n",theme_name);
1345
1346}
1347#endif
1348
1349
1350// Initalizing GUI strucutre.
1351bzero(&gui, sizeof(gui_t));
1352
1353// find best matching vesa mode for our requested width & height
1354getGraphicModeParams(screen_params);
1355
1356// set our screen structure with the mode width & height
1357gui.screen.width = screen_params[0];
1358gui.screen.height = screen_params[1];
1359
1360// load graphics otherwise fail and return
1361if (loadGraphics(dirsrc) == 0) {
1362loadThemeValues(&themeConfig);
1363colorFont(&font_small, gui.screen.font_small_color);
1364colorFont(&font_console, gui.screen.font_console_color);
1365
1366// create the screen & window buffers
1367if (createBackBuffer(&gui.screen) == 0)
1368{
1369if (createWindowBuffer(&gui.screen) == 0)
1370{
1371if (createWindowBuffer(&gui.devicelist) == 0)
1372{
1373if (createWindowBuffer(&gui.bootprompt) == 0)
1374{
1375if (createWindowBuffer(&gui.infobox) == 0)
1376{
1377if (createWindowBuffer(&gui.menu) == 0)
1378{
1379 gui.logo.draw = true;
1380drawBackground();
1381// lets copy the screen into the back buffer
1382 memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
1383
1384setVideoMode( GRAPHICS_MODE );
1385
1386gui.initialised = true;
1387return 0;
1388}
1389}
1390}
1391}
1392}
1393}
1394}
1395
1396DBG("Loading error occurred, reseting...\n",theme_name);
1397
1398// Loading error occurred, freeing resources
1399 freeWindowBuffer(&gui.menu);
1400 freeWindowBuffer(&gui.infobox);
1401 freeWindowBuffer(&gui.bootprompt);
1402 freeWindowBuffer(&gui.devicelist);
1403 freeWindowBuffer(&gui.screen);
1404 freeBackBuffer(&gui.screen);
1405 unloadGraphics();
1406
1407return 1;
1408}
1409
1410static bool is_image_loaded(int i)
1411{
1412return (images[i].image != NULL) ? true : false;
1413}
1414
1415static void drawDeviceIcon(BVRef device, pixmap_t *buffer, position_t p, bool isSelected)
1416{
1417int devicetype;
1418
1419if( diskIsCDROM(device) )
1420devicetype = iDeviceCDROM;// Use CDROM icon
1421else
1422{
1423switch (device->part_type)
1424{
1425case kPartitionTypeHFS:
1426{
1427#ifdef BOOT_HELPER_SUPPORT
1428// Use HFS or HFSRAID icon depending on bvr flags.
1429if (device->flags & kBVFlagBooter) {
1430
1431switch (device->OSVersion[3]) {
1432 case '8':
1433 devicetype = is_image_loaded(iDeviceHFSRAID_ML) ? iDeviceHFSRAID_ML : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1434 break;
1435case '7':
1436devicetype = is_image_loaded(iDeviceHFSRAID_Lion) ? iDeviceHFSRAID_Lion : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1437break;
1438case '6':
1439devicetype = is_image_loaded(iDeviceHFSRAID_SL) ? iDeviceHFSRAID_SL : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1440break;
1441case '5':
1442devicetype = is_image_loaded(iDeviceHFSRAID_Leo) ? iDeviceHFSRAID_Leo : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1443break;
1444case '4':
1445devicetype = is_image_loaded(iDeviceHFSRAID_Tiger) ? iDeviceHFSRAID_Tiger : is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1446break;
1447default:
1448devicetype = is_image_loaded(iDeviceHFSRAID) ? iDeviceHFSRAID : iDeviceGeneric;
1449break;
1450}
1451
1452} else
1453#endif
1454{
1455
1456switch (device->OSVersion[3]) {
1457 case '8':
1458 devicetype = is_image_loaded(iDeviceHFS_ML) ? iDeviceHFS_ML : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1459 break;
1460case '7':
1461devicetype = is_image_loaded(iDeviceHFS_Lion) ? iDeviceHFS_Lion : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1462break;
1463case '6':
1464devicetype = is_image_loaded(iDeviceHFS_SL) ? iDeviceHFS_SL : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1465break;
1466case '5':
1467devicetype = is_image_loaded(iDeviceHFS_Leo) ? iDeviceHFS_Leo : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1468break;
1469case '4':
1470devicetype = is_image_loaded(iDeviceHFS_Tiger) ? iDeviceHFS_Tiger : is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1471break;
1472default:
1473devicetype = is_image_loaded(iDeviceHFS) ? iDeviceHFS : iDeviceGeneric;
1474break;
1475}
1476
1477}
1478
1479break;
1480
1481}
1482case kPartitionTypeHPFS:
1483devicetype = is_image_loaded(iDeviceNTFS) ? iDeviceNTFS : iDeviceGeneric;// Use HPFS / NTFS icon
1484break;
1485
1486case kPartitionTypeFAT16:
1487devicetype = is_image_loaded(iDeviceFAT16) ? iDeviceFAT16 : iDeviceGeneric;// Use FAT16 icon
1488break;
1489
1490case kPartitionTypeFAT32:
1491devicetype = is_image_loaded(iDeviceFAT32) ? iDeviceFAT32 : iDeviceGeneric;// Use FAT32 icon
1492break;
1493
1494case kPartitionTypeEXT3:
1495devicetype = is_image_loaded(iDeviceEXT3) ? iDeviceEXT3 : iDeviceGeneric;// Use EXT2/3 icon
1496break;
1497
1498case kPartitionTypeFreeBSD:
1499devicetype = is_image_loaded(iDeviceFreeBSD) ? iDeviceFreeBSD : iDeviceGeneric;// Use FreeBSD icon
1500break;
1501
1502case kPartitionTypeOpenBSD:
1503devicetype = is_image_loaded(iDeviceOpenBSD) ? iDeviceOpenBSD : iDeviceGeneric;// Use OpenBSD icon
1504break;
1505
1506case kPartitionTypeBEFS: /* Haiku detection and Icon credits to scorpius */
1507devicetype = is_image_loaded(iDeviceBEFS) ? iDeviceBEFS : iDeviceGeneric;// Use BEFS / Haiku icon
1508break;
1509
1510default:
1511devicetype = iDeviceGeneric;// Use Generic icon
1512break;
1513}
1514}
1515
1516// Draw the selection image and use the next (device_*_o) image for the selected item.
1517 if (isSelected)
1518{
1519blend(images[iSelection].image, buffer, centeredAt(images[iSelection].image, p));
1520devicetype++; // selec override image
1521}
1522
1523// draw icon
1524blend( images[devicetype].image, buffer, centeredAt( images[devicetype].image, p ));
1525
1526p.y += (images[iSelection].image->height / 2) + font_console.chars[0]->height;
1527
1528// draw volume label
1529drawStrCenteredAt( device->label, &font_small, buffer, p);
1530
1531}
1532
1533void drawDeviceList (int start, int end, int selection, MenuItem * menuItems)
1534{
1535int i;
1536position_t p, p_prev, p_next;
1537
1538//uint8_tmaxDevices = MIN( gui.maxdevices, menucount );
1539
1540fillPixmapWithColor( gui.devicelist.pixmap, gui.devicelist.bgcolor);
1541
1542makeRoundedCorners( gui.devicelist.pixmap);
1543
1544 int devcnt = (int)get_env(envgDeviceCount);
1545
1546switch (gui.layout)
1547{
1548
1549case VerticalLayout:
1550p.x = (gui.devicelist.width /2);
1551p.y = ( ( images[iSelection].image->height / 2 ) + images[iDeviceScrollPrev].image->height + gui.devicelist.iconspacing );
1552
1553// place scroll indicators at top & bottom edges
1554p_prev = pos ( gui.devicelist.width / 2 , gui.devicelist.iconspacing );
1555p_next = pos ( p_prev.x, gui.devicelist.height - gui.devicelist.iconspacing );
1556
1557break;
1558
1559default:// use Horizontal layout as the default
1560
1561case HorizontalLayout:
1562p.x = (gui.devicelist.width - ( gui.devicelist.width / gui.maxdevices ) * gui.maxdevices ) / 2 + ( images[iSelection].image->width / 2) + images[iDeviceScrollPrev].image->width + gui.devicelist.iconspacing;
1563p.y = ((gui.devicelist.height - font_console.chars[0]->height ) - images[iSelection].image->height) / 2 + ( images[iSelection].image->height / 2 );
1564
1565// place scroll indicators at left & right edges
1566p_prev = pos ( images[iDeviceScrollPrev].image->width / 2 + gui.devicelist.iconspacing / 2, gui.devicelist.height / 2 );
1567p_next = pos ( gui.devicelist.width - ( images[iDeviceScrollNext].image->width / 2 + gui.devicelist.iconspacing / 2), gui.devicelist.height / 2 );
1568
1569break;
1570
1571}
1572
1573// draw visible device icons
1574for (i = 0; i < gui.maxdevices; i++)
1575{
1576BVRef param = menuItems[start + i].param;
1577
1578 bool isSelected = ((start + i) == selection) ? true : false;
1579if (isSelected)
1580{
1581 if (param->flags & kBVFlagNativeBoot)
1582 {
1583 infoMenuNativeBoot = true;
1584 }
1585 else
1586 {
1587 infoMenuNativeBoot = false;
1588 if(infoMenuSelection >= INFOMENU_NATIVEBOOT_START && infoMenuSelection <= INFOMENU_NATIVEBOOT_END)
1589infoMenuSelection = 0;
1590 }
1591
1592if(gui.menu.draw)
1593drawInfoMenuItems();
1594
1595#if DEBUG_GUI
1596 gui.debug.cursor = pos( 10, 100);
1597 dprintf( &gui.screen, "label %s\n", param->label );
1598 dprintf( &gui.screen, "biosdev 0x%x\n", param->biosdev );
1599 dprintf( &gui.screen, "width %d\n", gui.screen.width);
1600 dprintf( &gui.screen, "height %d\n", gui.screen.height);
1601 dprintf( &gui.screen, "type 0x%x\n", param->type );
1602 dprintf( &gui.screen, "flags 0x%x\n", param->flags );
1603 dprintf( &gui.screen, "part_no %d\n", param->part_no );
1604 dprintf( &gui.screen, "part_boff 0x%x\n", param->part_boff );
1605 dprintf( &gui.screen, "part_type 0x%x\n", param->part_type );
1606 dprintf( &gui.screen, "bps 0x%x\n", param->bps );
1607 dprintf( &gui.screen, "name %s\n", param->name );
1608 dprintf( &gui.screen, "type_name %s\n", param->type_name );
1609 dprintf( &gui.screen, "modtime %d\n", param->modTime );
1610#endif
1611}
1612
1613drawDeviceIcon( param, gui.devicelist.pixmap, p, isSelected);
1614
1615if (gui.layout == HorizontalLayout)
1616{
1617p.x += images[iSelection].image->width + gui.devicelist.iconspacing;
1618}
1619if (gui.layout == VerticalLayout)
1620{
1621p.y += ( images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing );
1622}
1623}
1624
1625// draw prev indicator
1626if(start)
1627blend( images[iDeviceScrollPrev].image, gui.devicelist.pixmap, centeredAt( images[iDeviceScrollPrev].image, p_prev ) );
1628
1629// draw next indicator
1630if( end < devcnt - 1 )
1631blend( images[iDeviceScrollNext].image, gui.devicelist.pixmap, centeredAt( images[iDeviceScrollNext].image, p_next ) );
1632
1633gui.redraw = true;
1634
1635updateVRAM();
1636
1637}
1638
1639void clearGraphicBootPrompt()
1640{
1641// clear text buffer
1642prompt[0] = '\0';
1643prompt_pos=0;
1644
1645
1646if(gui.bootprompt.draw == true )
1647{
1648gui.bootprompt.draw = false;
1649gui.redraw = true;
1650// this causes extra frames to be drawn
1651//updateVRAM();
1652}
1653
1654return;
1655}
1656
1657void updateGraphicBootPrompt(int key)
1658{
1659if ( key == kBackspaceKey )
1660prompt[--prompt_pos] = '\0';
1661else
1662{
1663prompt[prompt_pos] = key;
1664prompt_pos++;
1665prompt[prompt_pos] = '\0';
1666}
1667
1668fillPixmapWithColor( gui.bootprompt.pixmap, gui.bootprompt.bgcolor);
1669
1670makeRoundedCorners( gui.bootprompt.pixmap);
1671
1672position_t p_text = pos( gui.bootprompt.hborder , ( ( gui.bootprompt.height - font_console.chars[0]->height) ) / 2 );
1673
1674// print the boot prompt text
1675drawStr(prompt_text, &font_console, gui.bootprompt.pixmap, p_text);
1676
1677// get the position of the end of the boot prompt text to display user input
1678position_t p_prompt = pos( p_text.x + ( ( strlen(prompt_text) ) * font_console.chars[0]->width ), p_text.y );
1679
1680// calculate the position of the cursor
1681intoffset = ( prompt_pos - ( ( gui.bootprompt.width / font_console.chars[0]->width ) - strlen(prompt_text) - 2 ) );
1682
1683if ( offset < 0)
1684offset = 0;
1685
1686drawStr( prompt+offset, &font_console, gui.bootprompt.pixmap, p_prompt);
1687
1688gui.menu.draw = false;
1689gui.bootprompt.draw = true;
1690gui.redraw = true;
1691
1692updateVRAM();
1693
1694return;
1695}
1696
1697
1698static inline
1699void vramwrite (void *data, int width)
1700{
1701if (VIDEO (depth) == 0x20 /*32*/ && VIDEO (rowBytes) == (unsigned long)gui.backbuffer->width * 4)
1702memcpy((uint8_t *)vram, gui.backbuffer->pixels, VIDEO (rowBytes)*VIDEO (height));
1703else
1704{
1705uint32_t r, g, b;
1706uint32_t i, j;
1707for (i = 0; i < VIDEO (height); i++)
1708for (j = 0; j < VIDEO (width); j++)
1709{
1710b = ((uint8_t *) data)[4*i*width + 4*j];
1711g = ((uint8_t *) data)[4*i*width + 4*j + 1];
1712r = ((uint8_t *) data)[4*i*width + 4*j + 2];
1713switch (VIDEO (depth))
1714{
1715case 32:
1716*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*4) = (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);
1717break;
1718case 24:
1719*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*3) = ((*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*3))&0xff000000)
1720| (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);
1721break;
1722case 16:
1723// Somehow 16-bit is always 15-bits really
1724//*(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xfc)<<3) | ((r&0xf8)<<8);
1725//break;
1726case 15:
1727*(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xf8)<<2) | ((r&0xf8)<<7);
1728break;
1729default:
1730break;
1731}
1732}
1733}
1734}
1735
1736void updateVRAM()
1737{
1738if (gui.redraw)
1739{
1740if (gui.devicelist.draw)
1741blend( gui.devicelist.pixmap, gui.backbuffer, gui.devicelist.pos );
1742
1743if (gui.bootprompt.draw)
1744blend( gui.bootprompt.pixmap, gui.backbuffer, gui.bootprompt.pos );
1745
1746if (gui.menu.draw)
1747blend( gui.menu.pixmap, gui.backbuffer, gui.menu.pos );
1748
1749if (gui.infobox.draw)
1750blend( gui.infobox.pixmap, gui.backbuffer, gui.infobox.pos );
1751}
1752
1753vramwrite ( gui.backbuffer->pixels, gui.backbuffer->width );
1754
1755if (gui.redraw)
1756{
1757memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
1758gui.redraw = false;
1759}
1760}
1761
1762static void
1763sputc(int c, struct putc_info * pi)
1764{
1765 if (pi->last_str)
1766 if (pi->str == pi->last_str) {
1767 *(pi->str) = '\0';
1768 return;
1769 }
1770 *(pi->str)++ = c;
1771}
1772
1773int gprintf( window_t * window, const char * fmt, ...)
1774{
1775char *formattedtext;
1776
1777va_list ap;
1778
1779struct putc_info pi;
1780
1781if ((formattedtext = malloc(1024)) != NULL) {
1782// format the text
1783va_start(ap, fmt);
1784pi.str = formattedtext;
1785pi.last_str = 0;
1786prf(fmt, ap, sputc, &pi);
1787*pi.str = '\0';
1788va_end(ap);
1789
1790position_torigin, cursor, bounds;
1791
1792int i;
1793int character;
1794
1795origin.x = MAX( window->cursor.x, window->hborder );
1796origin.y = MAX( window->cursor.y, window->vborder );
1797
1798bounds.x = ( window->width - window->hborder );
1799bounds.y = ( window->height - window->vborder );
1800
1801cursor = origin;
1802
1803font_t *font = &font_console;
1804
1805for( i=0; i< strlen(formattedtext); i++ )
1806{
1807character = formattedtext[i];
1808
1809character -= 32;
1810
1811// newline ?
1812if( formattedtext[i] == '\n' )
1813{
1814cursor.x = window->hborder;
1815cursor.y += font->height;
1816
1817if ( cursor.y > bounds.y )
1818cursor.y = origin.y;
1819
1820continue;
1821}
1822
1823// tab ?
1824if( formattedtext[i] == '\t' )
1825cursor.x += ( font->chars[0]->width * 5 );
1826
1827// draw the character
1828if( font->chars[character])
1829blend(font->chars[character], window->pixmap, cursor);
1830
1831cursor.x += font->chars[character]->width;
1832
1833// check x pos and do newline
1834if ( cursor.x > bounds.x )
1835{
1836cursor.x = origin.x;
1837cursor.y += font->height;
1838}
1839
1840// check y pos and reset to origin.y
1841if ( cursor.y > bounds.y )
1842cursor.y = origin.y;
1843}
1844
1845// update cursor postition
1846window->cursor = cursor;
1847
1848free(formattedtext);
1849
1850return 0;
1851
1852}
1853return 1;
1854}
1855#if DEBUG_GUI
1856static int dprintf( window_t * window, const char * fmt, ...)
1857{
1858char *formattedtext;
1859
1860va_list ap;
1861
1862//window = &gui.debug;
1863
1864struct putc_info pi;
1865
1866if ((formattedtext = malloc(1024)) != NULL) {
1867// format the text
1868va_start(ap, fmt);
1869pi.str = formattedtext;
1870pi.last_str = 0;
1871prf(fmt, ap, sputc, &pi);
1872*pi.str = '\0';
1873va_end(ap);
1874
1875position_torigin, cursor, bounds;
1876
1877int i;
1878int character;
1879
1880origin.x = MAX( gui.debug.cursor.x, window->hborder );
1881origin.y = MAX( gui.debug.cursor.y, window->vborder );
1882
1883bounds.x = ( window->width - window->hborder );
1884bounds.y = ( window->height - window->vborder );
1885
1886cursor = origin;
1887
1888font_t *font = &font_console;
1889
1890for( i=0; i< strlen(formattedtext); i++ )
1891{
1892character = formattedtext[i];
1893
1894character -= 32;
1895
1896// newline ?
1897if( formattedtext[i] == '\n' )
1898{
1899cursor.x = window->hborder;
1900cursor.y += font->height;
1901
1902if ( cursor.y > bounds.y )
1903cursor.y = origin.y;
1904
1905continue;
1906}
1907
1908// tab ?
1909if( formattedtext[i] == '\t' )
1910cursor.x += ( font->chars[0]->width * 5 );
1911
1912// draw the character
1913if( font->chars[character])
1914blend(font->chars[character], gui.backbuffer, cursor);
1915
1916cursor.x += font->chars[character]->width;
1917
1918// check x pos and do newline
1919if ( cursor.x > bounds.x )
1920{
1921cursor.x = origin.x;
1922cursor.y += font->height;
1923}
1924
1925// check y pos and reset to origin.y
1926if ( cursor.y > bounds.y )
1927cursor.y = origin.y;
1928}
1929
1930// update cursor postition
1931gui.debug.cursor = cursor;
1932
1933free(formattedtext);
1934
1935return 0;
1936
1937}
1938return 1;
1939}
1940#endif
1941int vprf(const char * fmt, va_list ap)
1942{
1943int i;
1944int character;
1945
1946char *formattedtext;
1947window_t *window = &gui.screen;
1948struct putc_info pi;
1949
1950position_torigin, cursor, bounds;
1951font_t *font = &font_console;
1952
1953if ((formattedtext = malloc(1024)) != NULL) {
1954// format the text
1955pi.str = formattedtext;
1956pi.last_str = 0;
1957prf(fmt, ap, sputc, &pi);
1958*pi.str = '\0';
1959
1960origin.x = MAX( window->cursor.x, window->hborder );
1961origin.y = MAX( window->cursor.y, window->vborder );
1962bounds.x = ( window->width - ( window->hborder * 2 ) );
1963bounds.y = ( window->height - ( window->vborder * 2 ) );
1964cursor = origin;
1965
1966for( i=0; i< strlen(formattedtext); i++ )
1967{
1968character = formattedtext[i];
1969character -= 32;
1970
1971// newline ?
1972if( formattedtext[i] == '\n' )
1973{
1974cursor.x = window->hborder;
1975cursor.y += font->height;
1976if ( cursor.y > bounds.y )
1977{
1978gui.redraw = true;
1979updateVRAM();
1980cursor.y = window->vborder;
1981}
1982window->cursor.y = cursor.y;
1983continue;
1984}
1985
1986// tab ?
1987if( formattedtext[i] == '\t' )
1988{
1989cursor.x = ( cursor.x / ( font->chars[0]->width * 8 ) + 1 ) * ( font->chars[0]->width * 8 );
1990continue;
1991}
1992cursor.x += font->chars[character]->width;
1993
1994// check x pos and do newline
1995if ( cursor.x > bounds.x )
1996{
1997cursor.x = origin.x;
1998cursor.y += font->height;
1999}
2000
2001// check y pos and reset to origin.y
2002if ( cursor.y > ( bounds.y + font->chars[0]->height) )
2003{
2004gui.redraw = true;
2005updateVRAM();
2006cursor.y = window->vborder;
2007}
2008// draw the character
2009if( font->chars[character])
2010blend(font->chars[character], gui.backbuffer, cursor);
2011}
2012// save cursor postition
2013window->cursor.x = cursor.x;
2014updateVRAM();
2015free(formattedtext);
2016return 0;
2017}
2018return 1;
2019}
2020
2021pixmap_t* charToPixmap(unsigned char ch, font_t *font) {
2022unsigned int cha = (unsigned int)ch - 32;
2023if (cha >= font->count)
2024// return ? if the font for the char doesn't exists
2025cha = '?' - 32;
2026return font->chars[cha] ? font->chars[cha] : NULL;
2027}
2028
2029static position_t drawChar(unsigned char ch, font_t *font, pixmap_t *blendInto, position_t p) {
2030pixmap_t* pm = charToPixmap(ch, font);
2031if (pm && ((p.x + pm->width) < blendInto->width))
2032{
2033blend(pm, blendInto, p);
2034return pos(p.x + pm->width, p.y);
2035}
2036else
2037return p;
2038}
2039
2040static void drawStr(char *ch, font_t *font, pixmap_t *blendInto, position_t p)
2041{
2042int i=0;
2043position_t current_pos = pos(p.x, p.y);
2044
2045for (i=0; i < strlen(ch); i++)
2046{
2047// newline ?
2048if ( ch[i] == '\n' )
2049{
2050current_pos.x = p.x;
2051current_pos.y += font->height;
2052continue;
2053}
2054
2055// tab ?
2056if ( ch[i] == '\t' )
2057{
2058current_pos.x += TAB_PIXELS_WIDTH;
2059continue;
2060}
2061
2062current_pos = drawChar(ch[i], font, blendInto, current_pos);
2063}
2064}
2065
2066static void drawStrCenteredAt(char *text, font_t *font, pixmap_t *blendInto, position_t p)
2067{
2068int i = 0;
2069int width = 0;
2070int max_width = 0;
2071int height = font->height;
2072
2073// calculate the width in pixels
2074for (i=0; i < strlen(text); i++) {
2075if (text[i] == '\n')
2076{
2077width = 0;
2078height += font->height;
2079}
2080else if (text[i] == '\t')
2081width += TAB_PIXELS_WIDTH;
2082else
2083{
2084pixmap_t* pm = charToPixmap(text[i], font);
2085if (pm)
2086width += pm->width;
2087}
2088if (width > max_width)
2089max_width = width;
2090}
2091
2092p.x = ( p.x - ( max_width / 2 ) );
2093p.y = ( p.y - ( height / 2 ) );
2094
2095drawStr(text, font, blendInto, p);
2096}
2097
2098static int destroyFont(font_t *font)
2099{
2100int i;
2101 for (i = 0; i < CHARACTERS_COUNT; i++)
2102 {
2103if (font->chars[i])
2104{
2105if (font->chars[i]->pixels) free (font->chars[i]->pixels);
2106free (font->chars[i]);
2107font->chars[i] = 0;
2108}
2109 }
2110 return 0;
2111}
2112
2113static int initFont(font_t *font, image_t *data)
2114{
2115unsigned int x = 0, y = 0, x2 = 0, x3 = 0;
2116
2117int start = 0, end = 0, count = 0, space = 0;
2118
2119bool monospaced = false;
2120
2121font->height = data->image->height;
2122
2123for( x = 0; x < data->image->width && count < CHARACTERS_COUNT; x++)
2124{
2125start = end;
2126
2127// if the pixel is red we've reached the end of the char
2128if( pixel( data->image, x, 0 ).value == 0xFFFF0000)
2129{
2130end = x + 1;
2131
2132if( (font->chars[count] = malloc(sizeof(pixmap_t)) ) )
2133{
2134font->chars[count]->width = ( end - start) - 1;
2135font->chars[count]->height = font->height;
2136{
2137 int pixels_size = (font->chars[count]->width * data->image->height * 4);
2138
2139 if (!(pixels_size > 0))
2140 {
2141 continue;
2142 }
2143
2144 if ( !( font->chars[count]->pixels = malloc( pixels_size ) ) )
2145 {
2146 continue;
2147 }
2148
2149space += pixels_size;
2150 }
2151// we skip the first line because there are just the red pixels for the char width
2152 for( y = 1; y< (font->height); y++)
2153 {
2154 for( x2 = (unsigned)start, x3 = 0; x2 < (unsigned)end; x2++, x3++)
2155 {
2156 pixel( font->chars[count], x3, y ) = pixel( data->image, x2, y );
2157 }
2158 }
2159
2160 // check if font is monospaced
2161 if( ( count > 0 ) && ( font->width != font->chars[count]->width ) )
2162 monospaced = true;
2163
2164 font->width = font->chars[count]->width;
2165
2166 count++;
2167
2168}
2169}
2170}
2171
2172for (x = count; x < CHARACTERS_COUNT; x++)
2173font->chars[x] = NULL;
2174
2175if(monospaced)
2176font->width = 0;
2177
2178font->count = count;
2179
2180return 0;
2181}
2182
2183static void colorFont(font_t *font, uint32_t color)
2184{
2185if( !color )
2186return;
2187
2188int x, y, width, height;
2189int count = 0;
2190pixel_t *buff;
2191
2192while( font->chars[count++] )
2193{
2194width = font->chars[count-1]->width;
2195height = font->chars[count-1]->height;
2196for( y = 0; y < height; y++ )
2197{
2198for( x = 0; x < width; x++ )
2199{
2200buff = &(pixel( font->chars[count-1], x, y ));
2201if( buff->ch.a )
2202{
2203buff->ch.r = (color & 0xFFFF0000) >> 16;
2204buff->ch.g = (color & 0xFF00FF00) >> 8;
2205buff->ch.b = (color & 0xFF0000FF);
2206}
2207}
2208}
2209}
2210}
2211
2212static void makeRoundedCorners(pixmap_t *p)
2213{
2214int x,y;
2215int width=p->width-1;
2216int height=p->height-1;
2217
2218// 10px rounded corner alpha values
2219uint8_t roundedCorner[10][10] =
2220{
2221{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0xC0, 0xFF},
2222{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF},
2223{ 0x00, 0x00, 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2224{ 0x00, 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2225{ 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2226{ 0x00, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2227{ 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2228{ 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2229{ 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
2230{ 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
2231};
2232
2233uint8_t alpha=0;
2234
2235for( y=0; y<10; y++)
2236{
2237for( x=0; x<10; x++)
2238{
2239// skip if the pixel should be visible
2240if(roundedCorner[y][x] != 0xFF)
2241{
2242alpha = ( roundedCorner[y][x] ? (uint8_t) (roundedCorner[y][x] * pixel(p, x, y).ch.a) / 255 : 0 );
2243// Upper left corner
2244pixel(p, x, y).ch.a = alpha;
2245
2246// upper right corner
2247pixel(p, width-x,y).ch.a = alpha;
2248
2249// lower left corner
2250pixel(p, x, height-y).ch.a = alpha;
2251
2252// lower right corner
2253pixel(p, width-x, height-y).ch.a = alpha;
2254}
2255}
2256}
2257}
2258
2259void showInfoBox(char *title, char *text)
2260{
2261int i, key, lines, visiblelines;
2262
2263int currentline=0;
2264int cnt=0;
2265int offset=0;
2266
2267if( !title || !text )
2268return;
2269
2270position_t pos_title = pos ( gui.infobox.vborder, gui.infobox.vborder );
2271
2272// calculate number of lines in the title
2273for ( i = 0, lines = 1; i<strlen(title); i++ )
2274if( title[i] == '\n')
2275lines++;
2276
2277// y position of text is lines in title * height of font
2278position_t pos_text = pos( pos_title.x , pos_title.y + ( font_console.height * lines ));
2279
2280// calculate number of lines in the text
2281for ( i=0, lines = 1; i<strlen(text); i++ )
2282if( text[i] == '\n')
2283lines++;
2284
2285// if text ends with \n strip off
2286if( text[i] == '\n' || text[i] == '\0')
2287lines--;
2288
2289visiblelines = ( ( gui.infobox.height - ( gui.infobox.vborder * 2 ) ) / font_console.height ) - 1;
2290
2291// lets display the text and allow scroll thru using up down / arrows
2292while(1)
2293{
2294// move to current line in text
2295for( offset = 0, i = 0; offset < strlen(text); offset++ )
2296{
2297if( currentline == i)
2298break;
2299if( text[offset] =='\n')
2300i++;
2301}
2302
2303// find last visible line in text and place \0
2304for( i = offset, cnt = 0; i < strlen(text); i++)
2305{
2306if(text[i]=='\n')
2307cnt++;
2308if ( cnt == visiblelines )
2309{
2310text[i]='\0';
2311break;
2312}
2313}
2314
2315fillPixmapWithColor( gui.infobox.pixmap, gui.infobox.bgcolor);
2316
2317makeRoundedCorners( gui.infobox.pixmap);
2318
2319// print the title if present
2320if( title )
2321drawStr(title, &font_console, gui.infobox.pixmap, pos_title);
2322
2323// print the text
2324drawStr( text + offset, &font_console, gui.infobox.pixmap, pos_text);
2325
2326// restore \n in text
2327if ( cnt == visiblelines )
2328text[i] = '\n';
2329
2330position_t pos_indicator = pos( gui.infobox.width - ( images[iTextScrollPrev].image->width - ( gui.infobox.vborder / 2) ), pos_text.y );
2331
2332// draw prev indicator
2333if(offset)
2334{
2335blend( images[iTextScrollPrev].image, gui.infobox.pixmap, centeredAt( images[iTextScrollPrev].image, pos_indicator ));
2336}
2337
2338// draw next indicator
2339if( lines > ( currentline + visiblelines ) )
2340{
2341pos_indicator.y = ( gui.infobox.height - ( ( images[iTextScrollNext].image->width + gui.infobox.vborder ) / 2 ) );
2342blend( images[iTextScrollNext].image, gui.infobox.pixmap, centeredAt( images[iTextScrollNext].image, pos_indicator ) );
2343}
2344
2345gui.bootprompt.draw = false;
2346gui.infobox.draw = true;
2347gui.redraw = true;
2348
2349updateVRAM();
2350
2351key = getc();
2352
2353if( key == kUpArrowkey )
2354if( currentline > 0 )
2355currentline--;
2356
2357if( key == kDownArrowkey )
2358if( lines > ( currentline + visiblelines ) )
2359currentline++;
2360
2361if( key == kEscapeKey || key == 'q' || key == 'Q')
2362{
2363gui.infobox.draw = false;
2364gui.redraw = true;
2365updateVRAM();
2366break;
2367}
2368}
2369}
2370
2371static void animateProgressBar()
2372{
2373int y;
2374
2375if( time18() > (unsigned) lasttime)
2376{
2377lasttime = time18();
2378
2379pixmap_t *buffBar = images[iProgressBar].image;
2380
2381uint32_t buff = buffBar->pixels[0].value;
2382
2383memcpy( buffBar->pixels, buffBar->pixels + 1, ( (buffBar->width*buffBar->height) - 1 ) * 4 );
2384
2385for( y = buffBar->height - 1; y > 0; y--)
2386pixel(buffBar, buffBar->width - 1, y) = pixel(buffBar, buffBar->width - 1, y - 1);
2387
2388pixel(buffBar, buffBar->width-1, 0).value = buff;
2389}
2390}
2391
2392static void drawProgressBar(pixmap_t *blendInto, uint16_t width, position_t p, uint8_t progress)
2393{
2394if(progress>100)
2395return;
2396
2397p.x = ( p.x - ( width / 2 ) );
2398
2399int todraw = (width * progress) / 100;
2400
2401pixmap_t *buff = images[iProgressBar].image;
2402pixmap_t *buffBG = images[iProgressBarBackground].image;
2403if(!buff || !buffBG)
2404return;
2405
2406pixmap_t progressbar;
2407progressbar.pixels=malloc(width * 4 * buff->height);
2408if(!progressbar.pixels)
2409return;
2410
2411progressbar.width = width;
2412progressbar.height = buff->height;
2413
2414int x,x2,y;
2415
2416for(y=0; y<buff->height; y++)
2417{
2418for(x=0,x2=0; x<todraw; x++, x2++)
2419{
2420if(x2 == (buff->width-1)) x2=0;
2421pixel(&progressbar, x,y).value = pixel(buff, x2,y).value;
2422}
2423}
2424
2425for(y=0; y<buff->height; y++)
2426{
2427for(x=todraw, x2 = 0; x < width - 1; x++, x2++)
2428{
2429if(x2 == (buffBG->width -2 )) x2 = 0;
2430pixel(&progressbar, x,y).value = pixel(buffBG, x2,y).value;
2431}
2432if(progress < 100)
2433pixel(&progressbar, width - 1, y).value = pixel(buffBG, buffBG->width - 1, y).value;
2434if(progress == 0)
2435pixel(&progressbar, 0, y).value = pixel(buffBG, buffBG->width - 1, y).value;
2436}
2437
2438blend(&progressbar, blendInto, p);
2439animateProgressBar();
2440free(progressbar.pixels);
2441}
2442
2443static void drawInfoMenuItems()
2444{
2445int i,n;
2446
2447position_t position;
2448
2449pixmap_t *selection = images[iMenuSelection].image;
2450
2451pixmap_t *pbuff;
2452
2453fillPixmapWithColor(gui.menu.pixmap, gui.menu.bgcolor);
2454
2455makeRoundedCorners(gui.menu.pixmap);
2456
2457uint8_t offset = infoMenuNativeBoot ? 0 : infoMenuItemsCount - 1;
2458
2459position = pos(0,0);
2460
2461for ( i = 0, n = iMenuBoot; i < infoMenuItemsCount; i++, n++)
2462{
2463if (i == infoMenuSelection)
2464{
2465blend(selection, gui.menu.pixmap, position);
2466}
2467
2468pbuff = images[n].image;
2469if (offset && i >= INFOMENU_NATIVEBOOT_START && i <= INFOMENU_NATIVEBOOT_END)
2470{
2471blend( images[n + (iMenuHelp - iMenuBoot)].image , gui.menu.pixmap,
2472 pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2)));
2473}
2474else
2475{
2476blend( pbuff, gui.menu.pixmap,
2477 pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2)));
2478}
2479
2480drawStr(infoMenuItems[i].text, &font_console, gui.menu.pixmap,
2481pos(position.x + (pbuff->width + gui.menu.hborder),
2482position.y + ((selection->height - font_console.height) / 2)));
2483position.y += images[iMenuSelection].image->height;
2484
2485}
2486
2487gui.redraw = true;
2488}
2489
2490int drawInfoMenu()
2491{
2492drawInfoMenuItems();
2493
2494gui.menu.draw = true;
2495
2496updateVRAM();
2497
2498return 1;
2499}
2500
2501int updateInfoMenu(int key)
2502{
2503switch (key)
2504{
2505
2506case kUpArrowkey:// up arrow
2507if (infoMenuSelection > 0)
2508{
2509if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_END + 1)
2510{
2511infoMenuSelection -= 4;
2512}
2513else
2514{
2515infoMenuSelection--;
2516}
2517drawInfoMenuItems();
2518updateVRAM();
2519
2520}
2521else
2522{
2523
2524gui.menu.draw = false;
2525gui.redraw = true;
2526
2527updateVRAM();
2528
2529return CLOSE_INFO_MENU;
2530}
2531break;
2532
2533case kDownArrowkey:// down arrow
2534if (infoMenuSelection < infoMenuItemsCount - 1)
2535{
2536if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_START - 1)
2537infoMenuSelection += 4;
2538else
2539infoMenuSelection++;
2540drawInfoMenuItems();
2541updateVRAM();
2542}
2543break;
2544
2545case kReturnKey:
2546if( infoMenuSelection == MENU_SHOW_MEMORY_INFO )
2547showInfoBox( "Memory Info. Press q to quit.\n", getMemoryInfoString());
2548
2549else if( infoMenuSelection == MENU_SHOW_VIDEO_INFO )
2550showInfoBox( getVBEInfoString(), getVBEModeInfoString() );
2551
2552else if( infoMenuSelection == MENU_SHOW_HELP )
2553showHelp();
2554
2555else
2556{
2557int buff = infoMenuSelection;
2558infoMenuSelection = 0;
2559return buff;
2560}
2561break;
2562default:
2563break;
2564}
2565return DO_NOT_BOOT;
2566}
2567
2568uint16_t bootImageWidth = 0;
2569uint16_t bootImageHeight = 0;
2570uint8_t *bootImageData = NULL;
2571static bool usePngImage = false;
2572
2573//==========================================================================
2574// loadBootGraphics
2575static void loadBootGraphics(char *src)
2576{
2577if (bootImageData != NULL) {
2578return;
2579}
2580
2581char dirspec[256];
2582
2583if ((unsigned)(strlen(theme_name) + 34) > sizeof(dirspec)) {
2584usePngImage = false;
2585return;
2586}
2587sprintf(dirspec, "%s/%s/boot.png", src, theme_name);
2588if (strlen(theme_name) == 0 || loadPngImage(dirspec, &bootImageWidth, &bootImageHeight, &bootImageData) != 0) {
2589#ifdef EMBED_THEME
2590if ((loadEmbeddedPngImage(__boot_png, __boot_png_len, &bootImageWidth, &bootImageHeight, &bootImageData)) != 0)
2591#endif
2592usePngImage = false;
2593}
2594}
2595
2596//==========================================================================
2597// drawBootGraphics
2598void drawBootGraphics(void)
2599{
2600int pos;
2601int length;
2602const char *dummyVal;
2603int oldScreenWidth, oldScreenHeight;
2604uint16_t x, y;
2605bool legacy_logo = false;
2606getBoolForKey("Legacy Logo", &legacy_logo, DEFAULT_BOOT_CONFIG);
2607if (legacy_logo == false) {
2608usePngImage = true;
2609
2610if (bootImageData == NULL)
2611loadBootGraphics(dirsrc);
2612
2613}
2614
2615
2616if (execute_hook("getResolution_hook", &screen_params[0], &screen_params[1], &screen_params[2], NULL, NULL, NULL) != EFI_SUCCESS)
2617{
2618// parse screen size parameters
2619if (getIntForKey("boot_width", &pos, &themeConfig) && pos > 0) {
2620screen_params[0] = pos;
2621} else {
2622screen_params[0] = DEFAULT_SCREEN_WIDTH;
2623}
2624if (getIntForKey("boot_height", &pos, &themeConfig) && pos > 0) {
2625screen_params[1] = pos;
2626} else {
2627screen_params[1] = DEFAULT_SCREEN_HEIGHT;
2628}
2629}
2630
2631 // Save current screen resolution.
2632oldScreenWidth = gui.screen.width;
2633oldScreenHeight = gui.screen.height;
2634
2635gui.screen.width = screen_params[0];
2636gui.screen.height = screen_params[1];
2637
2638// find best matching vesa mode for our requested width & height
2639getGraphicModeParams(screen_params);
2640
2641 // Set graphics mode if the booter was in text mode or the screen resolution has changed.
2642if (getVideoMode() == VGA_TEXT_MODE
2643|| (screen_params[0] != (uint32_t)oldScreenWidth && screen_params[1] != (uint32_t)oldScreenHeight) )
2644{
2645
2646setVideoMode(GRAPHICS_MODE);
2647
2648}
2649
2650if (getValueForKey("-checkers", &dummyVal, &length, DEFAULT_BOOT_CONFIG)) {
2651drawCheckerBoard();
2652} else {
2653// Fill the background to 75% grey (same as BootX).
2654drawColorRectangle(0, 0, screen_params[0], screen_params[1], 0x01);
2655}
2656if ((bootImageData) && (usePngImage)) {
2657x = (screen_params[0] - MIN(bootImageWidth, screen_params[0])) / 2;
2658y = (screen_params[1] - MIN(bootImageHeight, screen_params[1])) / 2;
2659
2660// Draw the image in the center of the display.
2661blendImage(x, y, bootImageWidth, bootImageHeight, bootImageData);
2662} else {
2663uint8_t *appleBootPict;
2664bootImageData = NULL;
2665bootImageWidth = kAppleBootWidth;
2666bootImageHeight = kAppleBootHeight;
2667
2668// Prepare the data for the default Apple boot image.
2669appleBootPict = (uint8_t *) decodeRLE(gAppleBootPictRLE, kAppleBootRLEBlocks, bootImageWidth * bootImageHeight);
2670if (appleBootPict) {
2671if (convertImage(bootImageWidth, bootImageHeight, appleBootPict, &bootImageData) == 0)
2672 {
2673 if (bootImageData) {
2674 x = (screen_params[0] - MIN(kAppleBootWidth, screen_params[0])) / 2;
2675 y = (screen_params[1] - MIN(kAppleBootHeight, screen_params[1])) / 2;
2676 drawDataRectangle(x, y, kAppleBootWidth, kAppleBootHeight, bootImageData);
2677 free(bootImageData);
2678 }
2679 }
2680free(appleBootPict);
2681}
2682}
2683}
2684
2685int GUI_initGraphicsMode (void)
2686{
2687unsigned long params[4];
2688int count;
2689
2690params[3] = 0;
2691count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
2692
2693// Try to find a resolution if "Graphics Mode" setting is not available.
2694if ( count < 3 )
2695{
2696// Use the default resolution if we don't have an initialized GUI.
2697if (gui.screen.width == 0 || gui.screen.height == 0)
2698{
2699gui.screen.width = DEFAULT_SCREEN_WIDTH;
2700gui.screen.height = DEFAULT_SCREEN_HEIGHT;
2701}
2702
2703params[0] = gui.screen.width;
2704params[1] = gui.screen.height;
2705params[2] = 32;
2706}
2707
2708// Map from pixel format to bits per pixel.
2709
2710if ( params[2] == 256 ) params[2] = 8;
2711if ( params[2] == 555 ) params[2] = 16;
2712if ( params[2] == 888 ) params[2] = 32;
2713
2714return setVESAGraphicsMode( params[0], params[1], params[2] );
2715
2716}
2717
2718
2719int GUI_countdown( const char * msg, register int row, register int timeout , int *optionKey)
2720{
2721 register unsigned long time;
2722 int ch = 0;
2723 register int col = strlen(msg) + 1;
2724
2725 flushKeyboardBuffer();
2726
2727if( getVideoMode() == VGA_TEXT_MODE )
2728{
2729moveCursor( 0, row );
2730printf(msg);
2731
2732} else {
2733
2734position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
2735
2736char dummy[80];
2737getBootVolumeDescription( ((BVRef)(uint32_t)get_env(envgBootVolume)), dummy, sizeof(dummy) - 1, true );
2738drawDeviceIcon( ((BVRef)(uint32_t)get_env(envgBootVolume)), gui.screen.pixmap, p, true );
2739drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
2740
2741// make this screen the new background
2742memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
2743
2744}
2745
2746int multi_buff = 18 * (timeout);
2747 int multi = ++multi_buff;
2748
2749 int lasttime=0;
2750
2751 for ( time = time18(), timeout++; timeout > 0; )
2752 {
2753
2754if( time18() > (unsigned)lasttime)
2755{
2756multi--;
2757lasttime=time18();
2758}
2759
2760 if ((ch = readKeyboardStatus())){
2761 *optionKey = ch;
2762 break;
2763}
2764
2765 // Count can be interrupted by holding down shift,
2766 // control or alt key
2767 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
2768{
2769 ch = 1;
2770 break;
2771 }
2772
2773 if ( time18() >= time )
2774 {
2775 time += 18;
2776 timeout--;
2777
2778if( getVideoMode() == VGA_TEXT_MODE )
2779{
2780moveCursor( col, row );
2781printf("(%d) ", timeout);
2782}
2783 }
2784
2785if( getVideoMode() == GRAPHICS_MODE )
2786{
2787drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
2788gui.redraw = true;
2789updateVRAM();
2790}
2791
2792 }
2793
2794 flushKeyboardBuffer();
2795
2796 return ch;
2797}
2798

Archive Download this file

Revision: 1972