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

Reply via email to