muiltistring changed to multiline
(now we have multiline)
-- 
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
diff -Naur grub-2.00/grub-core/gfxmenu/gui_label.c grub-new/grub-core/gfxmenu/gui_label.c
--- grub-2.00/grub-core/gfxmenu/gui_label.c	2012-03-03 16:00:50.000000000 +0400
+++ grub-new/grub-core/gfxmenu/gui_label.c	2013-03-22 19:33:24.187744391 +0400
@@ -21,6 +21,7 @@
 #include <grub/misc.h>
 #include <grub/gui.h>
 #include <grub/font.h>
+#include <grub/charset.h>
 #include <grub/gui_string_util.h>
 #include <grub/i18n.h>
 
@@ -51,11 +52,22 @@
   grub_font_t font;
   grub_video_rgba_color_t color;
   int value;
+  int multiline;
   enum align_mode align;
 };
 
 typedef struct grub_gui_label *grub_gui_label_t;
 
+static int
+is_whitespace (char c)
+{
+  return (c == ' '
+          || c == '\t'
+          || c == '\r'
+          || c == '\n'
+          || c == '\f');
+}
+
 static void
 label_destroy (void *vself)
 {
@@ -79,17 +91,81 @@
   return grub_strcmp (type, "component") == 0;
 }
 
-static void
-label_paint (void *vself, const grub_video_rect_t *region)
+static int
+label_end_of_word (char *buf, int len, int pos)
 {
-  grub_gui_label_t self = vself;
+  while ((pos < len) && (!is_whitespace (buf[pos])))
+    {
+      pos++;
+    }
+  return pos;
+}
 
-  if (! self->visible)
-    return;
+static int
+label_string_width (char *buf, grub_font_t font, int beg, int end)
+{
+  char *tmpstr = grub_new_substring (buf, beg, end);
+  int result = grub_font_get_string_width (font, tmpstr);
+  grub_free (tmpstr);
+  return result;
+}
 
-  if (!grub_video_have_common_points (region, &self->bounds))
-    return;
+static int
+label_get_max_symbols(char *buf, grub_font_t font, int max_width,
+                      int start, int end, int *result_width, int isvertical)
+{
+  grub_uint32_t *ptr;
+  grub_ssize_t logical_len;
+  grub_uint32_t *logical;
+  struct grub_unicode_glyph glyph;
+
+  char *tmpstr = grub_new_substring (buf, start, end);
+  logical_len = grub_utf8_to_ucs4_alloc (tmpstr, &logical, 0);
+  grub_free (tmpstr);
+  if (logical_len < 0)
+    return end;
+  ptr = logical;
+
+  if (isvertical)
+    {
+      ptr += grub_unicode_aglomerate_comb (ptr,
+					   logical_len - (ptr - logical),
+					   &glyph);
+      *result_width += grub_font_get_constructed_device_width (font, &glyph);
+      grub_free (glyph.combining);
+
+      int result = start + grub_get_num_of_utf8_bytes (logical, 1);
+      grub_free (logical);
+      return result;
+    }
+
+  int cnt = 0;
+  int last_width;
+  int str_width = *result_width;
+  while ((str_width <= max_width) && (ptr < logical + logical_len))
+    {
+      cnt ++;
+      ptr += grub_unicode_aglomerate_comb (ptr,
+					   logical_len - (ptr - logical),
+					   &glyph);
+      last_width = str_width;
+      str_width += grub_font_get_constructed_device_width (font, &glyph);
+      grub_free (glyph.combining);
+    }
+  if (str_width > max_width)
+    {
+      cnt --;
+      str_width = last_width;
+    }
+  int result = start + grub_get_num_of_utf8_bytes (logical, cnt);
+  grub_free (logical);
+  *result_width = str_width;
+  return result;
+}
 
+static void
+label_paint (grub_gui_label_t self)
+{
   /* Calculate the starting x coordinate.  */
   int left_x;
   if (self->align == align_left)
@@ -100,19 +176,115 @@
   else if (self->align == align_right)
     left_x = (self->bounds.width
               - grub_font_get_string_width (self->font, self->text));
-  else
-    return;   /* Invalid alignment.  */
 
   if (left_x < 0 || left_x > (int) self->bounds.width)
     left_x = 0;
 
-  grub_video_rect_t vpsave;
-  grub_gui_set_viewport (&self->bounds, &vpsave);
   grub_font_draw_string (self->text,
                          self->font,
                          grub_video_map_rgba_color (self->color),
                          left_x,
                          grub_font_get_ascent (self->font));
+}
+
+static void
+label_paint_multiline (grub_gui_label_t self)
+{
+  int baseline = grub_font_get_ascent (self->font);
+  int text_height = grub_font_get_max_char_height (self->font);
+  int left_x = 0;
+  int l_width = self->bounds.width;
+  int l_lastend;
+  char *l_tmpstr;
+
+  char *buf = self->text;
+  int pos = 0;
+  int end = 0;
+  int len = grub_strlen(buf);
+  grub_font_t font = self->font;
+  int str_width = 0;
+  int word_width = 0;
+
+  int isvertical = (l_width == grub_font_get_max_char_width (self->font));
+
+  while (pos < len)
+  {
+    l_lastend = end;
+    if (is_whitespace (buf[end]))
+      {
+        end ++;
+      } else {
+        end = label_end_of_word (buf, len, end); // non-empty string
+        if (!isvertical && is_whitespace (buf[pos]))
+          {
+            pos = l_lastend; // remove whitespaces from the start of a string
+            str_width = 0;
+          }
+      }
+    word_width = label_string_width (buf, font, l_lastend, end);
+    if (isvertical || (str_width + word_width > l_width)) // can't add new word
+      {
+        if (isvertical || (word_width > l_width)) // word is too big
+          { // print as many symbols
+            end = label_get_max_symbols (buf, font, l_width, l_lastend, end,
+                                         &str_width, isvertical);
+          } else { // newline
+            end = l_lastend;
+          }
+      } else { // new word can be printed in the same line
+        str_width += word_width;
+        if (end < len) // if there are any other word
+          continue;
+      }
+    /* Remove whitespaces from the end of a string */
+    l_lastend = end;
+    if (!isvertical)
+      {
+        while ((end - pos > 1) && is_whitespace (buf[end - 1]))
+          end --;
+        str_width -= label_string_width(buf, font, end, l_lastend);
+      }
+    /* Calculate the starting x coordinate.  */
+    if (self->align == align_center)
+      left_x = (l_width - str_width) / 2;
+    else if (self->align == align_right)
+      left_x = (l_width - str_width);
+    l_tmpstr = grub_new_substring (buf, pos, end);
+    grub_font_draw_string (l_tmpstr,
+                           font,
+                           grub_video_map_rgba_color (self->color),
+                           left_x,
+                           baseline);
+    grub_free (l_tmpstr);
+    baseline += text_height;
+    str_width = 0;
+    /* Return saved state of "end" */
+    end = l_lastend;
+    pos = l_lastend;
+  }
+}
+
+static void
+label_paint_dispatcher (void *vself, const grub_video_rect_t *region)
+{
+  grub_gui_label_t self = vself;
+  if (! self->visible)
+    return;
+
+  if (!grub_video_have_common_points (region, &self->bounds))
+    return;
+
+  if ((!self->align == align_left) &&
+      (!self->align == align_center) &&
+      (!self->align == align_right))
+    return;    /* Invalid alignment */
+
+  grub_video_rect_t vpsave;
+  grub_gui_set_viewport (&self->bounds, &vpsave);
+  if (self->multiline)
+    label_paint_multiline(self);
+  else
+    label_paint(self);
   grub_gui_restore_viewport (&vpsave);
 }
 
@@ -148,9 +320,15 @@
 label_get_minimal_size (void *vself, unsigned *width, unsigned *height)
 {
   grub_gui_label_t self = vself;
-  *width = grub_font_get_string_width (self->font, self->text);
-  *height = (grub_font_get_ascent (self->font)
-             + grub_font_get_descent (self->font));
+  if (self->multiline)
+    {
+      *width = grub_font_get_max_char_width (self->font);
+      *height = grub_font_get_max_char_height (self->font);
+    } else {
+      *width = grub_font_get_string_width (self->font, self->text);
+      *height = (grub_font_get_ascent (self->font)
+                 + grub_font_get_descent (self->font));
+    }
 }
 
 static void
@@ -231,6 +409,10 @@
 	grub_gfxmenu_timeout_register ((grub_gui_component_t) self,
 				       label_set_state);
     }
+  else if (grub_strcmp (name, "multiline") == 0)
+    {
+      self->multiline = grub_strcmp (value, "false") != 0;
+    }
   return GRUB_ERR_NONE;
 }
 
@@ -239,7 +421,7 @@
   .destroy = label_destroy,
   .get_id = label_get_id,
   .is_instance = label_is_instance,
-  .paint = label_paint,
+  .paint = label_paint_dispatcher,
   .set_parent = label_set_parent,
   .get_parent = label_get_parent,
   .set_bounds = label_set_bounds,
@@ -264,5 +446,6 @@
   label->color.blue = 0;
   label->color.alpha = 255;
   label->align = align_left;
+  label->multiline = 0;
   return (grub_gui_component_t) label;
 }
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to