268 lines
8.1 KiB
Diff
268 lines
8.1 KiB
Diff
|
From b4c5f80fbfaf912553eca1b12da6fc49de4ae37f Mon Sep 17 00:00:00 2001
|
||
|
From: Michael Chang <mchang@suse.com>
|
||
|
Date: Mon, 7 Jan 2019 17:55:05 +0800
|
||
|
Subject: [PATCH] gfxmenu: support scrolling menu entry's text
|
||
|
|
||
|
If menu entry's title text is longer than its display width, the
|
||
|
overlong text simply get truncated. The only possible way to view the
|
||
|
full text is through the menu editing mode, but is a hassle switching
|
||
|
over the mode back and forth. Also menu editing mode could be password
|
||
|
protected which makes it not generally available to everyone.
|
||
|
|
||
|
This patch implemented scrolling text support to the title of grub's
|
||
|
gfxmenu to make it convenient for viewing the truncated text by pressing
|
||
|
the ctrl+l and ctrl+r to scroll the highlighted text left and right. The
|
||
|
scrolled result will remain in place to help memorizing it after
|
||
|
changing highlight to other entry.
|
||
|
---
|
||
|
grub-core/gfxmenu/gfxmenu.c | 3 +++
|
||
|
grub-core/gfxmenu/gui_label.c | 2 ++
|
||
|
grub-core/gfxmenu/gui_list.c | 38 ++++++++++++++++++++++++++++++++++
|
||
|
grub-core/gfxmenu/view.c | 48 +++++++++++++++++++++++++++++++++++++++++++
|
||
|
grub-core/normal/menu.c | 16 +++++++++++++++
|
||
|
include/grub/gfxmenu_view.h | 4 ++++
|
||
|
include/grub/menu_viewer.h | 1 +
|
||
|
7 files changed, 112 insertions(+)
|
||
|
|
||
|
diff --git a/grub-core/gfxmenu/gfxmenu.c b/grub-core/gfxmenu/gfxmenu.c
|
||
|
index 8a17dda2c..e834895fb 100644
|
||
|
--- a/grub-core/gfxmenu/gfxmenu.c
|
||
|
+++ b/grub-core/gfxmenu/gfxmenu.c
|
||
|
@@ -108,6 +108,8 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
|
||
|
view->menu = menu;
|
||
|
view->nested = nested;
|
||
|
view->first_timeout = -1;
|
||
|
+ if (menu->size)
|
||
|
+ view->menu_title_offset = grub_zalloc (sizeof (*view->menu_title_offset) * menu->size);
|
||
|
|
||
|
grub_video_set_viewport (0, 0, mode_info.width, mode_info.height);
|
||
|
if (view->double_repaint)
|
||
|
@@ -123,6 +125,7 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
|
||
|
instance->fini = grub_gfxmenu_viewer_fini;
|
||
|
instance->print_timeout = grub_gfxmenu_print_timeout;
|
||
|
instance->clear_timeout = grub_gfxmenu_clear_timeout;
|
||
|
+ instance->scroll_chosen_entry = grub_gfxmenu_scroll_chosen_entry;
|
||
|
|
||
|
grub_menu_register_viewer (instance);
|
||
|
|
||
|
diff --git a/grub-core/gfxmenu/gui_label.c b/grub-core/gfxmenu/gui_label.c
|
||
|
index a4c817891..8b1358dd4 100644
|
||
|
--- a/grub-core/gfxmenu/gui_label.c
|
||
|
+++ b/grub-core/gfxmenu/gui_label.c
|
||
|
@@ -192,6 +192,8 @@ label_set_property (void *vself, const char *name, const char *value)
|
||
|
"or `c' for a command-line.");
|
||
|
else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0)
|
||
|
value = _("enter: boot, `e': options, `c': cmd-line");
|
||
|
+ else if (grub_strcmp (value, "@SUSE_KEYMAP_SCROLL_ENTRY@") == 0)
|
||
|
+ value = _("ctrl+l: scroll entry left, ctrl+r: scroll entry right");
|
||
|
/* FIXME: Add more templates here if needed. */
|
||
|
self->template = grub_strdup (value);
|
||
|
self->text = grub_xasprintf (value, self->value);
|
||
|
diff --git a/grub-core/gfxmenu/gui_list.c b/grub-core/gfxmenu/gui_list.c
|
||
|
index 01477cdf2..90487aef4 100644
|
||
|
--- a/grub-core/gfxmenu/gui_list.c
|
||
|
+++ b/grub-core/gfxmenu/gui_list.c
|
||
|
@@ -24,6 +24,7 @@
|
||
|
#include <grub/gfxmenu_view.h>
|
||
|
#include <grub/gfxwidgets.h>
|
||
|
#include <grub/color.h>
|
||
|
+#include <grub/charset.h>
|
||
|
|
||
|
enum scrollbar_slice_mode {
|
||
|
SCROLLBAR_SLICE_WEST,
|
||
|
@@ -314,6 +315,33 @@ draw_scrollbar (list_impl_t self,
|
||
|
thumb->draw (thumb, thumbx, thumby);
|
||
|
}
|
||
|
|
||
|
+static const char *
|
||
|
+grub_utf8_offset_code (const char *src, grub_size_t srcsize, int num)
|
||
|
+{
|
||
|
+ int count = 0;
|
||
|
+ grub_uint32_t code = 0;
|
||
|
+
|
||
|
+ while (srcsize && num)
|
||
|
+ {
|
||
|
+ if (srcsize != (grub_size_t)-1)
|
||
|
+ srcsize--;
|
||
|
+ if (!grub_utf8_process ((grub_uint8_t)*src++, &code, &count))
|
||
|
+ return 0;
|
||
|
+ if (count != 0)
|
||
|
+ continue;
|
||
|
+ if (code == 0)
|
||
|
+ return 0;
|
||
|
+ if (code > GRUB_UNICODE_LAST_VALID)
|
||
|
+ return 0;
|
||
|
+ --num;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!num)
|
||
|
+ return src;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/* Draw the list of items. */
|
||
|
static void
|
||
|
draw_menu (list_impl_t self, int num_shown_items)
|
||
|
@@ -433,6 +461,16 @@ draw_menu (list_impl_t self, int num_shown_items)
|
||
|
const char *item_title =
|
||
|
grub_menu_get_entry (self->view->menu, menu_index)->title;
|
||
|
|
||
|
+ {
|
||
|
+ int off = self->view->menu_title_offset[menu_index];
|
||
|
+ const char *scrolled_title;
|
||
|
+
|
||
|
+ scrolled_title = grub_utf8_offset_code (item_title, grub_strlen (item_title), off);
|
||
|
+
|
||
|
+ if (scrolled_title)
|
||
|
+ item_title = scrolled_title;
|
||
|
+ }
|
||
|
+
|
||
|
sviewport.y = item_top + top_pad;
|
||
|
sviewport.width = viewport_width;
|
||
|
grub_gui_set_viewport (&sviewport, &svpsave);
|
||
|
diff --git a/grub-core/gfxmenu/view.c b/grub-core/gfxmenu/view.c
|
||
|
index ad5e82b81..7aed7faa1 100644
|
||
|
--- a/grub-core/gfxmenu/view.c
|
||
|
+++ b/grub-core/gfxmenu/view.c
|
||
|
@@ -37,6 +37,7 @@
|
||
|
#include <grub/gui_string_util.h>
|
||
|
#include <grub/icon_manager.h>
|
||
|
#include <grub/i18n.h>
|
||
|
+#include <grub/charset.h>
|
||
|
|
||
|
static void
|
||
|
init_terminal (grub_gfxmenu_view_t view);
|
||
|
@@ -142,6 +143,7 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view)
|
||
|
grub_free (view->title_text);
|
||
|
grub_free (view->progress_message_text);
|
||
|
grub_free (view->theme_path);
|
||
|
+ grub_free (view->menu_title_offset);
|
||
|
if (view->canvas)
|
||
|
view->canvas->component.ops->destroy (view->canvas);
|
||
|
grub_free (view);
|
||
|
@@ -410,6 +412,52 @@ grub_gfxmenu_set_chosen_entry (int entry, void *data)
|
||
|
grub_gfxmenu_redraw_menu (view);
|
||
|
}
|
||
|
|
||
|
+static int
|
||
|
+grub_utf8_get_num_code (const char *src, grub_size_t srcsize)
|
||
|
+{
|
||
|
+ int count = 0;
|
||
|
+ grub_uint32_t code = 0;
|
||
|
+ int num = 0;
|
||
|
+
|
||
|
+ while (srcsize)
|
||
|
+ {
|
||
|
+ if (srcsize != (grub_size_t)-1)
|
||
|
+ srcsize--;
|
||
|
+ if (!grub_utf8_process ((grub_uint8_t)*src++, &code, &count))
|
||
|
+ return 0;
|
||
|
+ if (count != 0)
|
||
|
+ continue;
|
||
|
+ if (code == 0)
|
||
|
+ return num;
|
||
|
+ if (code > GRUB_UNICODE_LAST_VALID)
|
||
|
+ return 0;
|
||
|
+ ++num;
|
||
|
+ }
|
||
|
+
|
||
|
+ return num;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+grub_gfxmenu_scroll_chosen_entry (void *data, int diren)
|
||
|
+{
|
||
|
+ grub_gfxmenu_view_t view = data;
|
||
|
+ const char *item_title;
|
||
|
+ int off;
|
||
|
+
|
||
|
+ if (!view->menu->size)
|
||
|
+ return;
|
||
|
+
|
||
|
+ item_title =grub_menu_get_entry (view->menu, view->selected)->title;
|
||
|
+ off = view->menu_title_offset[view->selected] + diren;
|
||
|
+
|
||
|
+ if (off < 0
|
||
|
+ || off > grub_utf8_get_num_code (item_title, grub_strlen(item_title)))
|
||
|
+ return;
|
||
|
+
|
||
|
+ view->menu_title_offset[view->selected] = off;
|
||
|
+ grub_gfxmenu_redraw_menu (view);
|
||
|
+}
|
||
|
+
|
||
|
static void
|
||
|
grub_gfxmenu_draw_terminal_box (void)
|
||
|
{
|
||
|
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
|
||
|
index e7a83c2d6..0af20d052 100644
|
||
|
--- a/grub-core/normal/menu.c
|
||
|
+++ b/grub-core/normal/menu.c
|
||
|
@@ -376,6 +376,15 @@ menu_set_chosen_entry (int entry)
|
||
|
cur->set_chosen_entry (entry, cur->data);
|
||
|
}
|
||
|
|
||
|
+static void
|
||
|
+menu_scroll_chosen_entry (int diren)
|
||
|
+{
|
||
|
+ struct grub_menu_viewer *cur;
|
||
|
+ for (cur = viewers; cur; cur = cur->next)
|
||
|
+ if (cur->scroll_chosen_entry)
|
||
|
+ cur->scroll_chosen_entry (cur->data, diren);
|
||
|
+}
|
||
|
+
|
||
|
static void
|
||
|
menu_print_timeout (int timeout)
|
||
|
{
|
||
|
@@ -755,6 +764,13 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
|
||
|
menu_set_chosen_entry (current_entry);
|
||
|
break;
|
||
|
|
||
|
+ case GRUB_TERM_CTRL | 'l':
|
||
|
+ menu_scroll_chosen_entry (1);
|
||
|
+ break;
|
||
|
+ case GRUB_TERM_CTRL | 'r':
|
||
|
+ menu_scroll_chosen_entry (-1);
|
||
|
+ break;
|
||
|
+
|
||
|
case '\n':
|
||
|
case '\r':
|
||
|
case GRUB_TERM_KEY_RIGHT:
|
||
|
diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h
|
||
|
index 4203c8fb9..56c0d17ae 100644
|
||
|
--- a/include/grub/gfxmenu_view.h
|
||
|
+++ b/include/grub/gfxmenu_view.h
|
||
|
@@ -61,6 +61,8 @@ void
|
||
|
grub_gfxmenu_print_timeout (int timeout, void *data);
|
||
|
void
|
||
|
grub_gfxmenu_set_chosen_entry (int entry, void *data);
|
||
|
+void
|
||
|
+grub_gfxmenu_scroll_chosen_entry (void *data, int diren);
|
||
|
|
||
|
grub_err_t grub_font_draw_string (const char *str,
|
||
|
grub_font_t font,
|
||
|
@@ -119,6 +121,8 @@ struct grub_gfxmenu_view
|
||
|
int nested;
|
||
|
|
||
|
int first_timeout;
|
||
|
+
|
||
|
+ int *menu_title_offset;
|
||
|
};
|
||
|
|
||
|
#endif /* ! GRUB_GFXMENU_VIEW_HEADER */
|
||
|
diff --git a/include/grub/menu_viewer.h b/include/grub/menu_viewer.h
|
||
|
index c6513c4e8..5f2a39dc9 100644
|
||
|
--- a/include/grub/menu_viewer.h
|
||
|
+++ b/include/grub/menu_viewer.h
|
||
|
@@ -33,6 +33,7 @@ struct grub_menu_viewer
|
||
|
void (*set_chosen_entry) (int entry, void *data);
|
||
|
void (*print_timeout) (int timeout, void *data);
|
||
|
void (*clear_timeout) (void *data);
|
||
|
+ void (*scroll_chosen_entry) (void *data, int diren);
|
||
|
void (*fini) (void *fini);
|
||
|
};
|
||
|
|
||
|
--
|
||
|
2.16.4
|
||
|
|