Chameleon

Chameleon Svn Source Tree

Root/branches/slice/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#include "gui.h"
12#include "appleboot.h"
13#include "vers.h"
14#include "modules.h"
15#include "../Resolution/edid.h"
16
17#ifndef DEBUG_GUI
18#define DEBUG_GUI 1
19#endif
20
21#if DEBUG_GUI
22#define DBG(x...)verbose(x) //;getc()
23#else
24#define DBG(x...)msglog(x)
25#endif
26
27
28
29gui_t gui;// gui structure
30font_t font_small;
31font_t font_console;
32
33
34#define IMG_REQUIRED -1
35#define THEME_NAME_DEFAULT"Default"
36const char* theme_name = THEME_NAME_DEFAULT;
37
38#ifdef EMBED_THEME
39#include "art.h"
40#endif
41
42#define LOADPNG(img, alt_img) if (loadThemeImage(#img, alt_img) != 0) { return 1; }
43
44#define MIN(x, y) ((x) < (y) ? (x) : (y))
45#define MAX(x, y) ((x) > (y) ? (x) : (y))
46
47#define VIDEO(x) (bootArgs->Video.v_ ## x)
48
49#define vram VIDEO(baseAddr)
50
51int lasttime = 0; // we need this for animating maybe
52
53extern int gDeviceCount;
54
55
56/*
57 * ATTENTION: the enum and the following array images[] MUST match !!!
58 */
59enum {
60 iBackground = 0,
61 iLogo,
62
63 iDeviceGeneric,
64 iDeviceGeneric_o,
65 iDeviceHFS,
66 iDeviceHFS_o,
67 iDeviceHFSRAID,
68 iDeviceHFSRAID_o,
69 iDeviceEXT3,
70 iDeviceEXT3_o,
71 iDeviceFAT,
72 iDeviceFAT_o,
73 iDeviceFAT16,
74 iDeviceFAT16_o,
75 iDeviceFAT32,
76 iDeviceFAT32_o,
77 iDeviceNTFS,
78 iDeviceNTFS_o,
79 iDeviceCDROM,
80 iDeviceCDROM_o,
81
82 iSelection,
83 iDeviceScrollPrev,
84 iDeviceScrollNext,
85
86 iMenuBoot,
87 iMenuVerbose,
88 iMenuIgnoreCaches,
89 iMenuSingleUser,
90 iMenuMemoryInfo,
91 iMenuVideoInfo,
92 iMenuHelp,
93 iMenuVerboseDisabled,
94 iMenuIgnoreCachesDisabled,
95 iMenuSingleUserDisabled,
96 iMenuSelection,
97
98 iProgressBar,
99 iProgressBarBackground,
100
101 iTextScrollPrev,
102 iTextScrollNext,
103
104 iFontConsole,
105 iFontSmall,
106};
107
108image_t images[] = {
109 {.name = "background", .image = NULL},
110 {.name = "logo", .image = NULL},
111
112 {.name = "device_generic", .image = NULL},
113 {.name = "device_generic_o", .image = NULL},
114 {.name = "device_hfsplus", .image = NULL},
115 {.name = "device_hfsplus_o", .image = NULL},
116 {.name = "device_hfsraid", .image = NULL},
117 {.name = "device_hfsraid_o", .image = NULL},
118 {.name = "device_ext3", .image = NULL},
119 {.name = "device_ext3_o", .image = NULL},
120 {.name = "device_fat", .image = NULL},
121 {.name = "device_fat_o", .image = NULL},
122 {.name = "device_fat16", .image = NULL},
123 {.name = "device_fat16_o", .image = NULL},
124 {.name = "device_fat32", .image = NULL},
125 {.name = "device_fat32_o", .image = NULL},
126 {.name = "device_ntfs", .image = NULL},
127 {.name = "device_ntfs_o", .image = NULL},
128 {.name = "device_cdrom", .image = NULL},
129 {.name = "device_cdrom_o", .image = NULL},
130
131 {.name = "device_selection", .image = NULL},
132 {.name = "device_scroll_prev", .image = NULL},
133 {.name = "device_scroll_next", .image = NULL},
134
135 {.name = "menu_boot", .image = NULL},
136 {.name = "menu_verbose", .image = NULL},
137 {.name = "menu_ignore_caches", .image = NULL},
138 {.name = "menu_single_user", .image = NULL},
139 {.name = "menu_memory_info", .image = NULL},
140 {.name = "menu_video_info", .image = NULL},
141 {.name = "menu_help", .image = NULL},
142 {.name = "menu_verbose_disabled", .image = NULL},
143 {.name = "menu_ignore_caches_disabled", .image = NULL},
144 {.name = "menu_single_user_disabled", .image = NULL},
145 {.name = "menu_selection", .image = NULL},
146
147 {.name = "progress_bar", .image = NULL},
148 {.name = "progress_bar_background", .image = NULL},
149
150 {.name = "text_scroll_prev", .image = NULL},
151 {.name = "text_scroll_next", .image = NULL},
152
153 {.name = "font_console", .image = NULL},
154 {.name = "font_small", .image = NULL},
155};
156
157int imageCnt = 0;
158
159extern intgDeviceCount;
160extern intselectIndex;
161
162char prompt[BOOT_STRING_LEN];
163
164int prompt_pos=0;
165
166char prompt_text[] = "boot: ";
167
168menuitem_t infoMenuItems[] =
169{
170{ .text = "Boot" },
171{ .text = "Boot Verbose" },
172{ .text = "Boot Ignore Caches" },
173//{ .text = "Boot Safe Mode" },
174{ .text = "Boot Single User" },
175{ .text = "Memory Info" },
176{ .text = "Video Info" },
177{ .text = "Help" }
178};
179
180int initFont(font_t *font, image_t *image);
181void colorFont(font_t *font, uint32_t color);
182void makeRoundedCorners(pixmap_t *p);
183
184int infoMenuSelection = 0;
185int infoMenuItemsCount = sizeof(infoMenuItems)/sizeof(infoMenuItems[0]);
186
187bool infoMenuNativeBoot = false;
188
189unsigned long screen_params[4] = {DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 32, 0};// here we store the used screen resolution
190
191int getImageIndexByName(const char *name)
192{
193 int i;
194for (i = 0; i < sizeof(images) / sizeof(images[0]); i++)
195{
196 if (strcmp(name, images[i].name) == 0)
197 return i; // found the name
198}
199return -1;
200}
201
202#ifdef EMBED_THEME
203static int getEmbeddedImageIndexByName(const char *name)
204{
205int upperLimit = sizeof(embeddedImages) / sizeof(embeddedImages[0]) - 1;
206int lowerLimit = 0;
207int compareIndex = (upperLimit - lowerLimit) >> 1; // Midpoint
208int result;
209
210// NOTE: This algorithm assumes that the embeddedImages is sorted.
211// This is currently done using the make file. If the array is every
212// manualy generated, this *will* fail to work properly.
213while((result = strcmp(name, embeddedImages[compareIndex].name)) != 0)
214{
215if(result > 0)// We need to search a HIGHER index
216{
217if(compareIndex != lowerLimit)
218{
219lowerLimit = compareIndex;
220}
221else
222{
223return -1;
224}
225compareIndex = (upperLimit + lowerLimit + 1) >> 1;// Midpoint, round up
226}
227else // We Need to search a LOWER index
228{
229if(compareIndex != upperLimit)
230{
231upperLimit = compareIndex;
232}
233else
234{
235return -1;
236}
237compareIndex = (upperLimit + lowerLimit) >> 1;// Midpoint, round down
238}
239}
240return compareIndex;
241}
242#endif
243
244static int loadThemeImage(const char *image, int alt_image)
245{
246chardirspec[256];
247int i;
248#ifdef EMBED_THEME
249int e;
250#endif
251uint16_twidth;
252uint16_theight;
253uint8_t*imagedata;
254if ((strlen(image) + strlen(theme_name) + 20 ) > sizeof(dirspec)) {
255return 1;
256}
257
258 if ((i = getImageIndexByName(image)) >= 0)
259 {
260 if (images[i].image == NULL) {
261 images[i].image = malloc(sizeof(pixmap_t));
262 }
263 sprintf(dirspec, "/Extra/Themes/%s/%s.png", theme_name, image);
264
265 width = 0;
266 height = 0;
267 imagedata = NULL;
268 if ((loadPngImage(dirspec, &width, &height, &imagedata)) == 0)
269 {
270 images[i].image->width = width;
271 images[i].image->height = height;
272 images[i].image->pixels = (pixel_t *)imagedata;
273 flipRB(images[i].image);
274 return 0;
275 }
276#ifdef EMBED_THEME
277 else if ((e = getEmbeddedImageIndexByName(image)) >= 0)
278 {
279 unsigned char *embed_data;
280 unsigned int embed_size;
281 embed_data = embeddedImages[e].pngdata;
282 embed_size = *embeddedImages[e].length;
283
284 if (loadEmbeddedPngImage(embed_data, embed_size, &width, &height, &imagedata) == 0)
285 {
286 images[i].image->width = width;
287 images[i].image->height = height;
288 images[i].image->pixels = (pixel_t *)imagedata;
289 flipRB(images[i].image);
290 return 0;
291 }
292
293 return 0;
294 }
295#endif
296 else if (alt_image != IMG_REQUIRED && images[alt_image].image->pixels != NULL)
297 {
298 // Using the passed alternate image for non-mandatory images.
299 // We don't clone the already existing pixmap, but using its properties instead!
300 images[i].image->width = images[alt_image].image->width;
301 images[i].image->height = images[alt_image].image->height;
302 images[i].image->pixels = images[alt_image].image->pixels;
303 return 0;
304 }
305 else
306 {
307#ifndef EMBED_THEME
308 printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
309sleep(2);
310#endif
311 return 1;
312 }
313 }
314
315return 1;
316}
317
318static int loadGraphics(void)
319{
320LOADPNG(background, IMG_REQUIRED);
321LOADPNG(logo, IMG_REQUIRED);
322
323LOADPNG(device_generic, IMG_REQUIRED);
324LOADPNG(device_generic_o, iDeviceGeneric);
325LOADPNG(device_hfsplus, iDeviceGeneric);
326LOADPNG(device_hfsplus_o, iDeviceHFS);
327LOADPNG(device_hfsraid, iDeviceGeneric);
328LOADPNG(device_hfsraid_o, iDeviceHFSRAID);
329LOADPNG(device_ext3, iDeviceGeneric);
330LOADPNG(device_ext3_o, iDeviceEXT3);
331LOADPNG(device_fat, iDeviceGeneric);
332LOADPNG(device_fat_o, iDeviceFAT);
333LOADPNG(device_fat16, iDeviceFAT);
334LOADPNG(device_fat16_o, iDeviceFAT_o);
335LOADPNG(device_fat32, iDeviceFAT);
336LOADPNG(device_fat32_o, iDeviceFAT_o);
337LOADPNG(device_ntfs, iDeviceGeneric);
338LOADPNG(device_ntfs_o, iDeviceNTFS);
339LOADPNG(device_cdrom, iDeviceGeneric);
340LOADPNG(device_cdrom_o, iDeviceCDROM);
341
342LOADPNG(device_selection, IMG_REQUIRED);
343LOADPNG(device_scroll_prev, IMG_REQUIRED);
344LOADPNG(device_scroll_next, IMG_REQUIRED);
345
346LOADPNG(menu_boot, IMG_REQUIRED);
347LOADPNG(menu_verbose, IMG_REQUIRED);
348LOADPNG(menu_ignore_caches, IMG_REQUIRED);
349LOADPNG(menu_single_user, IMG_REQUIRED);
350LOADPNG(menu_memory_info, IMG_REQUIRED);
351LOADPNG(menu_video_info, IMG_REQUIRED);
352LOADPNG(menu_help, IMG_REQUIRED);
353LOADPNG(menu_verbose_disabled, IMG_REQUIRED);
354LOADPNG(menu_ignore_caches_disabled, IMG_REQUIRED);
355LOADPNG(menu_single_user_disabled, IMG_REQUIRED);
356LOADPNG(menu_selection, IMG_REQUIRED);
357
358LOADPNG(progress_bar, IMG_REQUIRED);
359LOADPNG(progress_bar_background, IMG_REQUIRED);
360
361LOADPNG(text_scroll_prev, IMG_REQUIRED);
362LOADPNG(text_scroll_next, IMG_REQUIRED);
363
364LOADPNG(font_console, IMG_REQUIRED);
365LOADPNG(font_small, IMG_REQUIRED);
366
367initFont( &font_console, &images[iFontConsole]);
368initFont( &font_small, &images[iFontSmall]);
369
370return 0;
371}
372
373pixmap_t *getCroppedPixmapAtPosition( pixmap_t *from, position_t pos, uint16_t width, uint16_t height )
374{
375
376pixmap_t *cropped = malloc( sizeof( pixmap_t ) );
377if( !cropped )
378return 0;
379cropped->pixels = malloc( width * height * 4 );
380if ( !cropped->pixels )
381return 0;
382
383cropped->width = width;
384cropped->height = height;
385
386int destx = 0, desty = 0;
387int srcx = pos.x, srcy = pos.y;
388
389for( ; desty < height; desty++, srcy++)
390{
391for( destx = 0, srcx = pos.x; destx < width; destx++, srcx++ )
392{
393pixel( cropped, destx, desty ).value = pixel( from, srcx, srcy ).value;
394}
395}
396return cropped;
397}
398
399int createBackBuffer( window_t *window )
400{
401gui.backbuffer = malloc(sizeof(pixmap_t));
402if(!gui.backbuffer)
403return 1;
404
405gui.backbuffer->pixels = malloc( window->width * window->height * 4 );
406if(!gui.backbuffer->pixels)
407{
408free(gui.backbuffer);
409gui.backbuffer = 0;
410return 1;
411}
412
413gui.backbuffer->width = gui.screen.width;
414gui.backbuffer->height = gui.screen.height;
415//gui.backbuffer->width = window->width;
416//gui.backbuffer->height = window->height;
417
418return 0;
419}
420
421int createWindowBuffer( window_t *window )
422{
423window->pixmap = malloc(sizeof(pixmap_t));
424if(!window->pixmap)
425return 1;
426
427window->pixmap->pixels = malloc( window->width * window->height * 4 );
428if(!window->pixmap->pixels)
429{
430free(window->pixmap);
431window->pixmap = 0;
432return 1;
433}
434
435window->pixmap->width = window->width;
436window->pixmap->height = window->height;
437
438return 0;
439}
440
441int freeWindowBuffer( window_t *window )
442{
443if (window->pixmap && window->pixmap->pixels)
444 {
445free(window->pixmap->pixels);
446free(window->pixmap);
447return 0;
448}
449
450return 1;
451}
452
453void fillPixmapWithColor(pixmap_t *pm, uint32_t color)
454{
455int x,y;
456
457// fill with given color AARRGGBB
458for( x=0; x < pm->width; x++ )
459for( y=0; y< pm->height; y++)
460pixel(pm,x,y).value = color;
461}
462
463void drawBackground()
464{
465// reset text cursor
466gui.screen.cursor.x = gui.screen.hborder;
467gui.screen.cursor.y = gui.screen.vborder;
468
469fillPixmapWithColor( gui.screen.pixmap, gui.screen.bgcolor);
470
471// draw background.png into background buffer
472blend( images[iBackground].image, gui.screen.pixmap, gui.background.pos );
473
474// draw logo.png into background buffer
475if (gui.logo.draw)
476{
477 blend( images[iLogo].image, gui.screen.pixmap, gui.logo.pos);
478}
479
480memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
481}
482
483void setupDeviceList(config_file_t *theme)
484{
485unsigned int pixel;
486intalpha;// transparency level 0 (obligue) - 255 (transparent)
487uint32_t color;// color value formatted RRGGBB
488int val, len;
489const char *string;
490
491if(getIntForKey("devices_max_visible", &val, theme ))
492gui.maxdevices = MIN( val, gDeviceCount );
493
494if(getIntForKey("devices_iconspacing", &val, theme ))
495gui.devicelist.iconspacing = val;
496
497// check layout for horizontal or vertical
498gui.layout = HorizontalLayout;
499if(getValueForKey( "devices_layout", &string, &len, theme)) {
500if (!strcmp (string, "vertical")) {
501gui.layout = VerticalLayout;
502}
503}
504
505switch (gui.layout) {
506case VerticalLayout:
507gui.devicelist.height = ((images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing) * MIN(gui.maxdevices, gDeviceCount) + (images[iDeviceScrollPrev].image->height + images[iDeviceScrollNext].image->height) + gui.devicelist.iconspacing);
508gui.devicelist.width = (images[iSelection].image->width + gui.devicelist.iconspacing);
509
510if(getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , images[iSelection].image->width ) )
511gui.devicelist.pos.x = pixel;
512
513if(getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , gui.devicelist.height ) )
514gui.devicelist.pos.y = pixel;
515break;
516
517case HorizontalLayout:
518default:
519gui.devicelist.width = ((images[iSelection].image->width + gui.devicelist.iconspacing) * MIN(gui.maxdevices, gDeviceCount) + (images[iDeviceScrollPrev].image->width + images[iDeviceScrollNext].image->width) + gui.devicelist.iconspacing);
520gui.devicelist.height = (images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing);
521
522if(getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , gui.devicelist.width ) )
523gui.devicelist.pos.x = pixel;
524else
525gui.devicelist.pos.x = ( gui.screen.width - gui.devicelist.width ) / 2;
526
527if(getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , images[iSelection].image->height ) )
528gui.devicelist.pos.y = pixel;
529else
530gui.devicelist.pos.y = ( gui.screen.height - gui.devicelist.height ) / 2;
531break;
532}
533
534if(getColorForKey("devices_bgcolor", &color, theme))
535gui.devicelist.bgcolor = (color & 0x00FFFFFF);
536
537if(getIntForKey("devices_transparency", &alpha, theme))
538gui.devicelist.bgcolor = gui.devicelist.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
539
540if (gui.devicelist.pixmap)
541{
542 freeWindowBuffer(&gui.devicelist);
543 createWindowBuffer(&gui.devicelist);
544 }
545}
546
547void loadThemeValues(config_file_t *theme)
548{
549unsigned int screen_width = gui.screen.width;
550unsigned int screen_height = gui.screen.height;
551unsigned int pixel;
552intalpha;// transparency level 0 (obligue) - 255 (transparent)
553uint32_t color;// color value formatted RRGGBB
554int val;
555
556/*
557 * Parse screen parameters
558 */
559if(getColorForKey("screen_bgcolor", &color, theme ))
560gui.screen.bgcolor = (color & 0x00FFFFFF);
561
562if(getIntForKey("screen_textmargin_h", &val, theme))
563gui.screen.hborder = MIN( gui.screen.width , val );
564
565if(getIntForKey("screen_textmargin_v", &val, theme))
566gui.screen.vborder = MIN( gui.screen.height , val );
567
568/*
569 * Parse background parameters
570 */
571if(getDimensionForKey("background_pos_x", &pixel, theme, screen_width , images[iBackground].image->width ) )
572gui.background.pos.x = pixel;
573
574if(getDimensionForKey("background_pos_y", &pixel, theme, screen_height , images[iBackground].image->height ) )
575gui.background.pos.y = pixel;
576
577/*
578 * Parse logo parameters
579 */
580if(getDimensionForKey("logo_pos_x", &pixel, theme, screen_width , images[iLogo].image->width ) )
581gui.logo.pos.x = pixel;
582
583if(getDimensionForKey("logo_pos_y", &pixel, theme, screen_height , images[iLogo].image->height ) )
584gui.logo.pos.y = pixel;
585
586/*
587 * Parse progress bar parameters
588 */
589if(getDimensionForKey("progressbar_pos_x", &pixel, theme, screen_width , 0 ) )
590gui.progressbar.pos.x = pixel;
591
592if(getDimensionForKey("progressbar_pos_y", &pixel, theme, screen_height , 0 ) )
593gui.progressbar.pos.y = pixel;
594
595/*
596 * Parse countdown text parameters
597 */
598if(getDimensionForKey("countdown_pos_x", &pixel, theme, screen_width , 0 ) )
599gui.countdown.pos.x = pixel;
600
601if(getDimensionForKey("countdown_pos_y", &pixel, theme, screen_height , 0 ) )
602gui.countdown.pos.y = pixel;
603
604 /*
605 * Parse devicelist parameters
606 */
607setupDeviceList(theme);
608
609/*
610 * Parse infobox parameters
611 */
612if(getIntForKey("infobox_width", &val, theme))
613gui.infobox.width = MIN( screen_width , val );
614
615if(getIntForKey("infobox_height", &val, theme))
616gui.infobox.height = MIN( screen_height , val );
617
618if(getDimensionForKey("infobox_pos_x", &pixel, theme, screen_width , gui.infobox.width ) )
619gui.infobox.pos.x = pixel;
620
621if(getDimensionForKey("infobox_pos_y", &pixel, theme, screen_height , gui.infobox.height ) )
622gui.infobox.pos.y = pixel;
623
624if(getIntForKey("infobox_textmargin_h", &val, theme))
625gui.infobox.hborder = MIN( gui.infobox.width , val );
626
627if(getIntForKey("infobox_textmargin_v", &val, theme))
628gui.infobox.vborder = MIN( gui.infobox.height , val );
629
630if(getColorForKey("infobox_bgcolor", &color, theme))
631gui.infobox.bgcolor = (color & 0x00FFFFFF);
632
633if(getIntForKey("infobox_transparency", &alpha, theme))
634gui.infobox.bgcolor = gui.infobox.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
635
636/*
637 * Parse menu parameters
638 */
639if(getDimensionForKey("menu_width", &pixel, theme, gui.screen.width , 0 ) )
640gui.menu.width = pixel;
641else
642gui.menu.width = images[iMenuSelection].image->width;
643
644if(getDimensionForKey("menu_height", &pixel, theme, gui.screen.height , 0 ) )
645gui.menu.height = pixel;
646else
647gui.menu.height = (infoMenuItemsCount) * images[iMenuSelection].image->height;
648
649if(getDimensionForKey("menu_pos_x", &pixel, theme, screen_width , gui.menu.width ) )
650gui.menu.pos.x = pixel;
651
652if(getDimensionForKey("menu_pos_y", &pixel, theme, screen_height , gui.menu.height ) )
653gui.menu.pos.y = pixel;
654
655if(getIntForKey("menu_textmargin_h", &val, theme))
656gui.menu.hborder = MIN( gui.menu.width , val );
657
658if(getIntForKey("menu_textmargin_v", &val, theme))
659gui.menu.vborder = MIN( gui.menu.height , val );
660
661if(getColorForKey("menu_bgcolor", &color, theme))
662gui.menu.bgcolor = (color & 0x00FFFFFF);
663
664if(getIntForKey("menu_transparency", &alpha, theme))
665gui.menu.bgcolor = gui.menu.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
666
667/*
668 * Parse bootprompt parameters
669 */
670if(getDimensionForKey("bootprompt_width", &pixel, theme, screen_width , 0 ) )
671gui.bootprompt.width = pixel;
672
673if(getIntForKey("bootprompt_height", &val, theme))
674gui.bootprompt.height = MIN( screen_height , val );
675
676if(getDimensionForKey("bootprompt_pos_x", &pixel, theme, screen_width , gui.bootprompt.width ) )
677gui.bootprompt.pos.x = pixel;
678
679if(getDimensionForKey("bootprompt_pos_y", &pixel, theme, screen_height , gui.bootprompt.height ) )
680gui.bootprompt.pos.y = pixel;
681
682if(getIntForKey("bootprompt_textmargin_h", &val, theme))
683gui.bootprompt.hborder = MIN( gui.bootprompt.width , val );
684
685if(getIntForKey("bootprompt_textmargin_v", &val, theme))
686gui.bootprompt.vborder = MIN( gui.bootprompt.height , val );
687
688if(getColorForKey("bootprompt_bgcolor", &color, theme))
689gui.bootprompt.bgcolor = (color & 0x00FFFFFF);
690
691if(getIntForKey("bootprompt_transparency", &alpha, theme))
692gui.bootprompt.bgcolor = gui.bootprompt.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
693
694if(getColorForKey("font_small_color", &color, theme))
695gui.screen.font_small_color = (color & 0x00FFFFFF);
696
697if(getColorForKey("font_console_color", &color, theme))
698gui.screen.font_console_color = (color & 0x00FFFFFF);
699}
700
701int initGUI(void)
702{
703intval;
704intlen;
705char*dirspec; //[256];
706dirspec = (char*)malloc(256);
707
708getValueForKey( "Theme", &theme_name, &len, &bootInfo->bootConfig );
709if ((strlen(theme_name) + 27) > sizeof(dirspec)) {
710return 1;
711}
712
713sprintf(dirspec, "/Extra/Themes/%s/theme.plist", theme_name);
714if (loadConfigFile(dirspec, &bootInfo->themeConfig) != 0) {
715#ifdef EMBED_THEME
716config_file_t*config;
717DBG("Attention! EMBED_THEME!\n");
718config = &bootInfo->themeConfig;
719if (ParseXMLFile((char *)__theme_plist, &config->dictionary) != 0) {
720return 1;
721}
722#else
723DBG(" GUI from themeConfig failed\n");
724return 1;
725#endif
726}
727
728if(is_module_loaded("Resolution.dylib"))
729{
730getResolution(&screen_params[0], &screen_params[1], &screen_params[2]);
731gDualLink =((screen_params[0] * screen_params[1]) > (1<<20))?1:0;
732DBG("GUI module screen width=%d height=%d\n",(int)screen_params[0], (int)screen_params[1]);
733}
734if (((int)screen_params[0]<800) || ((int)screen_params[1]<600))
735{
736if (getIntForKey("screen_width", &val, &bootInfo->themeConfig) && val > 0)
737{
738screen_params[0] = val;
739}
740if (getIntForKey("screen_height", &val, &bootInfo->themeConfig) && val > 0)
741{
742screen_params[1] = val;
743}
744DBG("GUI theme screen width=%d height=%d\n",screen_params[0], screen_params[1]);
745}
746if (((int)screen_params[0]<800) || ((int)screen_params[1]<600))
747{
748screen_params[0] = DEFAULT_SCREEN_WIDTH;
749screen_params[1] = DEFAULT_SCREEN_HEIGHT;
750DBG("GUI default screen width=%d height=%d\n",screen_params[0], screen_params[1]);
751}
752/*if (((int)screen_params[0]>1280) || ((int)screen_params[1]>1024))
753{
754screen_params[0] = 1280;
755screen_params[1] = 1024;
756verbose("GUI MAX VESA screen width=%d height=%d\n",screen_params[0], screen_params[1]);
757}*/
758screen_params[2] = 32;
759// Initalizing GUI structure.
760bzero(&gui, sizeof(gui_t));
761
762// find best matching vesa mode for our requested width & height
763int modeV = getGraphicModeParams(screen_params);
764DBG("GUI: set mode %d: %dx%dx%d\n", modeV, screen_params[0], screen_params[1], screen_params[2]);
765
766// set our screen structure with the mode width & height
767gui.screen.width = screen_params[0];
768gui.screen.height = screen_params[1];
769
770// load graphics otherwise fail and return
771if (loadGraphics() == 0) {
772loadThemeValues(&bootInfo->themeConfig);
773colorFont(&font_small, gui.screen.font_small_color);
774colorFont(&font_console, gui.screen.font_console_color);
775
776// create the screen & window buffers
777if (createBackBuffer(&gui.screen) == 0)
778{
779if (createWindowBuffer(&gui.screen) == 0)
780{
781if (createWindowBuffer(&gui.devicelist) == 0)
782{
783if (createWindowBuffer(&gui.bootprompt) == 0)
784{
785if (createWindowBuffer(&gui.infobox) == 0)
786{
787if (createWindowBuffer(&gui.menu) == 0)
788{
789 gui.logo.draw = true;
790drawBackground();
791// lets copy the screen into the back buffer
792memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
793setVideoMode( GRAPHICS_MODE, 0 );
794gui.initialised = true;
795return 0;
796}
797}
798}
799}
800}
801}
802}
803return 1;
804}
805
806void drawDeviceIcon(BVRef device, pixmap_t *buffer, position_t p, bool isSelected)
807{
808int devicetype;
809
810if( diskIsCDROM(device) )
811devicetype = iDeviceCDROM;// Use CDROM icon
812else
813{
814switch (device->part_type)
815{
816case kPartitionTypeHFS:
817
818// Use HFS or HFSRAID icon depending on bvr flags.
819devicetype = (device->flags & kBVFlagBooter) ? iDeviceHFSRAID : iDeviceHFS;
820break;
821
822case kPartitionTypeHPFS:
823devicetype = iDeviceNTFS;// Use HPFS / NTFS icon
824break;
825
826case kPartitionTypeFAT16:
827devicetype = iDeviceFAT16;// Use FAT16 icon
828break;
829
830case kPartitionTypeFAT32:
831devicetype = iDeviceFAT32;// Use FAT32 icon
832break;
833
834case kPartitionTypeEXT3:
835devicetype = iDeviceEXT3;// Use EXT2/3 icon
836break;
837
838default:
839devicetype = iDeviceGeneric;// Use Generic icon
840break;
841}
842}
843
844// Draw the selection image and use the next (device_*_o) image for the selected item.
845 if (isSelected)
846{
847blend(images[iSelection].image, buffer, centeredAt(images[iSelection].image, p));
848devicetype++; // select override image
849}
850
851// draw icon
852blend( images[devicetype].image, buffer, centeredAt( images[devicetype].image, p ));
853
854p.y += (images[iSelection].image->height / 2) + font_console.chars[0]->height;
855
856// draw volume label
857drawStrCenteredAt( device->label, &font_small, buffer, p);
858
859}
860
861void drawDeviceList (int start, int end, int selection)
862{
863int i;
864position_t p, p_prev, p_next;
865
866//uint8_tmaxDevices = MIN( gui.maxdevices, menucount );
867
868fillPixmapWithColor( gui.devicelist.pixmap, gui.devicelist.bgcolor);
869
870makeRoundedCorners( gui.devicelist.pixmap);
871
872switch (gui.layout)
873{
874
875case VerticalLayout:
876p.x = (gui.devicelist.width /2);
877p.y = ( ( images[iSelection].image->height / 2 ) + images[iDeviceScrollPrev].image->height + gui.devicelist.iconspacing );
878
879// place scroll indicators at top & bottom edges
880p_prev = pos ( gui.devicelist.width / 2 , gui.devicelist.iconspacing );
881p_next = pos ( p_prev.x, gui.devicelist.height - gui.devicelist.iconspacing );
882
883break;
884
885default:// use Horizontal layout as the default
886
887case HorizontalLayout:
888p.x = (gui.devicelist.width - ( gui.devicelist.width / gui.maxdevices ) * gui.maxdevices ) / 2 + ( images[iSelection].image->width / 2) + images[iDeviceScrollPrev].image->width + gui.devicelist.iconspacing;
889p.y = ((gui.devicelist.height - font_console.chars[0]->height ) - images[iSelection].image->height) / 2 + ( images[iSelection].image->height / 2 );
890
891// place scroll indicators at left & right edges
892p_prev = pos ( images[iDeviceScrollPrev].image->width / 2 + gui.devicelist.iconspacing / 2, gui.devicelist.height / 2 );
893p_next = pos ( gui.devicelist.width - ( images[iDeviceScrollNext].image->width / 2 + gui.devicelist.iconspacing / 2), gui.devicelist.height / 2 );
894
895break;
896
897}
898
899// draw visible device icons
900for (i = 0; i < gui.maxdevices; i++)
901{
902BVRef param = menuItems[start + i].param;
903
904 bool isSelected = ((start + i) == selection) ? true : false;
905if (isSelected)
906{
907 if (param->flags & kBVFlagNativeBoot)
908 {
909 infoMenuNativeBoot = true;
910 }
911 else
912 {
913 infoMenuNativeBoot = false;
914 if(infoMenuSelection >= INFOMENU_NATIVEBOOT_START && infoMenuSelection <= INFOMENU_NATIVEBOOT_END)
915infoMenuSelection = 0;
916 }
917
918if(gui.menu.draw)
919drawInfoMenuItems();
920
921#if DEBUG
922 gui.debug.cursor = pos( 10, 100);
923 dprintf( &gui.screen, "label %s\n", param->label );
924 dprintf( &gui.screen, "biosdev 0x%x\n", param->biosdev );
925 dprintf( &gui.screen, "width %d\n", gui.screen.width);
926 dprintf( &gui.screen, "height %d\n", gui.screen.height);
927 dprintf( &gui.screen, "type 0x%x\n", param->type );
928 dprintf( &gui.screen, "flags 0x%x\n", param->flags );
929 dprintf( &gui.screen, "part_no %d\n", param->part_no );
930 dprintf( &gui.screen, "part_boff 0x%x\n", param->part_boff );
931 dprintf( &gui.screen, "part_type 0x%x\n", param->part_type );
932 dprintf( &gui.screen, "bps 0x%x\n", param->bps );
933 dprintf( &gui.screen, "name %s\n", param->name );
934 dprintf( &gui.screen, "type_name %s\n", param->type_name );
935 dprintf( &gui.screen, "modtime %d\n", param->modTime );
936#endif
937}
938
939drawDeviceIcon( param, gui.devicelist.pixmap, p, isSelected);
940
941if (gui.layout == HorizontalLayout)
942{
943p.x += images[iSelection].image->width + gui.devicelist.iconspacing;
944}
945if (gui.layout == VerticalLayout)
946{
947p.y += ( images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing );
948}
949}
950
951// draw prev indicator
952if(start)
953blend( images[iDeviceScrollPrev].image, gui.devicelist.pixmap, centeredAt( images[iDeviceScrollPrev].image, p_prev ) );
954
955// draw next indicator
956if( end < gDeviceCount - 1 )
957blend( images[iDeviceScrollNext].image, gui.devicelist.pixmap, centeredAt( images[iDeviceScrollNext].image, p_next ) );
958
959gui.redraw = true;
960
961updateVRAM();
962
963}
964
965void clearGraphicBootPrompt()
966{
967// clear text buffer
968prompt[0] = '\0';
969prompt_pos=0;
970
971
972if(gui.bootprompt.draw == true )
973{
974gui.bootprompt.draw = false;
975gui.redraw = true;
976// this causes extra frames to be drawn
977//updateVRAM();
978}
979
980return;
981}
982
983void updateGraphicBootPrompt(int key)
984{
985if ( key == kBackspaceKey )
986prompt[--prompt_pos] = '\0';
987else
988{
989prompt[prompt_pos] = key;
990prompt_pos++;
991prompt[prompt_pos] = '\0';
992}
993
994fillPixmapWithColor( gui.bootprompt.pixmap, gui.bootprompt.bgcolor);
995
996makeRoundedCorners( gui.bootprompt.pixmap);
997
998position_t p_text = pos( gui.bootprompt.hborder , ( ( gui.bootprompt.height - font_console.chars[0]->height) ) / 2 );
999
1000// print the boot prompt text
1001drawStr(prompt_text, &font_console, gui.bootprompt.pixmap, p_text);
1002
1003// get the position of the end of the boot prompt text to display user input
1004position_t p_prompt = pos( p_text.x + ( ( strlen(prompt_text) ) * font_console.chars[0]->width ), p_text.y );
1005
1006// calculate the position of the cursor
1007intoffset = ( prompt_pos - ( ( gui.bootprompt.width / font_console.chars[0]->width ) - strlen(prompt_text) - 2 ) );
1008
1009if ( offset < 0)
1010offset = 0;
1011
1012drawStr( prompt+offset, &font_console, gui.bootprompt.pixmap, p_prompt);
1013
1014gui.menu.draw = false;
1015gui.bootprompt.draw = true;
1016gui.redraw = true;
1017
1018updateVRAM();
1019
1020return;
1021}
1022
1023inline
1024void vramwrite (void *data, int width, int height)
1025{
1026if (VIDEO (depth) == 32 && VIDEO (rowBytes) == gui.backbuffer->width * 4)
1027memcpy((uint8_t *)vram, gui.backbuffer->pixels, VIDEO (rowBytes)*VIDEO (height));
1028else
1029{
1030uint32_t r, g, b;
1031int i, j;
1032for (i = 0; i < VIDEO (height); i++)
1033for (j = 0; j < VIDEO (width); j++)
1034{
1035b = ((uint8_t *) data)[4*i*width + 4*j];
1036g = ((uint8_t *) data)[4*i*width + 4*j + 1];
1037r = ((uint8_t *) data)[4*i*width + 4*j + 2];
1038switch (VIDEO (depth))
1039{
1040case 32:
1041*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*4) = (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);
1042break;
1043case 24:
1044*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*3) = ((*(uint32_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*3))&0xff000000)
1045| (b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16);
1046break;
1047case 16:
1048// Somehow 16-bit is always 15-bits really
1049//*(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xfc)<<3) | ((r&0xf8)<<8);
1050//break;
1051case 15:
1052*(uint16_t *)(((uint8_t *)vram)+i*VIDEO (rowBytes) + j*2) = ((b&0xf8)>>3) | ((g&0xf8)<<2) | ((r&0xf8)<<7);
1053break;
1054}
1055}
1056}
1057}
1058
1059void updateVRAM()
1060{
1061if (gui.redraw)
1062{
1063if (gui.devicelist.draw)
1064blend( gui.devicelist.pixmap, gui.backbuffer, gui.devicelist.pos );
1065
1066if (gui.bootprompt.draw)
1067blend( gui.bootprompt.pixmap, gui.backbuffer, gui.bootprompt.pos );
1068
1069if (gui.menu.draw)
1070blend( gui.menu.pixmap, gui.backbuffer, gui.menu.pos );
1071
1072if (gui.infobox.draw)
1073blend( gui.infobox.pixmap, gui.backbuffer, gui.infobox.pos );
1074}
1075
1076vramwrite ( gui.backbuffer->pixels, gui.backbuffer->width, gui.backbuffer->height );
1077
1078if (gui.redraw)
1079{
1080memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
1081gui.redraw = false;
1082}
1083}
1084
1085struct putc_info {
1086 char * str;
1087 char * last_str;
1088};
1089
1090static void
1091sputc(int c, struct putc_info * pi)
1092{
1093 if (pi->last_str)
1094 if (pi->str == pi->last_str) {
1095 *(pi->str) = '\0';
1096 return;
1097 }
1098 *(pi->str)++ = c;
1099}
1100
1101int gprintf( window_t * window, const char * fmt, ...)
1102{
1103char *formattedtext;
1104
1105va_list ap;
1106
1107struct putc_info pi;
1108
1109if ((formattedtext = malloc(1024)) != NULL) {
1110// format the text
1111va_start(ap, fmt);
1112pi.str = formattedtext;
1113pi.last_str = 0;
1114prf(fmt, ap, sputc, &pi);
1115*pi.str = '\0';
1116va_end(ap);
1117
1118position_torigin, cursor, bounds;
1119
1120int i;
1121int character;
1122
1123origin.x = MAX( window->cursor.x, window->hborder );
1124origin.y = MAX( window->cursor.y, window->vborder );
1125
1126bounds.x = ( window->width - window->hborder );
1127bounds.y = ( window->height - window->vborder );
1128
1129cursor = origin;
1130
1131font_t *font = &font_console;
1132
1133for( i=0; i< strlen(formattedtext); i++ )
1134{
1135character = formattedtext[i];
1136
1137character -= 32;
1138
1139// newline ?
1140if( formattedtext[i] == '\n' )
1141{
1142cursor.x = window->hborder;
1143cursor.y += font->height;
1144
1145if ( cursor.y > bounds.y )
1146cursor.y = origin.y;
1147
1148continue;
1149}
1150
1151// tab ?
1152if( formattedtext[i] == '\t' )
1153cursor.x += ( font->chars[0]->width * 5 );
1154
1155// draw the character
1156if( font->chars[character])
1157blend(font->chars[character], window->pixmap, cursor);
1158
1159cursor.x += font->chars[character]->width;
1160
1161// check x pos and do newline
1162if ( cursor.x > bounds.x )
1163{
1164cursor.x = origin.x;
1165cursor.y += font->height;
1166}
1167
1168// check y pos and reset to origin.y
1169if ( cursor.y > bounds.y )
1170cursor.y = origin.y;
1171}
1172
1173// update cursor postition
1174window->cursor = cursor;
1175
1176free(formattedtext);
1177
1178return 0;
1179
1180}
1181return 1;
1182}
1183
1184int dprintf( window_t * window, const char * fmt, ...)
1185{
1186char *formattedtext;
1187
1188va_list ap;
1189
1190//window = &gui.debug;
1191
1192struct putc_info pi;
1193
1194if ((formattedtext = malloc(1024)) != NULL) {
1195// format the text
1196va_start(ap, fmt);
1197pi.str = formattedtext;
1198pi.last_str = 0;
1199prf(fmt, ap, sputc, &pi);
1200*pi.str = '\0';
1201va_end(ap);
1202
1203position_torigin, cursor, bounds;
1204
1205int i;
1206int character;
1207
1208origin.x = MAX( gui.debug.cursor.x, window->hborder );
1209origin.y = MAX( gui.debug.cursor.y, window->vborder );
1210
1211bounds.x = ( window->width - window->hborder );
1212bounds.y = ( window->height - window->vborder );
1213
1214cursor = origin;
1215
1216font_t *font = &font_console;
1217
1218for( i=0; i< strlen(formattedtext); i++ )
1219{
1220character = formattedtext[i];
1221
1222character -= 32;
1223
1224// newline ?
1225if( formattedtext[i] == '\n' )
1226{
1227cursor.x = window->hborder;
1228cursor.y += font->height;
1229
1230if ( cursor.y > bounds.y )
1231cursor.y = origin.y;
1232
1233continue;
1234}
1235
1236// tab ?
1237if( formattedtext[i] == '\t' )
1238cursor.x += ( font->chars[0]->width * 5 );
1239
1240// draw the character
1241if( font->chars[character])
1242blend(font->chars[character], gui.backbuffer, cursor);
1243
1244cursor.x += font->chars[character]->width;
1245
1246// check x pos and do newline
1247if ( cursor.x > bounds.x )
1248{
1249cursor.x = origin.x;
1250cursor.y += font->height;
1251}
1252
1253// check y pos and reset to origin.y
1254if ( cursor.y > bounds.y )
1255cursor.y = origin.y;
1256}
1257
1258// update cursor postition
1259gui.debug.cursor = cursor;
1260
1261free(formattedtext);
1262
1263return 0;
1264
1265}
1266return 1;
1267}
1268
1269int vprf(const char * fmt, va_list ap)
1270{
1271int i;
1272int character;
1273
1274char *formattedtext;
1275window_t *window = &gui.screen;
1276struct putc_info pi;
1277
1278position_torigin, cursor, bounds;
1279font_t *font = &font_console;
1280
1281if ((formattedtext = malloc(1024)) != NULL) {
1282// format the text
1283pi.str = formattedtext;
1284pi.last_str = 0;
1285prf(fmt, ap, sputc, &pi);
1286*pi.str = '\0';
1287
1288origin.x = MAX( window->cursor.x, window->hborder );
1289origin.y = MAX( window->cursor.y, window->vborder );
1290bounds.x = ( window->width - ( window->hborder * 2 ) );
1291bounds.y = ( window->height - ( window->vborder * 2 ) );
1292cursor = origin;
1293
1294for( i=0; i< strlen(formattedtext); i++ )
1295{
1296character = formattedtext[i];
1297character -= 32;
1298
1299// newline ?
1300if( formattedtext[i] == '\n' )
1301{
1302cursor.x = window->hborder;
1303cursor.y += font->height;
1304if ( cursor.y > bounds.y )
1305{
1306gui.redraw = true;
1307updateVRAM();
1308cursor.y = window->vborder;
1309}
1310window->cursor.y = cursor.y;
1311continue;
1312}
1313
1314// tab ?
1315if( formattedtext[i] == '\t' )
1316{
1317cursor.x = ( cursor.x / ( font->chars[0]->width * 8 ) + 1 ) * ( font->chars[0]->width * 8 );
1318continue;
1319}
1320cursor.x += font->chars[character]->width;
1321
1322// check x pos and do newline
1323if ( cursor.x > bounds.x )
1324{
1325cursor.x = origin.x;
1326cursor.y += font->height;
1327}
1328
1329// check y pos and reset to origin.y
1330if ( cursor.y > ( bounds.y + font->chars[0]->height) )
1331{
1332gui.redraw = true;
1333updateVRAM();
1334cursor.y = window->vborder;
1335}
1336// draw the character
1337if( font->chars[character])
1338blend(font->chars[character], gui.backbuffer, cursor);
1339}
1340// save cursor postition
1341window->cursor.x = cursor.x;
1342updateVRAM();
1343free(formattedtext);
1344return 0;
1345}
1346return 1;
1347}
1348
1349void drawStr(char *ch, font_t *font, pixmap_t *blendInto, position_t p)
1350{
1351int i=0;
1352int y=0; // we need this to support multilines '\n'
1353int x=0;
1354
1355for(i=0;i<strlen(ch);i++)
1356{
1357int cha=(int)ch[i];
1358
1359cha-=32;
1360
1361// newline ?
1362if( ch[i] == '\n' )
1363{
1364x = 0;
1365y += font->height;
1366continue;
1367}
1368
1369// tab ?
1370if( ch[i] == '\t' )
1371x+=(font->chars[0]->width*5);
1372
1373if(font->chars[cha])
1374blend(font->chars[cha], blendInto, pos(p.x+x, p.y+y));
1375
1376x += font->chars[cha]->width;
1377}
1378}
1379
1380void drawStrCenteredAt(char *text, font_t *font, pixmap_t *blendInto, position_t p)
1381{
1382int i = 0;
1383int width = 0;
1384
1385// calculate the width in pixels
1386for(i=0;i<strlen(text);i++)
1387width += font->chars[text[i]-32]->width;
1388
1389p.x = ( p.x - ( width / 2 ) );
1390p.y = ( p.y - ( font->height / 2 ) );
1391
1392if ( p.x == -6 )
1393{
1394p.x = 0;
1395}
1396
1397for(i=0;i<strlen(text);i++)
1398{
1399int cha=(int)text[i];
1400
1401cha-=32;
1402
1403if(font->chars[cha])
1404{
1405blend(font->chars[cha], blendInto, p);
1406p.x += font->chars[cha]->width;
1407}
1408}
1409
1410}
1411
1412int initFont(font_t *font, image_t *data)
1413{
1414unsigned int x = 0, y = 0, x2 = 0, x3 = 0;
1415
1416int start = 0, end = 0, count = 0, space = 0;
1417
1418bool monospaced = false;
1419
1420font->height = data->image->height;
1421
1422for( x = 0; x < data->image->width; x++)
1423{
1424start = end;
1425
1426// if the pixel is red we've reached the end of the char
1427if( pixel( data->image, x, 0 ).value == 0xFFFF0000)
1428{
1429end = x + 1;
1430
1431if( (font->chars[count] = malloc(sizeof(pixmap_t)) ) )
1432{
1433font->chars[count]->width = ( end - start) - 1;
1434font->chars[count]->height = font->height;
1435
1436if ( ( font->chars[count]->pixels = malloc( font->chars[count]->width * data->image->height * 4) ) )
1437{
1438space += ( font->chars[count]->width * data->image->height * 4 );
1439// we skip the first line because there are just the red pixels for the char width
1440for( y = 1; y< (font->height); y++)
1441{
1442for( x2 = start, x3 = 0; x2 < end; x2++, x3++)
1443{
1444pixel( font->chars[count], x3, y ) = pixel( data->image, x2, y );
1445}
1446}
1447
1448// check if font is monospaced
1449if( ( count > 0 ) && ( font->width != font->chars[count]->width ) )
1450monospaced = true;
1451
1452font->width = font->chars[count]->width;
1453
1454count++;
1455}
1456}
1457}
1458}
1459
1460if(monospaced)
1461font->width = 0;
1462
1463return 0;
1464}
1465
1466void colorFont(font_t *font, uint32_t color)
1467{
1468if( !color )
1469return;
1470
1471int x, y, width, height;
1472int count = 0;
1473pixel_t *buff;
1474
1475while( font->chars[count++] )
1476{
1477width = font->chars[count-1]->width;
1478height = font->chars[count-1]->height;
1479for( y = 0; y < height; y++ )
1480{
1481for( x = 0; x < width; x++ )
1482{
1483buff = &(pixel( font->chars[count-1], x, y ));
1484if( buff->ch.a )
1485{
1486buff->ch.r = (color & 0xFFFF0000) >> 16;
1487buff->ch.g = (color & 0xFF00FF00) >> 8;
1488buff->ch.b = (color & 0xFF0000FF);
1489}
1490}
1491}
1492}
1493}
1494
1495void makeRoundedCorners(pixmap_t *p)
1496{
1497int x,y;
1498int width=p->width-1;
1499int height=p->height-1;
1500
1501// 10px rounded corner alpha values
1502uint8_t roundedCorner[10][10] =
1503{
1504{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0xC0, 0xFF},
1505{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF},
1506{ 0x00, 0x00, 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1507{ 0x00, 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1508{ 0x00, 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1509{ 0x00, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1510{ 0x40, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1511{ 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1512{ 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1513{ 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
1514};
1515
1516uint8_t alpha=0;
1517
1518for( y=0; y<10; y++)
1519{
1520for( x=0; x<10; x++)
1521{
1522// skip if the pixel should be visible
1523if(roundedCorner[y][x] != 0xFF)
1524{
1525alpha = ( roundedCorner[y][x] ? (uint8_t) (roundedCorner[y][x] * pixel(p, x, y).ch.a) / 255 : 0 );
1526// Upper left corner
1527pixel(p, x, y).ch.a = alpha;
1528
1529// upper right corner
1530pixel(p, width-x,y).ch.a = alpha;
1531
1532// lower left corner
1533pixel(p, x, height-y).ch.a = alpha;
1534
1535// lower right corner
1536pixel(p, width-x, height-y).ch.a = alpha;
1537}
1538}
1539}
1540}
1541
1542void showInfoBox(char *title, char *text)
1543{
1544int i, key, lines, visiblelines;
1545
1546int currentline=0;
1547int cnt=0;
1548int offset=0;
1549
1550if( !title || !text )
1551return;
1552
1553position_t pos_title = pos ( gui.infobox.vborder, gui.infobox.vborder );
1554
1555// calculate number of lines in the title
1556for ( i = 0, lines = 1; i<strlen(title); i++ )
1557if( title[i] == '\n')
1558lines++;
1559
1560// y position of text is lines in title * height of font
1561position_t pos_text = pos( pos_title.x , pos_title.y + ( font_console.height * lines ));
1562
1563// calculate number of lines in the text
1564for ( i=0, lines = 1; i<strlen(text); i++ )
1565if( text[i] == '\n')
1566lines++;
1567
1568// if text ends with \n strip off
1569if( text[i] == '\n' || text[i] == '\0')
1570lines--;
1571
1572visiblelines = ( ( gui.infobox.height - ( gui.infobox.vborder * 2 ) ) / font_console.height ) - 1;
1573
1574// lets display the text and allow scroll thru using up down / arrows
1575while(1)
1576{
1577// move to current line in text
1578for( offset = 0, i = 0; offset < strlen(text); offset++ )
1579{
1580if( currentline == i)
1581break;
1582if( text[offset] =='\n')
1583i++;
1584}
1585
1586// find last visible line in text and place \0
1587for( i = offset, cnt = 0; i < strlen(text); i++)
1588{
1589if(text[i]=='\n')
1590cnt++;
1591if ( cnt == visiblelines )
1592{
1593text[i]='\0';
1594break;
1595}
1596}
1597
1598fillPixmapWithColor( gui.infobox.pixmap, gui.infobox.bgcolor);
1599
1600makeRoundedCorners( gui.infobox.pixmap);
1601
1602// print the title if present
1603if( title )
1604drawStr(title, &font_console, gui.infobox.pixmap, pos_title);
1605
1606// print the text
1607drawStr( text + offset, &font_console, gui.infobox.pixmap, pos_text);
1608
1609// restore \n in text
1610if ( cnt == visiblelines )
1611text[i] = '\n';
1612
1613position_t pos_indicator = pos( gui.infobox.width - ( images[iTextScrollPrev].image->width - ( gui.infobox.vborder / 2) ), pos_text.y );
1614
1615// draw prev indicator
1616if(offset)
1617{
1618blend( images[iTextScrollPrev].image, gui.infobox.pixmap, centeredAt( images[iTextScrollPrev].image, pos_indicator ));
1619}
1620
1621// draw next indicator
1622if( lines > ( currentline + visiblelines ) )
1623{
1624pos_indicator.y = ( gui.infobox.height - ( ( images[iTextScrollNext].image->width + gui.infobox.vborder ) / 2 ) );
1625blend( images[iTextScrollNext].image, gui.infobox.pixmap, centeredAt( images[iTextScrollNext].image, pos_indicator ) );
1626}
1627
1628gui.bootprompt.draw = false;
1629gui.infobox.draw = true;
1630gui.redraw = true;
1631
1632updateVRAM();
1633
1634key = getc();
1635
1636if( key == kUpArrowkey )
1637if( currentline > 0 )
1638currentline--;
1639
1640if( key == kDownArrowkey )
1641if( lines > ( currentline + visiblelines ) )
1642currentline++;
1643
1644if( key == kEscapeKey || key == 'q' || key == 'Q')
1645{
1646gui.infobox.draw = false;
1647gui.redraw = true;
1648updateVRAM();
1649break;
1650}
1651}
1652}
1653
1654void animateProgressBar()
1655{
1656int y;
1657
1658if( time18() > lasttime)
1659{
1660lasttime = time18();
1661
1662pixmap_t *buffBar = images[iProgressBar].image;
1663
1664uint32_t buff = buffBar->pixels[0].value;
1665
1666memcpy( buffBar->pixels, buffBar->pixels + 1, ( (buffBar->width*buffBar->height) - 1 ) * 4 );
1667
1668for( y = buffBar->height - 1; y > 0; y--)
1669pixel(buffBar, buffBar->width - 1, y) = pixel(buffBar, buffBar->width - 1, y - 1);
1670
1671pixel(buffBar, buffBar->width-1, 0).value = buff;
1672}
1673}
1674
1675void drawProgressBar(pixmap_t *blendInto, uint16_t width, position_t p, uint8_t progress)
1676{
1677if(progress>100)
1678return;
1679
1680p.x = ( p.x - ( width / 2 ) );
1681
1682int todraw = (width * progress) / 100;
1683
1684pixmap_t *buff = images[iProgressBar].image;
1685pixmap_t *buffBG = images[iProgressBarBackground].image;
1686if(!buff || !buffBG)
1687return;
1688
1689pixmap_t progressbar;
1690progressbar.pixels=malloc(width * 4 * buff->height);
1691if(!progressbar.pixels)
1692return;
1693
1694progressbar.width = width;
1695progressbar.height = buff->height;
1696
1697int x=0,x2=0,y=0;
1698
1699for(y=0; y<buff->height; y++)
1700{
1701for(x=0; x<todraw; x++, x2++)
1702{
1703if(x2 == (buff->width-1)) x2=0;
1704pixel(&progressbar, x,y).value = pixel(buff, x2,y).value;
1705}
1706x2=0;
1707}
1708
1709for(y=0; y<buff->height; y++)
1710{
1711for(x=todraw, x2 = 0; x < width - 1; x++, x2++)
1712{
1713if(x2 == (buffBG->width -2 )) x2 = 0;
1714pixel(&progressbar, x,y).value = pixel(buffBG, x2,y).value;
1715}
1716if(progress < 100)
1717pixel(&progressbar, width - 1, y).value = pixel(buffBG, buffBG->width - 1, y).value;
1718if(progress == 0)
1719pixel(&progressbar, 0, y).value = pixel(buffBG, buffBG->width - 1, y).value;
1720x2=0;
1721}
1722
1723blend(&progressbar, blendInto, p);
1724animateProgressBar();
1725free(progressbar.pixels);
1726}
1727
1728void drawInfoMenuItems()
1729{
1730int i,n;
1731
1732position_t position;
1733
1734pixmap_t *selection = images[iMenuSelection].image;
1735
1736pixmap_t *pbuff;
1737
1738fillPixmapWithColor(gui.menu.pixmap, gui.menu.bgcolor);
1739
1740makeRoundedCorners(gui.menu.pixmap);
1741
1742uint8_t offset = infoMenuNativeBoot ? 0 : infoMenuItemsCount - 1;
1743
1744position = pos(0,0);
1745
1746for ( i = 0, n = iMenuBoot; i < infoMenuItemsCount; i++, n++)
1747{
1748if (i == infoMenuSelection)
1749{
1750blend(selection, gui.menu.pixmap, position);
1751}
1752
1753pbuff = images[n].image;
1754if (offset && i >= INFOMENU_NATIVEBOOT_START && i <= INFOMENU_NATIVEBOOT_END)
1755{
1756blend( images[n + (iMenuHelp - iMenuBoot)].image , gui.menu.pixmap,
1757 pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2)));
1758}
1759else
1760{
1761blend( pbuff, gui.menu.pixmap,
1762 pos((position.x + (gui.menu.hborder / 2)), position.y + ((selection->height - pbuff->height) / 2)));
1763}
1764
1765drawStr(infoMenuItems[i].text, &font_console, gui.menu.pixmap,
1766pos(position.x + (pbuff->width + gui.menu.hborder),
1767position.y + ((selection->height - font_console.height) / 2)));
1768position.y += images[iMenuSelection].image->height;
1769
1770}
1771
1772gui.redraw = true;
1773}
1774
1775int drawInfoMenu()
1776{
1777drawInfoMenuItems();
1778
1779gui.menu.draw = true;
1780
1781updateVRAM();
1782
1783return 1;
1784}
1785
1786int updateInfoMenu(int key)
1787{
1788switch (key)
1789{
1790
1791case kUpArrowkey:// up arrow
1792if (infoMenuSelection > 0)
1793{
1794if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_END + 1)
1795{
1796infoMenuSelection -= 4;
1797}
1798else
1799{
1800infoMenuSelection--;
1801}
1802drawInfoMenuItems();
1803updateVRAM();
1804
1805}
1806else
1807{
1808
1809gui.menu.draw = false;
1810gui.redraw = true;
1811
1812updateVRAM();
1813
1814return CLOSE_INFO_MENU;
1815}
1816break;
1817
1818case kDownArrowkey:// down arrow
1819if (infoMenuSelection < infoMenuItemsCount - 1)
1820{
1821if(!infoMenuNativeBoot && infoMenuSelection == INFOMENU_NATIVEBOOT_START - 1)
1822infoMenuSelection += 4;
1823else
1824infoMenuSelection++;
1825drawInfoMenuItems();
1826updateVRAM();
1827}
1828break;
1829
1830case kReturnKey:
1831key = 0;
1832if( infoMenuSelection == MENU_SHOW_MEMORY_INFO )
1833showInfoBox( "Memory Info. Press q to quit.\n", getMemoryInfoString());
1834
1835else if( infoMenuSelection == MENU_SHOW_VIDEO_INFO )
1836showInfoBox( getVBEInfoString(), getVBEModeInfoString() );
1837
1838else if( infoMenuSelection == MENU_SHOW_HELP )
1839showHelp();
1840
1841else
1842{
1843int buff = infoMenuSelection;
1844infoMenuSelection = 0;
1845return buff;
1846}
1847break;
1848}
1849return DO_NOT_BOOT;
1850}
1851
1852uint16_t bootImageWidth = 0;
1853uint16_t bootImageHeight = 0;
1854uint8_t *bootImageData = NULL;
1855char usePngImage = 0;
1856
1857//==========================================================================
1858// loadBootGraphics
1859void loadBootGraphics(void)
1860{
1861if (bootImageData != NULL) {
1862return;
1863}
1864
1865char dirspec[256];
1866
1867if ((strlen(theme_name) + 24) > sizeof(dirspec)) {
1868usePngImage = 0;
1869return;
1870}
1871sprintf(dirspec, "/Extra/Themes/%s/boot.png", theme_name);
1872if (loadPngImage(dirspec, &bootImageWidth, &bootImageHeight, &bootImageData) != 0) {
1873#ifdef EMBED_THEME
1874if ((loadEmbeddedPngImage(__boot_png, __boot_png_len, &bootImageWidth, &bootImageHeight, &bootImageData)) != 0)
1875#endif
1876usePngImage = 0;
1877}
1878}
1879
1880//==========================================================================
1881// drawBootGraphics
1882void drawBootGraphics(void)
1883{
1884//int pos;
1885int length;
1886const char *dummyVal;
1887int oldScreenWidth, oldScreenHeight;
1888uint16_t x, y;
1889bool legacy_logo = false;
1890if (getBoolForKey("Legacy Logo", &legacy_logo, &bootInfo->bootConfig) && !legacy_logo)
1891{
1892usePngImage = 1;
1893}
1894
1895if (usePngImage && bootImageData == NULL) {
1896loadBootGraphics();
1897}
1898//Slice - attention!
1899// getResolution already done!
1900// parse screen size parameters
1901/*if(is_module_loaded("Resolution.dylib"))
1902{
1903getResolution(&screen_params[0], &screen_params[1], &screen_params[2]);
1904}
1905else
1906{
1907if (getIntForKey("boot_width", &pos, &bootInfo->themeConfig) && pos > 0)
1908{
1909screen_params[0] = pos;
1910} else {
1911screen_params[0] = DEFAULT_SCREEN_WIDTH;
1912}
1913if (getIntForKey("boot_height", &pos, &bootInfo->themeConfig) && pos > 0)
1914{
1915screen_params[1] = pos;
1916} else
1917{
1918screen_params[1] = DEFAULT_SCREEN_HEIGHT;
1919}
1920}
1921msglog("boot_width=%d boot_height=%d\n", screen_params[0], screen_params[1]);
1922 // Save current screen resolution. // for a what?
1923 */
1924oldScreenWidth = gui.screen.width;
1925oldScreenHeight = gui.screen.height;
1926
1927gui.screen.width = screen_params[0];
1928gui.screen.height = screen_params[1];
1929
1930// find best matching vesa mode for our requested width & height
1931getGraphicModeParams(screen_params);
1932
1933 // Set graphics mode if the booter was in text mode or the screen resolution has changed.
1934if (bootArgs->Video.v_display == VGA_TEXT_MODE
1935|| (screen_params[0] != oldScreenWidth && screen_params[1] != oldScreenHeight) )
1936{
1937setVideoMode(GRAPHICS_MODE, 0);
1938}
1939
1940if (getValueForKey("-checkers", &dummyVal, &length, &bootInfo->bootConfig)) {
1941drawCheckerBoard();
1942} else {
1943// Fill the background to 75% grey (same as BootX).
1944drawColorRectangle(0, 0, screen_params[0], screen_params[1], 0x01);
1945}
1946if ((bootImageData) && (usePngImage)) {
1947x = (screen_params[0] - MIN(bootImageWidth, screen_params[0])) / 2;
1948y = (screen_params[1] - MIN(bootImageHeight, screen_params[1])) / 2;
1949
1950// Draw the image in the center of the display.
1951blendImage(x, y, bootImageWidth, bootImageHeight, bootImageData);
1952} else {
1953uint8_t *appleBootPict;
1954bootImageData = NULL;
1955bootImageWidth = kAppleBootWidth;
1956bootImageHeight = kAppleBootHeight;
1957
1958// Prepare the data for the default Apple boot image.
1959appleBootPict = (uint8_t *) decodeRLE(gAppleBootPictRLE, kAppleBootRLEBlocks, bootImageWidth * bootImageHeight);
1960if (appleBootPict) {
1961convertImage(bootImageWidth, bootImageHeight, appleBootPict, &bootImageData);
1962if (bootImageData) {
1963x = (screen_params[0] - MIN(kAppleBootWidth, screen_params[0])) / 2;
1964y = (screen_params[1] - MIN(kAppleBootHeight, screen_params[1])) / 2;
1965drawDataRectangle(x, y, kAppleBootWidth, kAppleBootHeight, bootImageData);
1966free(bootImageData);
1967}
1968free(appleBootPict);
1969}
1970}
1971}
1972
1973int GUI_initGraphicsMode ()
1974{
1975unsigned long params[4];
1976int count;
1977
1978params[3] = 0;
1979count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
1980
1981// Try to find a resolution if "Graphics Mode" setting is not available.
1982if ( count < 3 )
1983{
1984// Use the default resolution if we don't have an initialized GUI.
1985if (gui.screen.width == 0 || gui.screen.height == 0)
1986{
1987gui.screen.width = DEFAULT_SCREEN_WIDTH;
1988gui.screen.height = DEFAULT_SCREEN_HEIGHT;
1989}
1990
1991params[0] = gui.screen.width;
1992params[1] = gui.screen.height;
1993params[2] = 32;
1994}
1995
1996// Map from pixel format to bits per pixel.
1997
1998if ( params[2] == 256 ) params[2] = 8;
1999if ( params[2] == 555 ) params[2] = 16;
2000if ( params[2] == 888 ) params[2] = 32;
2001
2002return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
2003}
2004
2005
2006int GUI_countdown( const char * msg, int row, int timeout )
2007{
2008 unsigned long time;
2009 int ch = 0;
2010 int col = strlen(msg) + 1;
2011
2012 flushKeyboardBuffer();
2013
2014if( bootArgs->Video.v_display == VGA_TEXT_MODE )
2015{
2016moveCursor( 0, row );
2017printf(msg);
2018
2019} else {
2020
2021position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
2022
2023char dummy[80];
2024getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
2025drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
2026drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
2027
2028// make this screen the new background
2029memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
2030
2031}
2032
2033int multi_buff = 18 * (timeout);
2034 int multi = ++multi_buff;
2035
2036 int lasttime=0;
2037
2038 for ( time = time18(), timeout++; timeout > 0; )
2039 {
2040if( time18() > lasttime)
2041{
2042multi--;
2043lasttime=time18();
2044}
2045
2046 if (ch = readKeyboardStatus())
2047 break;
2048
2049 // Count can be interrupted by holding down shift,
2050 // control or alt key
2051 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
2052{
2053 ch = 1;
2054 break;
2055 }
2056
2057 if ( time18() >= time )
2058 {
2059 time += 18;
2060 timeout--;
2061
2062if( bootArgs->Video.v_display == VGA_TEXT_MODE )
2063{
2064moveCursor( col, row );
2065printf("(%d) ", timeout);
2066}
2067 }
2068
2069if( bootArgs->Video.v_display == GRAPHICS_MODE )
2070{
2071drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
2072gui.redraw = true;
2073updateVRAM();
2074}
2075
2076 }
2077
2078 flushKeyboardBuffer();
2079
2080 return ch;
2081}
2082
2083

Archive Download this file

Revision: 714