]> code.delx.au - refind/blobdiff - refind/screen.c
Improved scan_delay feature & new ability to edit boot options
[refind] / refind / screen.c
index 3b98586b5c41e706e4b5a279a145e74d4cbbfffd..e1154fff43bdd680c3040e38ed77141d059ed004 100644 (file)
@@ -48,8 +48,6 @@ UINTN ConWidth;
 UINTN ConHeight;
 CHAR16 *BlankLine;
 
-static VOID SwitchToText(IN BOOLEAN CursorEnabled);
-static VOID SwitchToGraphics(VOID);
 static VOID DrawScreenHeader(IN CHAR16 *Title);
 
 // UGA defines and variables
@@ -127,13 +125,13 @@ VOID SetupScreen(VOID)
     }
 }
 
-static VOID SwitchToText(IN BOOLEAN CursorEnabled)
+VOID SwitchToText(IN BOOLEAN CursorEnabled)
 {
     egSetGraphicsModeEnabled(FALSE);
     refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled);
 }
 
-static VOID SwitchToGraphics(VOID)
+VOID SwitchToGraphics(VOID)
 {
     if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) {
         egSetGraphicsModeEnabled(TRUE);
@@ -497,3 +495,185 @@ VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG
      egFreeImage(CompImage);
      GraphicsScreenDirty = TRUE;
 }
+
+// Line-editing functions borrowed from gummiboot (cursor_left(), cursor_right(), & line_edit())
+
+static void cursor_left(UINTN *cursor, UINTN *first)
+{
+   if ((*cursor) > 0)
+      (*cursor)--;
+   else if ((*first) > 0)
+      (*first)--;
+}
+
+static void cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len)
+{
+   if ((*cursor)+2 < x_max)
+      (*cursor)++;
+   else if ((*first) + (*cursor) < len)
+      (*first)++;
+}
+
+BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos) {
+   CHAR16 *line;
+   UINTN size;
+   UINTN len;
+   UINTN first;
+   CHAR16 *print;
+   UINTN cursor;
+   BOOLEAN exit;
+   BOOLEAN enter;
+
+   if (!line_in)
+      line_in = L"";
+   size = StrLen(line_in) + 1024;
+   line = AllocatePool(size * sizeof(CHAR16));
+   StrCpy(line, line_in);
+   len = StrLen(line);
+   print = AllocatePool(x_max * sizeof(CHAR16));
+
+   refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE);
+
+   first = 0;
+   cursor = 0;
+   enter = FALSE;
+   exit = FALSE;
+   while (!exit) {
+      UINTN index;
+      EFI_STATUS err;
+      EFI_INPUT_KEY key;
+      UINTN i;
+
+      i = len - first;
+      if (i >= x_max-2)
+         i = x_max-2;
+      CopyMem(print, line + first, i * sizeof(CHAR16));
+      print[i++] = ' ';
+      print[i] = '\0';
+
+      refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos);
+      refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print);
+      refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+
+      refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+      err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+      if (EFI_ERROR(err))
+         continue;
+
+      switch (key.ScanCode) {
+      case SCAN_ESC:
+         exit = TRUE;
+         break;
+      case SCAN_HOME:
+         cursor = 0;
+         first = 0;
+         continue;
+      case SCAN_END:
+         cursor = len;
+         if (cursor >= x_max) {
+            cursor = x_max-2;
+            first = len - (x_max-2);
+         }
+         continue;
+      case SCAN_UP:
+         while((first + cursor) && line[first + cursor] == ' ')
+            cursor_left(&cursor, &first);
+         while((first + cursor) && line[first + cursor] != ' ')
+            cursor_left(&cursor, &first);
+         while((first + cursor) && line[first + cursor] == ' ')
+            cursor_left(&cursor, &first);
+         if (first + cursor != len && first + cursor)
+            cursor_right(&cursor, &first, x_max, len);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_DOWN:
+         while(line[first + cursor] && line[first + cursor] == ' ')
+            cursor_right(&cursor, &first, x_max, len);
+         while(line[first + cursor] && line[first + cursor] != ' ')
+            cursor_right(&cursor, &first, x_max, len);
+         while(line[first + cursor] && line[first + cursor] == ' ')
+              cursor_right(&cursor, &first, x_max, len);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_RIGHT:
+         if (first + cursor == len)
+            continue;
+         cursor_right(&cursor, &first, x_max, len);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_LEFT:
+         cursor_left(&cursor, &first);
+         refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos);
+         continue;
+      case SCAN_DELETE:
+         if (len == 0)
+            continue;
+         if (first + cursor == len)
+            continue;
+         for (i = first + cursor; i < len; i++)
+            line[i] = line[i+1];
+         line[len-1] = ' ';
+         len--;
+         continue;
+      }
+
+      switch (key.UnicodeChar) {
+      case CHAR_LINEFEED:
+      case CHAR_CARRIAGE_RETURN:
+         if (StrCmp(line, line_in) != 0) {
+            *line_out = line;
+            line = NULL;
+         }
+         enter = TRUE;
+         exit = TRUE;
+         break;
+      case CHAR_BACKSPACE:
+         if (len == 0)
+            continue;
+         if (first == 0 && cursor == 0)
+            continue;
+         for (i = first + cursor-1; i < len; i++)
+            line[i] = line[i+1];
+         len--;
+         if (cursor > 0)
+            cursor--;
+         if (cursor > 0 || first == 0)
+            continue;
+         /* show full line if it fits */
+         if (len < x_max-2) {
+            cursor = first;
+            first = 0;
+            continue;
+         }
+         /* jump left to see what we delete */
+         if (first > 10) {
+            first -= 10;
+            cursor = 10;
+         } else {
+            cursor = first;
+            first = 0;
+         }
+         continue;
+      case '\t':
+      case ' ' ... '~':
+      case 0x80 ... 0xffff:
+         if (len+1 == size)
+            continue;
+         for (i = len; i > first + cursor; i--)
+            line[i] = line[i-1];
+         line[first + cursor] = key.UnicodeChar;
+         len++;
+         line[len] = '\0';
+         if (cursor+2 < x_max)
+            cursor++;
+         else if (first + cursor < len)
+            first++;
+         continue;
+      }
+   }
+
+   refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE);
+   FreePool(print);
+   FreePool(line);
+   return enter;
+} /* BOOLEAN line_edit() */