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