[FREELDR] Code fixes and enhancements.
[reactos.git] / boot / freeldr / freeldr / ui / ui.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #ifndef _M_ARM
20
21 #include <freeldr.h>
22
23 #include <debug.h>
24 DBG_DEFAULT_CHANNEL(UI);
25
26 #define TAG_UI_TEXT 'xTiU'
27
28 ULONG UiScreenWidth; // Screen Width
29 ULONG UiScreenHeight; // Screen Height
30
31 UCHAR UiStatusBarFgColor = COLOR_BLACK; // Status bar foreground color
32 UCHAR UiStatusBarBgColor = COLOR_CYAN; // Status bar background color
33 UCHAR UiBackdropFgColor = COLOR_WHITE; // Backdrop foreground color
34 UCHAR UiBackdropBgColor = COLOR_BLUE; // Backdrop background color
35 UCHAR UiBackdropFillStyle = MEDIUM_FILL; // Backdrop fill style
36 UCHAR UiTitleBoxFgColor = COLOR_WHITE; // Title box foreground color
37 UCHAR UiTitleBoxBgColor = COLOR_RED; // Title box background color
38 UCHAR UiMessageBoxFgColor = COLOR_WHITE; // Message box foreground color
39 UCHAR UiMessageBoxBgColor = COLOR_BLUE; // Message box background color
40 UCHAR UiMenuFgColor = COLOR_WHITE; // Menu foreground color
41 UCHAR UiMenuBgColor = COLOR_BLUE; // Menu background color
42 UCHAR UiTextColor = COLOR_YELLOW; // Normal text color
43 UCHAR UiSelectedTextColor = COLOR_BLACK; // Selected text color
44 UCHAR UiSelectedTextBgColor = COLOR_GRAY; // Selected text background color
45 UCHAR UiEditBoxTextColor = COLOR_WHITE; // Edit box text color
46 UCHAR UiEditBoxBgColor = COLOR_BLACK; // Edit box text background color
47
48 CHAR UiTitleBoxTitleText[260] = "Boot Menu"; // Title box's title text
49
50 BOOLEAN UiUseSpecialEffects = FALSE; // Tells us if we should use fade effects
51 BOOLEAN UiDrawTime = TRUE; // Tells us if we should draw the time
52 BOOLEAN UiCenterMenu = TRUE; // Tells us if we should use a centered or left-aligned menu
53 BOOLEAN UiMenuBox = TRUE; // Tells us if we should draw a box around the menu
54 CHAR UiTimeText[260] = "[Time Remaining: ] ";
55
56 const CHAR UiMonthNames[12][15] = { "January ", "February ", "March ", "April ", "May ", "June ", "July ", "August ", "September ", "October ", "November ", "December " };
57
58 UIVTBL UiVtbl =
59 {
60 NoUiInitialize,
61 NoUiUnInitialize,
62 NoUiDrawBackdrop,
63 NoUiFillArea,
64 NoUiDrawShadow,
65 NoUiDrawBox,
66 NoUiDrawText,
67 NoUiDrawText2,
68 NoUiDrawCenteredText,
69 NoUiDrawStatusText,
70 NoUiUpdateDateTime,
71 NoUiMessageBox,
72 NoUiMessageBoxCritical,
73 NoUiDrawProgressBarCenter,
74 NoUiDrawProgressBar,
75 NoUiEditBox,
76 NoUiTextToColor,
77 NoUiTextToFillStyle,
78 NoUiFadeInBackdrop,
79 NoUiFadeOut,
80 NoUiDisplayMenu,
81 NoUiDrawMenu,
82 };
83
84 BOOLEAN UiInitialize(BOOLEAN ShowGui)
85 {
86 VIDEODISPLAYMODE UiDisplayMode; // Tells us if we are in text or graphics mode
87 BOOLEAN UiMinimal = FALSE; // Tells us if we are using a minimal console-like UI
88 ULONG_PTR SectionId;
89 ULONG Depth;
90 CHAR SettingText[260];
91
92 if (!ShowGui)
93 {
94 if (!UiVtbl.Initialize())
95 {
96 MachVideoSetDisplayMode(NULL, FALSE);
97 return FALSE;
98 }
99 return TRUE;
100 }
101
102 TRACE("Initializing User Interface.\n");
103 TRACE("Reading UI settings from [Display] section.\n");
104
105 /* Open the [Display] section */
106 if (!IniOpenSection("Display", &SectionId))
107 SectionId = 0;
108
109 /* Select the video mode */
110 SettingText[0] = '\0';
111 if ((SectionId != 0) && !IniReadSettingByName(SectionId, "DisplayMode", SettingText, sizeof(SettingText)))
112 {
113 SettingText[0] = '\0';
114 }
115 UiDisplayMode = MachVideoSetDisplayMode(SettingText, TRUE);
116 MachVideoGetDisplaySize(&UiScreenWidth, &UiScreenHeight, &Depth);
117
118 /* Select the UI */
119 if ((SectionId != 0) && IniReadSettingByName(SectionId, "MinimalUI", SettingText, sizeof(SettingText)))
120 {
121 UiMinimal = (_stricmp(SettingText, "Yes") == 0 && strlen(SettingText) == 3);
122 }
123
124 if (UiDisplayMode == VideoTextMode)
125 UiVtbl = (UiMinimal ? MiniTuiVtbl : TuiVtbl);
126 else
127 UiVtbl = GuiVtbl;
128
129 if (!UiVtbl.Initialize())
130 {
131 MachVideoSetDisplayMode(NULL, FALSE);
132 return FALSE;
133 }
134
135 /* Load the settings */
136 if (SectionId != 0)
137 {
138 static const struct
139 {
140 PCSTR SettingName;
141 PVOID SettingVar;
142 UCHAR SettingType; // 0: Text, 1: Yes/No, 2: Color, 3: Fill style
143 } Settings[] =
144 {
145 {"TitleText", &UiTitleBoxTitleText, 0},
146 {"TimeText" , &UiTimeText , 0},
147
148 {"SpecialEffects", &UiUseSpecialEffects, 1},
149 {"ShowTime" , &UiDrawTime , 1},
150 {"MenuBox" , &UiMenuBox , 1},
151 {"CenterMenu" , &UiCenterMenu , 1},
152
153 {"BackdropColor" , &UiBackdropBgColor , 2},
154 {"BackdropTextColor" , &UiBackdropFgColor , 2},
155 {"StatusBarColor" , &UiStatusBarBgColor , 2},
156 {"StatusBarTextColor" , &UiStatusBarFgColor , 2},
157 {"TitleBoxColor" , &UiTitleBoxBgColor , 2},
158 {"TitleBoxTextColor" , &UiTitleBoxFgColor , 2},
159 {"MessageBoxColor" , &UiMessageBoxBgColor , 2},
160 {"MessageBoxTextColor", &UiMessageBoxFgColor , 2},
161 {"MenuColor" , &UiMenuBgColor , 2},
162 {"MenuTextColor" , &UiMenuFgColor , 2},
163 {"TextColor" , &UiTextColor , 2},
164 {"SelectedColor" , &UiSelectedTextBgColor, 2},
165 {"SelectedTextColor" , &UiSelectedTextColor , 2},
166 {"EditBoxColor" , &UiEditBoxBgColor , 2},
167 {"EditBoxTextColor" , &UiEditBoxTextColor , 2},
168
169 {"BackdropFillStyle", &UiBackdropFillStyle, 3},
170 };
171 ULONG i;
172
173 for (i = 0; i < sizeof(Settings)/sizeof(Settings[0]); ++i)
174 {
175 if (!IniReadSettingByName(SectionId, Settings[i].SettingName, SettingText, sizeof(SettingText)))
176 continue;
177
178 switch (Settings[i].SettingType)
179 {
180 case 0: // Text
181 strcpy((PCHAR)Settings[i].SettingVar, SettingText);
182 break;
183 case 1: // Yes/No
184 *(PBOOLEAN)Settings[i].SettingVar = (_stricmp(SettingText, "Yes") == 0 && strlen(SettingText) == 3);
185 break;
186 case 2: // Color
187 *(PUCHAR)Settings[i].SettingVar = UiTextToColor(SettingText);
188 break;
189 case 3: // Fill style
190 *(PUCHAR)Settings[i].SettingVar = UiTextToFillStyle(SettingText);
191 break;
192 default:
193 break;
194 }
195 }
196 }
197
198 /* Draw the backdrop and fade it in if special effects are enabled */
199 UiFadeInBackdrop();
200
201 TRACE("UiInitialize() returning TRUE.\n");
202 return TRUE;
203 }
204
205 VOID UiUnInitialize(PCSTR BootText)
206 {
207 UiDrawBackdrop();
208 UiDrawStatusText(BootText);
209 UiInfoBox(BootText);
210
211 UiVtbl.UnInitialize();
212 }
213
214 VOID UiDrawBackdrop(VOID)
215 {
216 UiVtbl.DrawBackdrop();
217 }
218
219 VOID UiFillArea(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, CHAR FillChar, UCHAR Attr /* Color Attributes */)
220 {
221 UiVtbl.FillArea(Left, Top, Right, Bottom, FillChar, Attr);
222 }
223
224 VOID UiDrawShadow(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom)
225 {
226 UiVtbl.DrawShadow(Left, Top, Right, Bottom);
227 }
228
229 VOID UiDrawBox(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, UCHAR VertStyle, UCHAR HorzStyle, BOOLEAN Fill, BOOLEAN Shadow, UCHAR Attr)
230 {
231 UiVtbl.DrawBox(Left, Top, Right, Bottom, VertStyle, HorzStyle, Fill, Shadow, Attr);
232 }
233
234 VOID UiDrawText(ULONG X, ULONG Y, PCSTR Text, UCHAR Attr)
235 {
236 UiVtbl.DrawText(X, Y, Text, Attr);
237 }
238
239 VOID UiDrawText2(ULONG X, ULONG Y, ULONG MaxNumChars, PCSTR Text, UCHAR Attr)
240 {
241 UiVtbl.DrawText2(X, Y, MaxNumChars, Text, Attr);
242 }
243
244 VOID UiDrawCenteredText(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, PCSTR TextString, UCHAR Attr)
245 {
246 UiVtbl.DrawCenteredText(Left, Top, Right, Bottom, TextString, Attr);
247 }
248
249 VOID UiDrawStatusText(PCSTR StatusText)
250 {
251 UiVtbl.DrawStatusText(StatusText);
252 }
253
254 VOID UiUpdateDateTime(VOID)
255 {
256 UiVtbl.UpdateDateTime();
257 }
258
259 VOID UiInfoBox(PCSTR MessageText)
260 {
261 SIZE_T TextLength;
262 ULONG BoxWidth;
263 ULONG BoxHeight;
264 ULONG LineBreakCount;
265 SIZE_T Index;
266 SIZE_T LastIndex;
267 ULONG Left;
268 ULONG Top;
269 ULONG Right;
270 ULONG Bottom;
271
272 TextLength = strlen(MessageText);
273
274 // Count the new lines and the box width
275 LineBreakCount = 0;
276 BoxWidth = 0;
277 LastIndex = 0;
278 for (Index=0; Index<TextLength; Index++)
279 {
280 if (MessageText[Index] == '\n')
281 {
282 LastIndex = Index;
283 LineBreakCount++;
284 }
285 else
286 {
287 if ((Index - LastIndex) > BoxWidth)
288 {
289 BoxWidth = (ULONG)(Index - LastIndex);
290 }
291 }
292 }
293
294 // Calc the box width & height
295 BoxWidth += 6;
296 BoxHeight = LineBreakCount + 4;
297
298 // Calc the box coordinates
299 Left = (UiScreenWidth / 2) - (BoxWidth / 2);
300 Top =(UiScreenHeight / 2) - (BoxHeight / 2);
301 Right = (UiScreenWidth / 2) + (BoxWidth / 2);
302 Bottom = (UiScreenHeight / 2) + (BoxHeight / 2);
303
304 // Draw the box
305 UiDrawBox(Left,
306 Top,
307 Right,
308 Bottom,
309 VERT,
310 HORZ,
311 TRUE,
312 TRUE,
313 ATTR(UiMenuFgColor, UiMenuBgColor)
314 );
315
316 // Draw the text
317 UiDrawCenteredText(Left, Top, Right, Bottom, MessageText, ATTR(UiTextColor, UiMenuBgColor));
318 }
319
320 VOID UiMessageBox(PCSTR Format, ...)
321 {
322 CHAR Buffer[256];
323 va_list ap;
324
325 va_start(ap, Format);
326 vsnprintf(Buffer, sizeof(Buffer) - sizeof(CHAR), Format, ap);
327 UiVtbl.MessageBox(Buffer);
328 va_end(ap);
329 }
330
331 VOID UiMessageBoxCritical(PCSTR MessageText)
332 {
333 UiVtbl.MessageBoxCritical(MessageText);
334 }
335
336 UCHAR UiTextToColor(PCSTR ColorText)
337 {
338 return UiVtbl.TextToColor(ColorText);
339 }
340
341 UCHAR UiTextToFillStyle(PCSTR FillStyleText)
342 {
343 return UiVtbl.TextToFillStyle(FillStyleText);
344 }
345
346 VOID UiDrawProgressBarCenter(ULONG Position, ULONG Range, PCHAR ProgressText)
347 {
348 UiVtbl.DrawProgressBarCenter(Position, Range, ProgressText);
349 }
350
351 VOID UiDrawProgressBar(ULONG Left, ULONG Top, ULONG Right, ULONG Bottom, ULONG Position, ULONG Range, PCHAR ProgressText)
352 {
353 UiVtbl.DrawProgressBar(Left, Top, Right, Bottom, Position, Range, ProgressText);
354 }
355
356 VOID
357 UiShowMessageBoxesInSection(
358 IN ULONG_PTR SectionId)
359 {
360 ULONG Idx;
361 CHAR SettingName[80];
362 CHAR SettingValue[80];
363 PCHAR MessageBoxText;
364 ULONG MessageBoxTextSize;
365
366 if (SectionId == 0)
367 return;
368
369 /* Find all the message box settings and run them */
370 for (Idx = 0; Idx < IniGetNumSectionItems(SectionId); Idx++)
371 {
372 IniReadSettingByNumber(SectionId, Idx, SettingName, sizeof(SettingName), SettingValue, sizeof(SettingValue));
373 if (_stricmp(SettingName, "MessageBox") != 0)
374 continue;
375
376 /* Get the real length of the MessageBox text */
377 MessageBoxTextSize = IniGetSectionSettingValueSize(SectionId, Idx);
378 // if (MessageBoxTextSize <= 0)
379 // continue;
380
381 /* Allocate enough memory to hold the text */
382 MessageBoxText = FrLdrTempAlloc(MessageBoxTextSize, TAG_UI_TEXT);
383 if (!MessageBoxText)
384 continue;
385
386 /* Get the MessageBox text */
387 IniReadSettingByNumber(SectionId, Idx, SettingName, sizeof(SettingName), MessageBoxText, MessageBoxTextSize);
388
389 /* Fix it up */
390 UiEscapeString(MessageBoxText);
391
392 /* Display it */
393 UiMessageBox(MessageBoxText);
394
395 /* Free the memory */
396 FrLdrTempFree(MessageBoxText, TAG_UI_TEXT);
397 }
398 }
399
400 VOID
401 UiShowMessageBoxesInArgv(
402 IN ULONG Argc,
403 IN PCHAR Argv[])
404 {
405 ULONG LastIndex;
406 PCSTR ArgValue;
407 PCHAR MessageBoxText;
408 SIZE_T MessageBoxTextSize;
409
410 /* Find all the message box settings and run them */
411 for (LastIndex = 0;
412 (ArgValue = GetNextArgumentValue(Argc, Argv, &LastIndex, "MessageBox")) != NULL;
413 ++LastIndex)
414 {
415 /* Get the real length of the MessageBox text */
416 MessageBoxTextSize = (strlen(ArgValue) + 1) * sizeof(CHAR);
417
418 /* Allocate enough memory to hold the text */
419 MessageBoxText = FrLdrTempAlloc(MessageBoxTextSize, TAG_UI_TEXT);
420 if (!MessageBoxText)
421 continue;
422
423 /* Get the MessageBox text */
424 strcpy(MessageBoxText, ArgValue);
425
426 /* Fix it up */
427 UiEscapeString(MessageBoxText);
428
429 /* Display it */
430 UiMessageBox(MessageBoxText);
431
432 /* Free the memory */
433 FrLdrTempFree(MessageBoxText, TAG_UI_TEXT);
434 }
435 }
436
437 VOID UiEscapeString(PCHAR String)
438 {
439 ULONG Idx;
440
441 for (Idx=0; Idx<strlen(String); Idx++)
442 {
443 // Escape the new line characters
444 if (String[Idx] == '\\' && String[Idx+1] == 'n')
445 {
446 // Escape the character
447 String[Idx] = '\n';
448
449 // Move the rest of the string up
450 strcpy(&String[Idx+1], &String[Idx+2]);
451 }
452 }
453 }
454
455 VOID UiTruncateStringEllipsis(PCHAR StringText, ULONG MaxChars)
456 {
457 /* If it's too large, just add some ellipsis past the maximum */
458 if (strlen(StringText) > MaxChars)
459 strcpy(&StringText[MaxChars - 3], "...");
460 }
461
462 BOOLEAN
463 UiDisplayMenu(
464 IN PCSTR MenuHeader,
465 IN PCSTR MenuFooter OPTIONAL,
466 IN BOOLEAN ShowBootOptions,
467 IN PCSTR MenuItemList[],
468 IN ULONG MenuItemCount,
469 IN ULONG DefaultMenuItem,
470 IN LONG MenuTimeOut,
471 OUT PULONG SelectedMenuItem,
472 IN BOOLEAN CanEscape,
473 IN UiMenuKeyPressFilterCallback KeyPressFilter OPTIONAL,
474 IN PVOID Context OPTIONAL)
475 {
476 return UiVtbl.DisplayMenu(MenuHeader, MenuFooter, ShowBootOptions,
477 MenuItemList, MenuItemCount, DefaultMenuItem,
478 MenuTimeOut, SelectedMenuItem, CanEscape,
479 KeyPressFilter, Context);
480 }
481
482 VOID UiFadeInBackdrop(VOID)
483 {
484 UiVtbl.FadeInBackdrop();
485 }
486
487 VOID UiFadeOut(VOID)
488 {
489 UiVtbl.FadeOut();
490 }
491
492 BOOLEAN UiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length)
493 {
494 return UiVtbl.EditBox(MessageText, EditTextBuffer, Length);
495 }
496
497 #else
498 BOOLEAN UiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length)
499 {
500 return FALSE;
501 }
502 #endif