]> code.delx.au - refind/blobdiff - refind/menu.c
Refinements to PNG support.
[refind] / refind / menu.c
index 7de9d8bc3b9d462a0d590984cd00bc9ef7a61287..7f0265261dd7ebb5af73fef25ebce75e648930c9 100644 (file)
@@ -48,6 +48,7 @@
 #include "menu.h"
 #include "config.h"
 #include "libeg.h"
+#include "libegint.h"
 #include "../include/refit_call_wrapper.h"
 
 #include "../include/egemb_back_selected_small.h"
@@ -68,6 +69,7 @@ typedef VOID (*MENU_STYLE_FUNC)(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *S
 static CHAR16 ArrowUp[2] = { ARROW_UP, 0 };
 static CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 };
 
+// Text and icon spacing constants....
 #define TEXT_YMARGIN (2)
 #define TEXT_XMARGIN (8)
 #define TEXT_LINE_HEIGHT (FONT_CELL_HEIGHT + TEXT_YMARGIN * 2)
@@ -82,7 +84,7 @@ static CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 };
 #define ALIGN_RIGHT 1
 #define ALIGN_LEFT 0
 
-static EG_IMAGE *SelectionImages[4] = { NULL, NULL, NULL, NULL };
+static EG_IMAGE *SelectionImages[2] = { NULL, NULL };
 static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 };
 static EG_IMAGE *TextBuffer = NULL;
 
@@ -102,33 +104,33 @@ static VOID InitSelection(VOID)
 
     // load small selection image
     if (GlobalConfig.SelectionSmallFileName != NULL) {
-        SelectionImages[2] = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, FALSE);
+        SelectionImages[1] = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, TRUE);
     }
-    if (SelectionImages[2] == NULL)
-        SelectionImages[2] = egPrepareEmbeddedImage(&egemb_back_selected_small, FALSE);
-    SelectionImages[2] = egEnsureImageSize(SelectionImages[2],
+    if (SelectionImages[1] == NULL)
+        SelectionImages[1] = egPrepareEmbeddedImage(&egemb_back_selected_small, TRUE);
+    SelectionImages[1] = egEnsureImageSize(SelectionImages[1],
                                            ROW1_TILESIZE, ROW1_TILESIZE, &MenuBackgroundPixel);
-    if (SelectionImages[2] == NULL)
+    if (SelectionImages[1] == NULL)
         return;
 
     // load big selection image
     if (GlobalConfig.SelectionBigFileName != NULL) {
-        SelectionImages[0] = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, FALSE);
+        SelectionImages[0] = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, TRUE);
         SelectionImages[0] = egEnsureImageSize(SelectionImages[0],
                                                ROW0_TILESIZE, ROW0_TILESIZE, &MenuBackgroundPixel);
     }
     if (SelectionImages[0] == NULL) {
         // calculate big selection image from small one
 
-        SelectionImages[0] = egCreateImage(ROW0_TILESIZE, ROW0_TILESIZE, FALSE);
+        SelectionImages[0] = egCreateImage(ROW0_TILESIZE, ROW0_TILESIZE, TRUE);
         if (SelectionImages[0] == NULL) {
-            egFreeImage(SelectionImages[2]);
-            SelectionImages[2] = NULL;
+            egFreeImage(SelectionImages[1]);
+            SelectionImages[1] = NULL;
             return;
         }
 
         DestPtr = SelectionImages[0]->PixelData;
-        SrcPtr  = SelectionImages[2]->PixelData;
+        SrcPtr  = SelectionImages[1]->PixelData;
         for (y = 0; y < ROW0_TILESIZE; y++) {
             if (y < (ROW1_TILESIZE >> 1))
                 src_y = y;
@@ -149,11 +151,7 @@ static VOID InitSelection(VOID)
             }
         }
     }
-
-    // non-selected background images
-    SelectionImages[1] = egCreateFilledImage(ROW0_TILESIZE, ROW0_TILESIZE, FALSE, &MenuBackgroundPixel);
-    SelectionImages[3] = egCreateFilledImage(ROW1_TILESIZE, ROW1_TILESIZE, FALSE, &MenuBackgroundPixel);
-}
+} // VOID InitSelection()
 
 //
 // Scrolling functions
@@ -544,9 +542,6 @@ static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State,
                 MergeStrings(&DisplayStrings[i], Screen->Entries[i]->Title, 0);
                 if (StrLen(DisplayStrings[i]) > MenuWidth)
                    DisplayStrings[i][MenuWidth - 1] = 0;
-//                DisplayStrings[i] = AllocateZeroPool(256 * sizeof(CHAR16));
-//                SPrint(DisplayStrings[i], ((MenuWidth < 255) ? MenuWidth : 255) * sizeof(CHAR16),
-//                       L" %s ", Screen->Entries[i]->Title);
                 // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle)
                 // TODO: account for double-width characters
             } // for
@@ -641,10 +636,11 @@ static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State,
 //
 
 
-static VOID DrawMenuText(IN CHAR16 *Text, IN UINTN SelectedWidth, IN UINTN XPos, IN UINTN YPos)
+// Display a submenu
+static VOID DrawSubmenuText(IN CHAR16 *Text, IN UINTN SelectedWidth, IN UINTN XPos, IN UINTN YPos)
 {
     if (TextBuffer == NULL)
-        TextBuffer = egCreateImage(LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT, FALSE);
+        TextBuffer = egCreateImage(LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT, TRUE);
 
     egFillImage(TextBuffer, &MenuBackgroundPixel);
     if (SelectedWidth > 0) {
@@ -655,7 +651,8 @@ static VOID DrawMenuText(IN CHAR16 *Text, IN UINTN SelectedWidth, IN UINTN XPos,
 
     // render the text
     egRenderText(Text, TextBuffer, TEXT_XMARGIN, TEXT_YMARGIN);
-    BltImage(TextBuffer, XPos, YPos);
+    egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height);
+//    BltImage(TextBuffer, XPos, YPos);
 }
 
 // Displays sub-menus
@@ -691,20 +688,18 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta
                 EntriesPosX = (UGAWidth + (Screen->TitleImage->Width + TITLEICON_SPACING) - MenuWidth) >> 1;
             else
                 EntriesPosX = (UGAWidth - MenuWidth) >> 1;
-            EntriesPosY = ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_YOFFSET + TEXT_LINE_HEIGHT * 2;
+            EntriesPosY = ComputeRow0PosX() + TEXT_LINE_HEIGHT * 2;
             TimeoutPosY = EntriesPosY + (Screen->EntryCount + 1) * TEXT_LINE_HEIGHT;
 
             // initial painting
             SwitchToGraphicsAndClear();
             egMeasureText(Screen->Title, &ItemWidth, NULL);
-            DrawMenuText(Screen->Title, 0, ((UGAWidth - ItemWidth) >> 1) - TEXT_XMARGIN, EntriesPosY - TEXT_LINE_HEIGHT * 2);
+            DrawSubmenuText(Screen->Title, 0, ((UGAWidth - ItemWidth) >> 1) - TEXT_XMARGIN, EntriesPosY - TEXT_LINE_HEIGHT * 2);
             if (Screen->TitleImage)
-                BltImageAlpha(Screen->TitleImage,
-                              EntriesPosX - (Screen->TitleImage->Width + TITLEICON_SPACING), EntriesPosY,
-                              &MenuBackgroundPixel);
+               BltImage(Screen->TitleImage, EntriesPosX - (Screen->TitleImage->Width + TITLEICON_SPACING), EntriesPosY);
             if (Screen->InfoLineCount > 0) {
                 for (i = 0; i < (INTN)Screen->InfoLineCount; i++) {
-                    DrawMenuText(Screen->InfoLines[i], 0, EntriesPosX, EntriesPosY);
+                    DrawSubmenuText(Screen->InfoLines[i], 0, EntriesPosX, EntriesPosY);
                     EntriesPosY += TEXT_LINE_HEIGHT;
                 }
                 EntriesPosY += TEXT_LINE_HEIGHT;  // also add a blank line
@@ -718,16 +713,16 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta
 
         case MENU_FUNCTION_PAINT_ALL:
             for (i = 0; i <= State->MaxIndex; i++) {
-                DrawMenuText(Screen->Entries[i]->Title, (i == State->CurrentSelection) ? MenuWidth : 0,
+                DrawSubmenuText(Screen->Entries[i]->Title, (i == State->CurrentSelection) ? MenuWidth : 0,
                              EntriesPosX, EntriesPosY + i * TEXT_LINE_HEIGHT);
             }
             if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) {
                if ((Screen->Hint1 != NULL) && (StrLen(Screen->Hint1) > 0)) {
-                  DrawMenuText(Screen->Hint1, 0, (UGAWidth - (StrLen(Screen->Hint1) * FONT_CELL_WIDTH)) / 2,
+                  DrawSubmenuText(Screen->Hint1, 0, (UGAWidth - (StrLen(Screen->Hint1) * FONT_CELL_WIDTH)) / 2,
                                UGAHeight - (FONT_CELL_HEIGHT * 3));
                }
                if ((Screen->Hint2 != NULL) && (StrLen(Screen->Hint2) > 0)) {
-                  DrawMenuText(Screen->Hint2, 0, (UGAWidth - (StrLen(Screen->Hint2) * FONT_CELL_WIDTH)) / 2,
+                  DrawSubmenuText(Screen->Hint2, 0, (UGAWidth - (StrLen(Screen->Hint2) * FONT_CELL_WIDTH)) / 2,
                                UGAHeight - (FONT_CELL_HEIGHT * 2));
                } // if
             } // if
@@ -735,14 +730,14 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta
 
         case MENU_FUNCTION_PAINT_SELECTION:
             // redraw selection cursor
-            DrawMenuText(Screen->Entries[State->PreviousSelection]->Title, 0,
+            DrawSubmenuText(Screen->Entries[State->PreviousSelection]->Title, 0,
                          EntriesPosX, EntriesPosY + State->PreviousSelection * TEXT_LINE_HEIGHT);
-            DrawMenuText(Screen->Entries[State->CurrentSelection]->Title, MenuWidth,
+            DrawSubmenuText(Screen->Entries[State->CurrentSelection]->Title, MenuWidth,
                          EntriesPosX, EntriesPosY + State->CurrentSelection * TEXT_LINE_HEIGHT);
             break;
 
         case MENU_FUNCTION_PAINT_TIMEOUT:
-            DrawMenuText(ParamText, 0, EntriesPosX, TimeoutPosY);
+            DrawSubmenuText(ParamText, 0, EntriesPosX, TimeoutPosY);
             break;
 
     }
@@ -754,22 +749,26 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta
 
 static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN XPos, UINTN YPos)
 {
-    UINTN ImageNum;
-
-    ImageNum = ((Entry->Row == 0) ? 0 : 2) + (selected ? 0 : 1);
-    if (SelectionImages != NULL)
-        BltImageCompositeBadge(SelectionImages[ImageNum],
-                               Entry->Image, Entry->BadgeImage, XPos, YPos);
-}
+   EG_IMAGE *Background;
+
+   if (SelectionImages != NULL) {
+      if (selected) {
+         Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos,
+                                  SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height);
+         egComposeImage(Background, SelectionImages[Entry->Row], 0, 0);
+         BltImageCompositeBadge(Background, Entry->Image, Entry->BadgeImage, XPos, YPos);
+      } else { // Image not selected; copy background
+         egDrawImageWithTransparency(Entry->Image, Entry->BadgeImage, XPos, YPos,
+                                     SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height);
+      } // if/else
+   } // if
+} // VOID DrawMainMenuEntry()
 
 static VOID DrawMainMenuText(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos)
 {
     UINTN TextWidth, TextPosX;
 
-    if (TextBuffer == NULL)
-        TextBuffer = egCreateImage(LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT, FALSE);
-
-    egFillImage(TextBuffer, &MenuBackgroundPixel);
+    TextBuffer = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT);
 
     // render the text
     egMeasureText(Text, &TextWidth, NULL);
@@ -778,8 +777,7 @@ static VOID DrawMainMenuText(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos)
     else
        TextPosX = (TextBuffer->Width - TextWidth) / 2;
     egRenderText(Text, TextBuffer, TextPosX, 0);
-//    egRenderText(Text, TextBuffer, (TextBuffer->Width - TextWidth) >> 1, 0);
-    BltImage(TextBuffer, XPos, YPos);
+    egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height);
 }
 
 static VOID PaintAll(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX,
@@ -855,10 +853,50 @@ static VOID PaintIcon(IN EG_EMBEDDED_IMAGE *BuiltInIcon, IN CHAR16 *ExternalFile
    if (Icon != NULL) {
       if (Alignment == ALIGN_RIGHT)
          PosX -= Icon->Width;
-      BltImageAlpha(Icon, PosX, PosY - (Icon->Height / 2), &MenuBackgroundPixel);
+      egDrawImageWithTransparency(Icon, NULL, PosX, PosY - (Icon->Height / 2), Icon->Width, Icon->Height);
    }
 } // static VOID PaintIcon()
 
+inline UINTN ComputeRow0PosX(VOID) {
+//   return ((UGAHeight / 2) - (5 * ROW0_TILESIZE / 6));
+   return ((UGAHeight / 2) - ROW0_TILESIZE / 2);
+} // UINTN ComputeRow0PosX()
+
+// Display (or erase) the arrow icons to the left and right of an icon's row,
+// as appropriate.
+static VOID PaintArrows(SCROLL_STATE *State, UINTN PosX, UINTN PosY, UINTN row0Loaders) {
+   CHAR16 FileName[256];
+   EG_IMAGE *TempImage;
+   UINTN Width, Height, RightX, AdjPosY;
+
+   // NOTE: Assume that left and right arrows are of the same size....
+   Width = egemb_arrow_left.Width;
+   Height = egemb_arrow_left.Height;
+   RightX = (UGAWidth + (ROW0_TILESIZE + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING;
+   AdjPosY = PosY - (Height / 2);
+
+   // For PaintIcon() calls, the starting Y position is moved to the midpoint
+   // of the surrounding row; PaintIcon() adjusts this back up by half the
+   // icon's height to properly center it.
+   if ((State->FirstVisible > 0) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) {
+      SPrint(FileName, 255, L"%s\\arrow_left.icns", GlobalConfig.IconsDir ? GlobalConfig.IconsDir : DEFAULT_ICONS_DIR);
+      PaintIcon(&egemb_arrow_left, FileName, PosX, PosY, ALIGN_RIGHT);
+   } else {
+      TempImage = egCropImage(GlobalConfig.ScreenBackground, PosX - Width, AdjPosY, Width, Height);
+      BltImage(TempImage, PosX - Width, AdjPosY);
+      egFreeImage(TempImage);
+   } // if/else
+
+   if ((State->LastVisible < (row0Loaders - 1)) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) {
+      SPrint(FileName, 255, L"%s\\arrow_right.icns", GlobalConfig.IconsDir ? GlobalConfig.IconsDir : DEFAULT_ICONS_DIR);
+      PaintIcon(&egemb_arrow_right, FileName, RightX, PosY, ALIGN_LEFT);
+   } else {
+      TempImage = egCropImage(GlobalConfig.ScreenBackground, RightX, AdjPosY, Width, Height);
+      BltImage(TempImage, RightX, AdjPosY);
+      egFreeImage(TempImage);
+   } // if/else
+} // VOID PaintArrows()
+
 // Display main menu in graphics mode
 VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText)
 {
@@ -867,7 +905,6 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT
     UINTN row0Count, row1Count, row1PosX, row1PosXRunning;
     static UINTN *itemPosX;
     static UINTN row0PosY, textPosY;
-    CHAR16 FileName[256];
 
     State->ScrollMode = SCROLL_MODE_ICONS;
     switch (Function) {
@@ -889,7 +926,7 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT
                }
             }
             row0PosX = (UGAWidth + TILE_XSPACING - (ROW0_TILESIZE + TILE_XSPACING) * row0Count) >> 1;
-            row0PosY = ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_YOFFSET;
+            row0PosY = ComputeRow0PosX();
             row1PosX = (UGAWidth + TILE_XSPACING - (ROW1_TILESIZE + TILE_XSPACING) * row1Count) >> 1;
             row1PosY = row0PosY + ROW0_TILESIZE + TILE_YSPACING;
             if (row1Count > 0)
@@ -919,22 +956,11 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT
             break;
 
         case MENU_FUNCTION_PAINT_ALL:
-            BltClearScreen(TRUE);
             PaintAll(Screen, State, itemPosX, row0PosY, row1PosY, textPosY);
-            // For PaintIcon() calls, the starting Y position is moved to the midpoint
+            // For PaintArrows(), the starting Y position is moved to the midpoint
             // of the surrounding row; PaintIcon() adjusts this back up by half the
             // icon's height to properly center it.
-            if ((State->FirstVisible > 0) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) {
-               SPrint(FileName, 255, L"%s\\arrow_left.icns", GlobalConfig.IconsDir ? GlobalConfig.IconsDir : DEFAULT_ICONS_DIR);
-               PaintIcon(&egemb_arrow_left, FileName, row0PosX - TILE_XSPACING,
-                         row0PosY + (ROW0_TILESIZE / 2), ALIGN_RIGHT);
-            } // if
-            if ((State->LastVisible < (row0Loaders - 1)) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) {
-               SPrint(FileName, 255, L"%s\\arrow_right.icns", GlobalConfig.IconsDir ? GlobalConfig.IconsDir : DEFAULT_ICONS_DIR);
-               PaintIcon(&egemb_arrow_right, FileName,
-                         (UGAWidth + (ROW0_TILESIZE + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING,
-                         row0PosY + (ROW0_TILESIZE / 2), ALIGN_LEFT);
-            } // if
+            PaintArrows(State, row0PosX - TILE_XSPACING, row0PosY + (ROW0_TILESIZE / 2), row0Loaders);
             break;
 
         case MENU_FUNCTION_PAINT_SELECTION: