Hi, grub-developers,
I implemented a complete horizontal extension to the boot menu and some
other little features and fixes for extending the gfxmenu boot menu.
I would just describe my added theme parameters for the boot_menu control:
- item_width: Optionally specifying a width for each item in
horizontal lists, but could also be implemented to work with vertical lists.
- item_icon_padding: Padding between icon and box or between icon and
other item if there is no item_box.
- horizontal: boolean, defining this boot_list as horizontal.
- item_pixmap_style: like selected_item_pixmap_style but for non
selected entries.
- item_pixmap_icon_only: boolean, selected and unselected pixmaps are
only shown around the icons and not around the whole item.
The scrollbars must be manually turned around to be in horizontal mode,
I have uploaded a demo theme as an example:
http://data.e7p.de/grub-horizontal-theme.png
http://data.e7p.de/grub-horizontal-theme.zip
I fixed a bug in the icon-section. The first group in any menuentry was
skipped while looking for icons before, so only icons for the second
class would be searched.
The normal menu is also modified as I wanted to allow to use right/left
keys while navigating through the menu while it is horizontal. At
menu_init, a new environment variable (orientation) can be set by the
used menu module to horizontal for obvious reasons.
Best regards,
Endres
=== modified file 'grub-core/gfxmenu/gui_list.c'
--- grub-core/gfxmenu/gui_list.c 2010-10-16 20:16:52 +0000
+++ grub-core/gfxmenu/gui_list.c 2011-04-10 18:20:42 +0000
@@ -23,6 +23,7 @@
#include <grub/gui_string_util.h>
#include <grub/gfxmenu_view.h>
#include <grub/gfxwidgets.h>
+#include <grub/env.h>
struct grub_gui_list_impl
{
@@ -35,9 +36,11 @@
int icon_width;
int icon_height;
+ int item_width;
int item_height;
int item_padding;
int item_icon_space;
+ int item_icon_padding;
int item_spacing;
grub_font_t item_font;
grub_font_t selected_item_font;
@@ -53,14 +56,19 @@
grub_gfxmenu_box_t scrollbar_thumb;
int scrollbar_width;
+ int horizontal;
+
int first_shown_index;
int need_to_recreate_boxes;
char *theme_dir;
char *menu_box_pattern;
char *selected_item_box_pattern;
+ char *item_box_pattern;
grub_gfxmenu_box_t menu_box;
grub_gfxmenu_box_t selected_item_box;
+ grub_gfxmenu_box_t item_box;
+ int box_icon_only;
grub_gfxmenu_icon_manager_t icon_manager;
@@ -91,15 +99,27 @@
get_num_shown_items (list_impl_t self)
{
int boxpad = self->item_padding;
- int item_vspace = self->item_spacing;
+ int item_space = self->item_spacing;
int item_height = self->item_height;
+ int item_width = self->item_width;
grub_gfxmenu_box_t box = self->menu_box;
int box_top_pad = box->get_top_pad (box);
int box_bottom_pad = box->get_bottom_pad (box);
-
- return (self->bounds.height + item_vspace - 2 * boxpad
- - box_top_pad - box_bottom_pad) / (item_height + item_vspace);
+ int box_left_pad = box->get_left_pad (box);
+ int box_right_pad = box->get_right_pad (box);
+
+ grub_gfxmenu_box_t itembox = self->item_box;
+
+ if(self->horizontal)
+ return (self->bounds.width + item_space - 2 * boxpad
+ - box_left_pad - box_right_pad) / (grub_max(item_width,
+ self->icon_width + 2 * self->item_icon_padding) + item_space
+ + itembox->get_left_pad(itembox) + itembox->get_right_pad(itembox));
+ else
+ return (self->bounds.height + item_space - 2 * boxpad
+ - box_top_pad - box_bottom_pad) / (item_height + item_space
+ + itembox->get_top_pad(itembox) + itembox->get_bottom_pad(itembox));
}
static int
@@ -115,6 +135,10 @@
self->selected_item_box_pattern,
self->theme_dir);
+ grub_gui_recreate_box (&self->item_box,
+ self->item_box_pattern,
+ self->theme_dir);
+
self->need_to_recreate_boxes = 0;
}
@@ -183,29 +207,48 @@
static void
draw_scrollbar (list_impl_t self,
int value, int extent, int min, int max,
- int rightx, int topy, int height)
+ int x1, int y1, int length)
{
+ /* x1 and y1 have now their special meanings:
+ * if vertical: x1 = right, y1 = top
+ * if horizontal: x1 = left, y1 = bottom */
grub_gfxmenu_box_t frame = self->scrollbar_frame;
grub_gfxmenu_box_t thumb = self->scrollbar_thumb;
int frame_vertical_pad = (frame->get_top_pad (frame)
+ frame->get_bottom_pad (frame));
int frame_horizontal_pad = (frame->get_left_pad (frame)
+ frame->get_right_pad (frame));
- int tracktop = topy + frame->get_top_pad (frame);
- int tracklen = height - frame_vertical_pad;
- frame->set_content_size (frame, self->scrollbar_width, tracklen);
- int thumby = tracktop + tracklen * (value - min) / (max - min);
- int thumbheight = tracklen * extent / (max - min) + 1;
- thumb->set_content_size (thumb,
- self->scrollbar_width - frame_horizontal_pad,
- thumbheight - (thumb->get_top_pad (thumb)
- + thumb->get_bottom_pad (thumb)));
- frame->draw (frame,
- rightx - (self->scrollbar_width + frame_horizontal_pad),
- topy);
- thumb->draw (thumb,
- rightx - (self->scrollbar_width - frame->get_right_pad (frame)),
- thumby);
+ if(self->horizontal == 0) {
+ int tracktop = y1 + frame->get_top_pad (frame);
+ int tracklen = length - frame_vertical_pad;
+ frame->set_content_size (frame, self->scrollbar_width, tracklen);
+ int thumby = tracktop + tracklen * (value - min) / (max - min);
+ int thumbheight = tracklen * extent / (max - min) + 1;
+ thumb->set_content_size (thumb,
+ self->scrollbar_width - frame_horizontal_pad,
+ thumbheight - (thumb->get_top_pad (thumb)
+ + thumb->get_bottom_pad (thumb)));
+ frame->draw (frame,
+ x1 - (self->scrollbar_width + frame_horizontal_pad),
+ y1);
+ thumb->draw (thumb,
+ x1 - (self->scrollbar_width - frame->get_right_pad (frame)),
+ thumby);
+ } else {
+ int trackleft = x1 + frame->get_left_pad (frame);
+ int tracklen = length - frame_horizontal_pad;
+ frame->set_content_size (frame, tracklen, self->scrollbar_width);
+ int thumbx = trackleft + tracklen * (value - min) / (max - min);
+ int thumbwidth = tracklen * extent / (max - min) + 1;
+ thumb->set_content_size (thumb,
+ thumbwidth - (thumb->get_left_pad (thumb)
+ + thumb->get_right_pad (thumb)),
+ self->scrollbar_width - frame_vertical_pad);
+ frame->draw (frame, x1,
+ y1 - (self->scrollbar_width + frame_vertical_pad));
+ thumb->draw (thumb, thumbx,
+ y1 - (self->scrollbar_width - frame->get_bottom_pad (frame)));
+ }
}
/* Draw the list of items. */
@@ -217,24 +260,44 @@
int boxpad = self->item_padding;
int icon_text_space = self->item_icon_space;
- int item_vspace = self->item_spacing;
+ int item_space = self->item_spacing;
+
+ int horizontal = self->horizontal;
int ascent = grub_font_get_ascent (self->item_font);
int descent = grub_font_get_descent (self->item_font);
+ int icon_width = self->icon_width + 2 * self->item_icon_padding;
+ int icon_height = self->icon_height + 2 * self->item_icon_padding;
+ int item_width = icon_width; // TODO: for both horizontal and vertical
int item_height = self->item_height;
-
+
make_selected_item_visible (self);
grub_gfxmenu_box_t selbox = self->selected_item_box;
+ grub_gfxmenu_box_t itembox = self->item_box;
int sel_leftpad = selbox->get_left_pad (selbox);
int sel_toppad = selbox->get_top_pad (selbox);
- int item_top = sel_toppad;
+ int item_leftpad = selbox->get_left_pad (itembox);
+ int item_toppad = selbox->get_top_pad (itembox);
+ int max_leftpad = grub_max(sel_leftpad, item_leftpad);
+ int max_toppad = grub_max(sel_toppad, item_toppad);
+
+ int item_left = max_leftpad;
+ int item_top = max_toppad;
+
int menu_index;
int visible_index;
struct grub_video_rect oviewport;
grub_video_get_viewport (&oviewport.x, &oviewport.y,
&oviewport.width, &oviewport.height);
+ if (horizontal) {
+ int new_width = grub_min(num_shown_items, self->view->menu->size)
+ * (grub_max(icon_width,item_width) + 2 * item_leftpad + item_space)
+ - item_space - 1 + 2 * grub_abs(sel_leftpad-item_leftpad) + 2 * boxpad;
+ oviewport.x += grub_max(0, self->bounds.width - new_width) / 2 - grub_abs(sel_leftpad-item_leftpad) / 2;
+ oviewport.width = new_width;
+ }
grub_video_set_viewport (oviewport.x + boxpad,
oviewport.y + boxpad,
oviewport.width - 2 * boxpad,
@@ -246,20 +309,45 @@
{
int is_selected = (menu_index == self->view->selected);
- if (is_selected)
- {
- selbox->set_content_size (selbox, oviewport.width - 2 * boxpad - 2,
- item_height - 1);
- selbox->draw (selbox, 0,
- item_top - sel_toppad);
- }
+ if (is_selected) {
+ if (horizontal == 0)
+ selbox->set_content_size (selbox,
+ (self->box_icon_only?icon_width:
+ (int)(oviewport.width - 2 * boxpad - 2)),
+ item_height - 1);
+ else
+ selbox->set_content_size (selbox, item_width - 1,
+ (self->box_icon_only?icon_height:
+ (int)(oviewport.height - 2 * boxpad - 2)));
+ selbox->draw (selbox, item_left - sel_leftpad, item_top - sel_toppad);
+ } else if (itembox) {
+ if (horizontal == 0)
+ itembox->set_content_size (itembox,
+ (self->box_icon_only?icon_width:
+ (int)(oviewport.width - 2 * boxpad - 2)),
+ item_height - 1);
+ else
+ itembox->set_content_size (itembox, item_width - 1,
+ (self->box_icon_only?icon_height:
+ (int)(oviewport.height - 2 * boxpad - 2)));
+ itembox->draw (itembox, item_left - item_leftpad, item_top - item_toppad);
+ }
struct grub_video_bitmap *icon;
- if ((icon = get_item_icon (self, menu_index)) != 0)
- grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND,
- sel_leftpad,
- item_top + (item_height - self->icon_height) / 2,
- 0, 0, self->icon_width, self->icon_height);
+ if ((icon = get_item_icon (self, menu_index)) != 0) {
+ if (horizontal == 0)
+ grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND,
+ item_left + self->item_icon_padding,
+ item_top + self->item_icon_padding +
+ (item_height - self->icon_height) / 2,
+ 0, 0, self->icon_width, self->icon_height);
+ else
+ grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND,
+ item_left + self->item_icon_padding +
+ (item_width - icon_width) / 2,
+ item_top + self->item_icon_padding,
+ 0, 0, self->icon_width, self->icon_height);
+ }
const char *item_title =
grub_menu_get_entry (self->view->menu, menu_index)->title;
@@ -271,15 +359,24 @@
((is_selected && self->selected_item_color_set)
? self->selected_item_color
: self->item_color);
- grub_font_draw_string (item_title,
- font,
- grub_gui_map_color (text_color),
- sel_leftpad + self->icon_width + icon_text_space,
- (item_top + (item_height - (ascent + descent))
- / 2 + ascent));
-
- item_top += item_height + item_vspace;
+ if (horizontal == 0) {
+ grub_font_draw_string (item_title, font,
+ grub_gui_map_color (text_color),
+ icon_width + icon_text_space,
+ item_top + (item_height - (ascent + descent)) / 2 + ascent);
+
+ item_top += item_height + item_space;
+ } else {
+ grub_font_draw_string (item_title, font,
+ grub_gui_map_color (text_color),
+ (item_left + (item_width -
+ grub_font_get_string_width(font, item_title)) / 2),
+ item_top + item_toppad + icon_height + icon_text_space + ascent);
+
+ item_left += item_width + item_space + 2 * item_leftpad;
+ }
}
+
grub_video_set_viewport (oviewport.x,
oviewport.y,
oviewport.width,
@@ -332,10 +429,13 @@
draw_scrollbar (self,
self->first_shown_index, num_shown_items,
0, self->view->menu->size,
- self->bounds.width - box_right_pad
- + self->scrollbar_width,
- box_top_pad,
- self->bounds.height - box_top_pad - box_bottom_pad);
+ (self->horizontal?box_left_pad:
+ (int)(self->bounds.width - box_right_pad + self->scrollbar_width)),
+ (!self->horizontal?box_top_pad:
+ (int)(self->bounds.height - box_bottom_pad - self->scrollbar_width)),
+ (self->horizontal?
+ (self->bounds.width - box_left_pad - box_right_pad):
+ (self->bounds.height - box_top_pad - box_bottom_pad)));
}
grub_gui_restore_viewport (&vpsave);
@@ -377,7 +477,7 @@
if (check_boxes (self))
{
int boxpad = self->item_padding;
- int item_vspace = self->item_spacing;
+ int item_space = self->item_spacing;
int item_height = self->item_height;
int num_items = 3;
@@ -386,24 +486,48 @@
int box_top_pad = box->get_top_pad (box);
int box_right_pad = box->get_right_pad (box);
int box_bottom_pad = box->get_bottom_pad (box);
- unsigned width_s;
+
+ unsigned sel_size;
grub_gfxmenu_box_t selbox = self->selected_item_box;
int sel_toppad = selbox->get_top_pad (selbox);
-
- *width = grub_font_get_string_width (self->item_font, "Typical OS");
- width_s = grub_font_get_string_width (self->selected_item_font,
- "Typical OS");
- if (*width < width_s)
- *width = width_s;
-
- *width += 2 * boxpad + box_left_pad + box_right_pad;
-
- /* Set the menu box height to fit the items. */
- *height = (item_height * num_items
- + item_vspace * (num_items - 1)
- + 2 * boxpad
- + box_top_pad + box_bottom_pad + sel_toppad);
+ int sel_bottompad = selbox->get_bottom_pad (selbox);
+
+ grub_gfxmenu_box_t itembox = self->item_box;
+ int item_toppad = itembox->get_top_pad (itembox);
+ int item_bottompad = itembox->get_bottom_pad (itembox);
+
+ unsigned max_toppad = grub_max(sel_toppad, item_toppad);
+ unsigned max_bottompad = grub_max(sel_bottompad, item_bottompad);
+
+ if (self->horizontal == 0) {
+ *width = grub_font_get_string_width (self->item_font, "Typical OS");
+ sel_size = grub_font_get_string_width (self->selected_item_font,
+ "Typical OS");
+ if (*width < sel_size) *width = sel_size;
+
+ *width += 2 * boxpad + box_left_pad + box_right_pad;
+
+ /* Set the menu box height to fit the items. */
+ *height = (item_height * num_items
+ + item_space * (num_items - 1)
+ + 2 * boxpad
+ + box_top_pad + box_bottom_pad + sel_toppad);
+ } else {
+ *height = grub_font_get_ascent (self->item_font)
+ - grub_font_get_descent (self->item_font);
+ sel_size = grub_font_get_ascent (self->selected_item_font)
+ - grub_font_get_descent (self->selected_item_font);
+ if (*height < sel_size && self->selected_item_font) *height = sel_size;
+ if (*height + self->item_icon_space < max_bottompad) *height = max_bottompad;
+ else *height += max_bottompad;
+
+ *height += self->icon_height + box_top_pad + box_bottom_pad
+ + (2 * (boxpad + self->item_icon_padding))
+ + max_toppad + self->item_icon_space;
+ /* Set the menu box width to fit the items. ie: set to full width */
+ *width = self->bounds.width;
+ }
}
else
{
@@ -458,6 +582,10 @@
self->icon_width,
self->icon_height);
}
+ else if (grub_strcmp (name, "item_width") == 0)
+ {
+ self->item_width = grub_strtol (value, 0, 10);
+ }
else if (grub_strcmp (name, "item_height") == 0)
{
self->item_height = grub_strtol (value, 0, 10);
@@ -470,6 +598,10 @@
{
self->item_icon_space = grub_strtol (value, 0, 10);
}
+ else if (grub_strcmp (name, "item_icon_padding") == 0)
+ {
+ self->item_icon_padding = grub_strtol (value, 0, 10);
+ }
else if (grub_strcmp (name, "item_spacing") == 0)
{
self->item_spacing = grub_strtol (value, 0, 10);
@@ -490,6 +622,16 @@
grub_free (self->selected_item_box_pattern);
self->selected_item_box_pattern = value ? grub_strdup (value) : 0;
}
+ else if (grub_strcmp (name, "item_pixmap_style") == 0)
+ {
+ self->need_to_recreate_boxes = 1;
+ grub_free (self->item_box_pattern);
+ self->item_box_pattern = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "item_pixmap_icon_only") == 0)
+ {
+ self->box_icon_only = grub_strcmp (value, "false") != 0;
+ }
else if (grub_strcmp (name, "scrollbar_frame") == 0)
{
self->need_to_recreate_scrollbar = 1;
@@ -524,6 +666,11 @@
else
self->id = 0;
}
+ else if (grub_strcmp (name, "horizontal") == 0)
+ {
+ self->horizontal = grub_strcmp (value, "false") != 0;
+ if(self->horizontal) grub_env_set("orientation", "horizontal");
+ }
return grub_errno;
}
@@ -578,9 +725,11 @@
self->icon_width = 32;
self->icon_height = 32;
+ self->item_width = 42; // Only applies to horizontal lists TODO: do for both and appropriate default value
self->item_height = 42;
self->item_padding = 14;
self->item_icon_space = 4;
+ self->item_icon_padding = 0;
self->item_spacing = 16;
self->item_font = default_font;
self->selected_item_font = 0; /* Default to using the item_font. */
@@ -604,6 +753,10 @@
self->selected_item_box_pattern = 0;
self->menu_box = grub_gfxmenu_create_box (0, 0);
self->selected_item_box = grub_gfxmenu_create_box (0, 0);
+ self->item_box = grub_gfxmenu_create_box (0, 0);
+ self->box_icon_only = 0;
+
+ self->horizontal = 0;
self->icon_manager = grub_gfxmenu_icon_manager_new ();
if (! self->icon_manager)
=== modified file 'grub-core/gfxmenu/icon_manager.c'
--- grub-core/gfxmenu/icon_manager.c 2009-11-21 16:48:05 +0000
+++ grub-core/gfxmenu/icon_manager.c 2011-04-09 13:10:49 +0000
@@ -257,7 +257,7 @@
/* Try each class in succession. */
icon = 0;
- for (c = entry->classes->next; c && ! icon; c = c->next)
+ for (c = entry->classes; c && ! icon; c = c->next)
icon = get_icon_by_class (mgr, c->name);
return icon;
}
=== modified file 'grub-core/normal/menu.c'
--- grub-core/normal/menu.c 2011-04-08 10:12:02 +0000
+++ grub-core/normal/menu.c 2011-04-10 18:13:14 +0000
@@ -349,6 +349,8 @@
struct grub_term_output *term;
int gfxmenu = 0;
+ grub_env_set("orientation", "vertical");
+
FOR_ACTIVE_TERM_OUTPUTS(term)
if (grub_strcmp (term->name, "gfxterm") == 0)
{
@@ -580,22 +582,6 @@
menu_set_chosen_entry (current_entry);
break;
- case GRUB_TERM_KEY_UP:
- case GRUB_TERM_CTRL | 'p':
- case '^':
- if (current_entry > 0)
- current_entry--;
- menu_set_chosen_entry (current_entry);
- break;
-
- case GRUB_TERM_CTRL | 'n':
- case GRUB_TERM_KEY_DOWN:
- case 'v':
- if (current_entry < menu->size - 1)
- current_entry++;
- menu_set_chosen_entry (current_entry);
- break;
-
case GRUB_TERM_CTRL | 'g':
case GRUB_TERM_KEY_PPAGE:
if (current_entry < GRUB_MENU_PAGE_SIZE)
@@ -614,14 +600,6 @@
menu_set_chosen_entry (current_entry);
break;
- case '\n':
- case '\r':
- case GRUB_TERM_KEY_RIGHT:
- case GRUB_TERM_CTRL | 'f':
- menu_fini ();
- *auto_boot = 0;
- return current_entry;
-
case '\e':
if (nested)
{
@@ -656,6 +634,62 @@
*auto_boot = 0;
return i;
}
+
+ if (grub_strcmp(grub_env_get("orientation"), "horizontal") == 0) {
+ switch(c) {
+ case GRUB_TERM_KEY_LEFT:
+ case GRUB_TERM_CTRL | 'p':
+ case '<':
+ if (current_entry > 0)
+ current_entry--;
+ menu_set_chosen_entry (current_entry);
+ break;
+
+ case GRUB_TERM_CTRL | 'n':
+ case GRUB_TERM_KEY_RIGHT:
+ case '>':
+ if (current_entry < menu->size - 1)
+ current_entry++;
+ menu_set_chosen_entry (current_entry);
+ break;
+
+ case '\n':
+ case '\r':
+ case GRUB_TERM_CTRL | 'f':
+ menu_fini ();
+ *auto_boot = 0;
+ return current_entry;
+
+ }
+ } else {
+ switch(c) {
+ case GRUB_TERM_KEY_UP:
+ case GRUB_TERM_CTRL | 'p':
+ case '^':
+ if (current_entry > 0)
+ current_entry--;
+ menu_set_chosen_entry (current_entry);
+ break;
+
+ case GRUB_TERM_CTRL | 'n':
+ case GRUB_TERM_KEY_DOWN:
+ case 'v':
+ if (current_entry < menu->size - 1)
+ current_entry++;
+ menu_set_chosen_entry (current_entry);
+ break;
+
+ case '\n':
+ case '\r':
+ case GRUB_TERM_KEY_RIGHT:
+ case GRUB_TERM_CTRL | 'f':
+ menu_fini ();
+ *auto_boot = 0;
+ return current_entry;
+
+ }
+ }
+
}
break;
}
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel