Unverified Commit 15b8b1f3 authored by A1ive's avatar A1ive Committed by GitHub
Browse files

support scrolling menu entry's text (#1539)

parent a20592ec
...@@ -119,6 +119,8 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) ...@@ -119,6 +119,8 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
view->menu = menu; view->menu = menu;
view->nested = nested; view->nested = nested;
view->first_timeout = -1; 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); grub_video_set_viewport (0, 0, mode_info.width, mode_info.height);
if (view->double_repaint) if (view->double_repaint)
...@@ -134,6 +136,8 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) ...@@ -134,6 +136,8 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
instance->fini = grub_gfxmenu_viewer_fini; instance->fini = grub_gfxmenu_viewer_fini;
instance->print_timeout = grub_gfxmenu_print_timeout; instance->print_timeout = grub_gfxmenu_print_timeout;
instance->clear_timeout = grub_gfxmenu_clear_timeout; instance->clear_timeout = grub_gfxmenu_clear_timeout;
if (view->menu_title_offset)
instance->scroll_chosen_entry = grub_gfxmenu_scroll_chosen_entry;
grub_menu_register_viewer (instance); grub_menu_register_viewer (instance);
......
This diff is collapsed.
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <grub/gui_string_util.h> #include <grub/gui_string_util.h>
#include <grub/icon_manager.h> #include <grub/icon_manager.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/charset.h>
static void static void
init_terminal (grub_gfxmenu_view_t view); init_terminal (grub_gfxmenu_view_t view);
...@@ -142,6 +143,8 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) ...@@ -142,6 +143,8 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view)
grub_free (view->title_text); grub_free (view->title_text);
grub_free (view->progress_message_text); grub_free (view->progress_message_text);
grub_free (view->theme_path); grub_free (view->theme_path);
if (view->menu_title_offset)
grub_free (view->menu_title_offset);
if (view->canvas) if (view->canvas)
view->canvas->component.ops->destroy (view->canvas); view->canvas->component.ops->destroy (view->canvas);
grub_free (view); grub_free (view);
...@@ -428,6 +431,27 @@ grub_gfxmenu_set_chosen_entry (int entry, void *data) ...@@ -428,6 +431,27 @@ grub_gfxmenu_set_chosen_entry (int entry, void *data)
} }
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 static void
grub_gfxmenu_draw_terminal_box (void) grub_gfxmenu_draw_terminal_box (void)
{ {
......
This diff is collapsed.
...@@ -461,6 +461,15 @@ menu_set_chosen_entry (grub_menu_t menu, int entry) ...@@ -461,6 +461,15 @@ menu_set_chosen_entry (grub_menu_t menu, int entry)
cur->set_chosen_entry (entry, cur->data); 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 static void
menu_print_timeout (int timeout) menu_print_timeout (int timeout)
{ {
...@@ -846,6 +855,13 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) ...@@ -846,6 +855,13 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
menu_set_chosen_entry (menu, current_entry); menu_set_chosen_entry (menu, current_entry);
break; break;
case GRUB_TERM_KEY_RIGHT:
menu_scroll_chosen_entry (1);
break;
case GRUB_TERM_KEY_LEFT:
menu_scroll_chosen_entry (-1);
break;
case '\n': case '\n':
case '\r': case '\r':
// case GRUB_TERM_KEY_RIGHT: // case GRUB_TERM_KEY_RIGHT:
......
...@@ -42,6 +42,7 @@ struct menu_viewer_data ...@@ -42,6 +42,7 @@ struct menu_viewer_data
TIMEOUT_TERSE_NO_MARGIN TIMEOUT_TERSE_NO_MARGIN
} timeout_msg; } timeout_msg;
grub_menu_t menu; grub_menu_t menu;
int *menu_title_offset;
struct grub_term_output *term; struct grub_term_output *term;
}; };
...@@ -524,6 +525,37 @@ menu_text_set_chosen_entry (int entry, void *dataptr) ...@@ -524,6 +525,37 @@ menu_text_set_chosen_entry (int entry, void *dataptr)
grub_term_refresh (data->term); grub_term_refresh (data->term);
} }
static void
menu_text_scroll_chosen_entry (void *dataptr, int diren)
{
struct menu_viewer_data *data = dataptr;
const char *orig_title, *scrolled_title;
int off;
int selected;
grub_menu_entry_t entry;
if (!data->menu->size)
return;
selected = data->first + data->offset;
entry = grub_menu_get_entry (data->menu, selected);
orig_title = entry->title;
off = data->menu_title_offset[selected] + diren;
if (off < 0
|| off > grub_utf8_get_num_code (orig_title, grub_strlen(orig_title)))
return;
scrolled_title =
grub_utf8_offset_code (orig_title, grub_strlen (orig_title), off);
if (scrolled_title)
entry->title = scrolled_title;
print_entry (data->geo.first_entry_y + data->offset, 1, entry, data);
entry->title = orig_title;
data->menu_title_offset[selected] = off;
grub_term_refresh (data->term);
}
static void static void
menu_text_fini (void *dataptr) menu_text_fini (void *dataptr)
{ {
...@@ -531,6 +563,8 @@ menu_text_fini (void *dataptr) ...@@ -531,6 +563,8 @@ menu_text_fini (void *dataptr)
grub_term_setcursor (data->term, 1); grub_term_setcursor (data->term, 1);
grub_term_cls (data->term); grub_term_cls (data->term);
if (data->menu_title_offset)
grub_free (data->menu_title_offset);
grub_free (data); grub_free (data);
} }
...@@ -585,9 +619,14 @@ grub_menu_try_text (struct grub_term_output *term, ...@@ -585,9 +619,14 @@ grub_menu_try_text (struct grub_term_output *term,
return grub_errno; return grub_errno;
} }
if (menu->size)
data->menu_title_offset = grub_zalloc (sizeof (*data->menu_title_offset) * menu->size);
data->term = term; data->term = term;
instance->data = data; instance->data = data;
instance->set_chosen_entry = menu_text_set_chosen_entry; instance->set_chosen_entry = menu_text_set_chosen_entry;
if (data->menu_title_offset)
instance->scroll_chosen_entry = menu_text_scroll_chosen_entry;
instance->print_timeout = menu_text_print_timeout; instance->print_timeout = menu_text_print_timeout;
instance->clear_timeout = menu_text_clear_timeout; instance->clear_timeout = menu_text_clear_timeout;
instance->fini = menu_text_fini; instance->fini = menu_text_fini;
......
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_CHARSET_HEADER
#define GRUB_CHARSET_HEADER 1
#include <grub/types.h>
#define GRUB_UINT8_1_LEADINGBIT 0x80
#define GRUB_UINT8_2_LEADINGBITS 0xc0
#define GRUB_UINT8_3_LEADINGBITS 0xe0
#define GRUB_UINT8_4_LEADINGBITS 0xf0
#define GRUB_UINT8_5_LEADINGBITS 0xf8
#define GRUB_UINT8_6_LEADINGBITS 0xfc
#define GRUB_UINT8_7_LEADINGBITS 0xfe
#define GRUB_UINT8_1_TRAILINGBIT 0x01
#define GRUB_UINT8_2_TRAILINGBITS 0x03
#define GRUB_UINT8_3_TRAILINGBITS 0x07
#define GRUB_UINT8_4_TRAILINGBITS 0x0f
#define GRUB_UINT8_5_TRAILINGBITS 0x1f
#define GRUB_UINT8_6_TRAILINGBITS 0x3f
#define GRUB_MAX_UTF8_PER_UTF16 4
/* You need at least one UTF-8 byte to have one UTF-16 word.
You need at least three UTF-8 bytes to have 2 UTF-16 words (surrogate pairs).
*/
#define GRUB_MAX_UTF16_PER_UTF8 1
#define GRUB_MAX_UTF8_PER_CODEPOINT 4
#define GRUB_UCS2_LIMIT 0x10000
#define GRUB_UTF16_UPPER_SURROGATE(code) \
(0xD800 | ((((code) - GRUB_UCS2_LIMIT) >> 10) & 0x3ff))
#define GRUB_UTF16_LOWER_SURROGATE(code) \
(0xDC00 | (((code) - GRUB_UCS2_LIMIT) & 0x3ff))
/* Process one character from UTF8 sequence.
At beginning set *code = 0, *count = 0. Returns 0 on failure and
1 on success. *count holds the number of trailing bytes. */
static inline int
grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count)
{
if (*count)
{
if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT)
{
*count = 0;
/* invalid */
return 0;
}
else
{
*code <<= 6;
*code |= (c & GRUB_UINT8_6_TRAILINGBITS);
(*count)--;
/* Overlong. */
if ((*count == 1 && *code <= 0x1f)
|| (*count == 2 && *code <= 0xf))
{
*code = 0;
*count = 0;
return 0;
}
return 1;
}
}
if ((c & GRUB_UINT8_1_LEADINGBIT) == 0)
{
*code = c;
return 1;
}
if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS)
{
*count = 1;
*code = c & GRUB_UINT8_5_TRAILINGBITS;
/* Overlong */
if (*code <= 1)
{
*count = 0;
*code = 0;
return 0;
}
return 1;
}
if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS)
{
*count = 2;
*code = c & GRUB_UINT8_4_TRAILINGBITS;
return 1;
}
if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS)
{
*count = 3;
*code = c & GRUB_UINT8_3_TRAILINGBITS;
return 1;
}
return 0;
}
/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string.
Return the number of characters converted. DEST must be able to hold
at least DESTSIZE characters. If an invalid sequence is found, return -1.
If SRCEND is not NULL, then *SRCEND is set to the next byte after the
last byte used in SRC. */
static inline grub_size_t
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
const grub_uint8_t *src, grub_size_t srcsize,
const grub_uint8_t **srcend)
{
grub_uint16_t *p = dest;
int count = 0;
grub_uint32_t code = 0;
if (srcend)
*srcend = src;
while (srcsize && destsize)
{
int was_count = count;
if (srcsize != (grub_size_t)-1)
srcsize--;
if (!grub_utf8_process (*src++, &code, &count))
{
code = '?';
count = 0;
/* Character c may be valid, don't eat it. */
if (was_count)
src--;
}
if (count != 0)
continue;
if (code == 0)
break;
if (destsize < 2 && code >= GRUB_UCS2_LIMIT)
break;
if (code >= GRUB_UCS2_LIMIT)
{
*p++ = GRUB_UTF16_UPPER_SURROGATE (code);
*p++ = GRUB_UTF16_LOWER_SURROGATE (code);
destsize -= 2;
}
else
{
*p++ = code;
destsize--;
}
}
if (srcend)
*srcend = src;
return p - dest;
}
/* Determine the last position where the UTF-8 string [beg, end) can
be safely cut. */
static inline grub_size_t
grub_getend (const char *beg, const char *end)
{
const char *ptr;
for (ptr = end - 1; ptr >= beg; ptr--)
if ((*ptr & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT)
break;
if (ptr < beg)
return 0;
if ((*ptr & GRUB_UINT8_1_LEADINGBIT) == 0)
return ptr + 1 - beg;
if ((*ptr & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS
&& ptr + 2 <= end)
return ptr + 2 - beg;
if ((*ptr & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS
&& ptr + 3 <= end)
return ptr + 3 - beg;
if ((*ptr & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS
&& ptr + 4 <= end)
return ptr + 4 - beg;
/* Invalid character or incomplete. Cut before it. */
return ptr - beg;
}
/* Convert UTF-16 to UTF-8. */
static inline grub_uint8_t *
grub_utf16_to_utf8 (grub_uint8_t *dest, const grub_uint16_t *src,
grub_size_t size)
{
grub_uint32_t code_high = 0;
while (size--)
{
grub_uint32_t code = *src++;
if (code_high)
{
if (code >= 0xDC00 && code <= 0xDFFF)
{
/* Surrogate pair. */
code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
*dest++ = (code >> 18) | 0xF0;
*dest++ = ((code >> 12) & 0x3F) | 0x80;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
else
{
/* Error... */
*dest++ = '?';
/* *src may be valid. Don't eat it. */
src--;
}
code_high = 0;
}
else
{
if (code <= 0x007F)
*dest++ = code;
else if (code <= 0x07FF)
{
*dest++ = (code >> 6) | 0xC0;
*dest++ = (code & 0x3F) | 0x80;
}
else if (code >= 0xD800 && code <= 0xDBFF)
{
code_high = code;
continue;
}
else if (code >= 0xDC00 && code <= 0xDFFF)
{
/* Error... */
*dest++ = '?';
}
else if (code < 0x10000)
{
*dest++ = (code >> 12) | 0xE0;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
else
{
*dest++ = (code >> 18) | 0xF0;
*dest++ = ((code >> 12) & 0x3F) | 0x80;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
}
}
return dest;
}
#define GRUB_MAX_UTF8_PER_LATIN1 2
/* Convert Latin1 to UTF-8. */
static inline grub_uint8_t *
grub_latin1_to_utf8 (grub_uint8_t *dest, const grub_uint8_t *src,
grub_size_t size)
{
while (size--)
{
if (!(*src & 0x80))
*dest++ = *src;
else
{
*dest++ = (*src >> 6) | 0xC0;
*dest++ = (*src & 0x3F) | 0x80;
}
src++;
}
return dest;
}
/* Convert UCS-4 to UTF-8. */
char *grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size);
int
grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize);
grub_ssize_t grub_utf8_to_ucs4_alloc (const char *msg,
grub_uint32_t **unicode_msg,
grub_uint32_t **last_position);
/* Returns the number of bytes the string src would occupy is converted
to UTF-8, excluding \0. */
grub_size_t
grub_get_num_of_utf8_bytes (const grub_uint32_t *src, grub_size_t size);
/* Converts UCS-4 to UTF-8. Returns the number of bytes effectively written
excluding the trailing \0. */
grub_size_t
grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size,
grub_uint8_t *dest, grub_size_t destsize);
grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
const grub_uint8_t *src, grub_size_t srcsize,
const grub_uint8_t **srcend);
/* Returns -2 if not enough space, -1 on invalid character. */
grub_ssize_t
grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend,
grub_uint32_t code);
const grub_uint32_t *
grub_unicode_get_comb_start (const grub_uint32_t *str,
const grub_uint32_t *cur);
int
grub_utf8_get_num_code (const char *src, grub_size_t srcsize);
const char *
grub_utf8_offset_code (const char *src, grub_size_t srcsize, int num);
#endif
/* gfxmenu_view.h - gfxmenu view interface. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_GFXMENU_VIEW_HEADER
#define GRUB_GFXMENU_VIEW_HEADER 1
#include <grub/types.h>
#include <grub/err.h>
#include <grub/menu.h>
#include <grub/font.h>
#include <grub/gfxwidgets.h>
struct grub_gfxmenu_view; /* Forward declaration of opaque type. */
typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t;
grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path,
int width, int height);
void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view);
/* Set properties on the view based on settings from the specified
theme file. */
grub_err_t grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view,
const char *theme_path);
grub_err_t grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr,
const char *pattern, const char *theme_dir);
void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view);
void
grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view);
void
grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view);
void
grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view,
const grub_video_rect_t *region);
void
grub_gfxmenu_clear_timeout (void *data);
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,
grub_video_color_t color,
int left_x, int baseline_y);
int grub_font_get_string_width (grub_font_t font,
const char *str);
/* Implementation details -- this should not be used outside of the
view itself. */
#include <grub/video.h>
#include <grub/bitmap.h>
#include <grub/bitmap_scale.h>
#include <grub/gui.h>
#include <grub/gfxwidgets.h>
#include <grub/icon_manager.h>
/* Definition of the private representation of the view. */
struct grub_gfxmenu_view
{
grub_video_rect_t screen;
int need_to_check_sanity;
grub_video_rect_t terminal_rect;
int terminal_border;
grub_font_t title_font;
grub_font_t message_font;
char *terminal_font_name;
grub_video_rgba_color_t title_color;
grub_video_rgba_color_t message_color;
grub_video_rgba_color_t message_bg_color;
struct grub_video_bitmap *raw_desktop_image;
struct grub_video_bitmap *scaled_desktop_image;
grub_video_bitmap_selection_method_t desktop_image_scale_method;
grub_video_bitmap_h_align_t desktop_image_h_align;
grub_video_bitmap_v_align_t desktop_image_v_align;
grub_video_rgba_color_t desktop_color;
grub_gfxmenu_box_t terminal_box;
char *title_text;
char *progress_message_text;
char *theme_path;
grub_gui_container_t canvas;
int double_repaint;
int selected;
grub_video_rect_t progress_message_frame;
grub_menu_t menu;
int nested;
int first_timeout;
int *menu_title_offset;
};
#endif /* ! GRUB_GFXMENU_VIEW_HEADER */
/* menu_viewer.h - Interface to menu viewer implementations. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_MENU_VIEWER_HEADER
#define GRUB_MENU_VIEWER_HEADER 1
#include <grub/err.h>
#include <grub/symbol.h>
#include <grub/types.h>
#include <grub/menu.h>
#include <grub/term.h>
struct grub_menu_viewer
{
struct grub_menu_viewer *next;
void *data;
void (*set_chosen_entry) (int entry, void *data);
void (*scroll_chosen_entry) (void *data, int diren);
void (*print_timeout) (int timeout, void *data);
void (*clear_timeout) (void *data);
void (*fini) (void *fini);
};
void grub_menu_register_viewer (struct grub_menu_viewer *viewer);
grub_err_t
grub_menu_try_text (struct grub_term_output *term,
int entry, grub_menu_t menu, int nested);
extern grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
int nested);
#endif /* GRUB_MENU_VIEWER_HEADER */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment