* Re: [PATCH] multistring support in gui_label
@ 2013-04-16 9:04 Vladimir Testov
2013-04-16 17:10 ` Andrey Borzenkov
2013-04-17 7:01 ` Vladimir 'φ-coder/phcoder' Serbinenko
0 siblings, 2 replies; 14+ messages in thread
From: Vladimir Testov @ 2013-04-16 9:04 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 2157 bytes --]
>Please don't use // comments.
O.k. I won't.
>This code completely forgets the cases
>when even the first word doesn't fit in the available space.
Mmm. It can handle this case actually.
>The code as whole breaks some unicode concepts like e.g. bidi stack.
Didn't get what you mean.
>Could you reuse the already available line-vreaking algorithm in
>normal/term.c and normal/charset.c ? Since the line-breaking is
>artificially disabled for labels it should require only minor
>adjustments to be reenabled.
Yep! Here it is (patch included)!
Nevertheless, two problems appeared and I don't sure how exactly should I fix
them.
1) Handling of some long word. If this word is not first in line and it's
length is more than label's width
then the length of the first fragment of the word will be counted as if it will
be drawn on the same line,
but actually it will be printed on the next line.
2) There is funny handling of UTF-8 symbols. Each symbol have "device_width"
parameter,
which is used in calculation of string's length. But, when we are going to
actually print a symbol,
it's length (with spaces) is calculated in other way. First, all symbols that
have special connection with
current symbol are looked through. Then device_width is replaced with maximum
of printed lengths in all cases.
So, for some special symbols (eg "`", used in @KEYMAP_LONG@) actual length
will be more than pre-counted.
How should I fix these problems?
1st one - for example, I can slightly update line-breaking mechanism.
2nd one - more interesting, harder. I suggest utf-8 printing mechanism
(charset.c unicode.c etc) should be remade. So symbol connections will be
counted in more intelligent way (e.g. while counting spaces - take into
consideration nearby symbols). It is interesting. :) I can do it. Would be
happy, if someone could give me some advices.
Problem2.png
text = "@KEYMAP_LONG@"
t is misprinted
Problem1.png
text = "short short short
HereWeHaveSomeVeryLongWordSoItCannotBePrintedEntirelyOnOneLine"
See how the line-breaking works.
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
[-- Attachment #2: Problem1.png --]
[-- Type: image/png, Size: 2141 bytes --]
[-- Attachment #3: problem2.png --]
[-- Type: image/png, Size: 2954 bytes --]
[-- Attachment #4: grub-2.00-label-multistring.patch --]
[-- Type: text/x-patch, Size: 7526 bytes --]
diff -Naur grub-2.00/grub-core/gfxmenu/font.c grub-new/grub-core/gfxmenu/font.c
--- grub-2.00/grub-core/gfxmenu/font.c 2012-03-27 18:29:43.000000000 +0400
+++ grub-new/grub-core/gfxmenu/font.c 2013-04-15 09:55:26.978883414 +0400
@@ -75,6 +75,94 @@
return GRUB_ERR_NONE;
}
+/* Differs from grub_font_draw_line only in multiline output */
+grub_err_t
+grub_font_draw_multiline (const char *str, grub_font_t font,
+ grub_video_color_t color,
+ int baseline_y, int font_height,
+ int max_width, int max_height,
+ int align)
+{
+ int x;
+ struct grub_font_glyph *glyph;
+ grub_uint32_t *logical;
+ grub_ssize_t logical_len, visual_len;
+ struct grub_unicode_glyph *visual, *ptr, *pos;
+
+ grub_err_t print_line ()
+ {
+ while (pos != ptr)
+ {
+ grub_err_t err;
+ glyph = grub_font_construct_glyph (font, pos);
+ if (!glyph)
+ return grub_errno;
+ err = grub_font_draw_glyph (glyph, color, x, baseline_y);
+ x += glyph->device_width;
+ grub_free (glyph);
+ if (err)
+ return err;
+ pos ++;
+ }
+
+ return GRUB_ERR_NONE;
+ }
+
+ logical_len = grub_utf8_to_ucs4_alloc (str, &logical, 0);
+ if (logical_len < 0)
+ return grub_errno;
+
+ auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c);
+ grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c)
+ {
+ return grub_font_get_constructed_device_width (font, c);
+ }
+
+ visual_len = grub_bidi_logical_to_visual (logical, logical_len, &visual,
+ getcharwidth, max_width, 0);
+ grub_free (logical);
+ if (visual_len < 0)
+ return grub_errno;
+
+ pos = visual;
+ for (ptr = visual, x = 0; ptr <= visual + visual_len; ptr++)
+ {
+ if (baseline_y > max_height)
+ break;
+ if (ptr->base == '\n' || ptr == visual + visual_len)
+ {
+ int left_x;
+ if (align == 1)
+ left_x = (max_width - x) / 2;
+ else if (align == 2)
+ left_x = max_width - x;
+ else
+ left_x = 0;
+
+ x = left_x;
+
+ grub_err_t err;
+ err = print_line();
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ baseline_y += font_height;
+ x = 0;
+ while ((ptr + 1 < visual + visual_len)
+ && ((ptr + 1)->base == ' '
+ || (ptr + 1)->base == '\t'))
+ ptr ++;
+ pos = ptr + 1;
+ }
+ else
+ x += grub_font_get_constructed_device_width (font, ptr);
+ }
+
+ grub_free (visual);
+
+ return GRUB_ERR_NONE;
+}
+
/* Get the width in pixels of the specified UTF-8 string, when rendered in
in the specified font (but falling back on other fonts for glyphs that
are missing). */
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-04-12 16:40:50.151859580 +0400
@@ -46,6 +46,7 @@
grub_video_rect_t bounds;
char *id;
int visible;
+ int multiline;
char *text;
char *template;
grub_font_t font;
@@ -91,28 +92,46 @@
return;
/* Calculate the starting x coordinate. */
- int left_x;
- if (self->align == align_left)
- left_x = 0;
- else if (self->align == align_center)
- left_x = (self->bounds.width
- - grub_font_get_string_width (self->font, self->text)) / 2;
- else if (self->align == align_right)
- left_x = (self->bounds.width
- - grub_font_get_string_width (self->font, self->text));
- else
- return; /* Invalid alignment. */
+ int left_x = 0;
+ if (!self->multiline)
+ {
+ if (self->align == align_left)
+ left_x = 0;
+ else if (self->align == align_center)
+ left_x = (self->bounds.width
+ - grub_font_get_string_width (self->font, self->text)) / 2;
+ 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;
+ 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));
+ if (!self->multiline)
+ grub_font_draw_string (self->text,
+ self->font,
+ grub_video_map_rgba_color (self->color),
+ left_x,
+ grub_font_get_ascent (self->font));
+ else
+ {
+ int font_height = grub_font_get_max_char_height (self->font);
+ int max_width = self->bounds.width;
+ int max_height = self->bounds.height;
+ grub_font_draw_multiline (self->text,
+ self->font,
+ grub_video_map_rgba_color (self->color),
+ grub_font_get_ascent (self->font),
+ font_height,
+ max_width,
+ max_height,
+ self->align);
+ }
grub_gui_restore_viewport (&vpsave);
}
@@ -148,9 +167,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
@@ -218,6 +243,10 @@
{
self->visible = grub_strcmp (value, "false") != 0;
}
+ else if (grub_strcmp (name, "multiline") == 0)
+ {
+ self->multiline = grub_strcmp (value, "false") != 0;
+ }
else if (grub_strcmp (name, "id") == 0)
{
grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
@@ -257,6 +286,7 @@
return 0;
label->comp.ops = &label_ops;
label->visible = 1;
+ label->multiline = 0;
label->text = grub_strdup ("");
label->font = grub_font_get ("Unknown Regular 16");
label->color.red = 0;
diff -Naur grub-2.00/include/grub/gfxmenu_view.h grub-new/include/grub/gfxmenu_view.h
--- grub-2.00/include/grub/gfxmenu_view.h 2012-02-24 14:19:45.000000000 +0400
+++ grub-new/include/grub/gfxmenu_view.h 2013-04-12 16:26:41.869448464 +0400
@@ -66,6 +66,12 @@
grub_font_t font,
grub_video_color_t color,
int left_x, int baseline_y);
+grub_err_t grub_font_draw_multiline (const char *str,
+ grub_font_t font,
+ grub_video_color_t color,
+ int baseline_y, int font_height,
+ int max_width, int max_height,
+ int align);
int grub_font_get_string_width (grub_font_t font,
const char *str);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-16 9:04 [PATCH] multistring support in gui_label Vladimir Testov
@ 2013-04-16 17:10 ` Andrey Borzenkov
2013-04-17 6:56 ` Vladimir Testov
2013-04-17 7:01 ` Vladimir 'φ-coder/phcoder' Serbinenko
1 sibling, 1 reply; 14+ messages in thread
From: Andrey Borzenkov @ 2013-04-16 17:10 UTC (permalink / raw)
To: grub-devel
В Tue, 16 Apr 2013 13:04:28 +0400
Vladimir Testov <vladimir.testov@rosalab.ru> пишет:
> >Please don't use // comments.
> O.k. I won't.
> >This code completely forgets the cases
> >when even the first word doesn't fit in the available space.
>
> Mmm. It can handle this case actually.
>
> >The code as whole breaks some unicode concepts like e.g. bidi stack.
>
> Didn't get what you mean.
>
> >Could you reuse the already available line-vreaking algorithm in
> >normal/term.c and normal/charset.c ? Since the line-breaking is
> >artificially disabled for labels it should require only minor
> >adjustments to be reenabled.
>
> Yep! Here it is (patch included)!
>
> +/* Differs from grub_font_draw_line only in multiline output */
You mean grub_font_draw_string? Is it possible to extend this function
instead of duplicating it?
> +grub_err_t
> +grub_font_draw_multiline (const char *str, grub_font_t font,
> + grub_video_color_t color,
> + int baseline_y, int font_height,
> + int max_width, int max_height,
> + int align)
> +
> + grub_err_t print_line ()
> + {
> + while (pos != ptr)
> + auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c);
> + grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c)
> + {
> + return grub_font_get_constructed_device_width (font, c);
> + }
All nested functions were removed from trunk. Please do not reintroduce
them. This should not even compile.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-16 17:10 ` Andrey Borzenkov
@ 2013-04-17 6:56 ` Vladimir Testov
0 siblings, 0 replies; 14+ messages in thread
From: Vladimir Testov @ 2013-04-17 6:56 UTC (permalink / raw)
To: grub-devel; +Cc: Andrey Borzenkov
On Tuesday, April 16, 2013 09:10:23 PM Andrey Borzenkov wrote:
> > +/* Differs from grub_font_draw_line only in multiline output */
>
> You mean grub_font_draw_string? Is it possible to extend this function
> instead of duplicating it?
Hmmm... I'll think through it. Would it be wise? The sets of parameteres in
these two functions are very different and the code is totally different...
> All nested functions were removed from trunk. Please do not reintroduce
> them. This should not even compile.
My fault. Made the patch for grub-2.00, and forgot to remade it for upstream
version. I've noticed that nested functions were removed. I will remake it
soon.
I've included the patch more for seeing the idea. It is not complete and (I
think) shouldn't be included in the upstream until two problems, I've
mentioned in previous letter, are not fixed. :)
Thank for the reply.
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-16 9:04 [PATCH] multistring support in gui_label Vladimir Testov
2013-04-16 17:10 ` Andrey Borzenkov
@ 2013-04-17 7:01 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-04-17 9:02 ` Vladimir Testov
1 sibling, 1 reply; 14+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-04-17 7:01 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 2208 bytes --]
On 16.04.2013 11:04, Vladimir Testov wrote:
>> Please don't use // comments.
> O.k. I won't.
>> This code completely forgets the cases
>> when even the first word doesn't fit in the available space.
>
> Mmm. It can handle this case actually.
>
>> The code as whole breaks some unicode concepts like e.g. bidi stack.
>
> Didn't get what you mean.
>
>> Could you reuse the already available line-vreaking algorithm in
>> normal/term.c and normal/charset.c ? Since the line-breaking is
>> artificially disabled for labels it should require only minor
>> adjustments to be reenabled.
>
> Yep! Here it is (patch included)!
>
> Nevertheless, two problems appeared and I don't sure how exactly should I fix
> them.
> 1) Handling of some long word. If this word is not first in line and it's
> length is more than label's width
> then the length of the first fragment of the word will be counted as if it will
> be drawn on the same line,
> but actually it will be printed on the next line.
Don't write any line-breaking at all yourself.
> 2) There is funny handling of UTF-8 symbols. Each symbol have "device_width"
> parameter,
> which is used in calculation of string's length.
Where is it used? Show exactly. It must be some leftover code.
> How should I fix these problems?
> 1st one - for example, I can slightly update line-breaking mechanism.
> 2nd one - more interesting, harder. I suggest utf-8 printing mechanism
> (charset.c unicode.c etc) should be remade. So symbol connections will be
> counted in more intelligent way (e.g. while counting spaces - take into
> consideration nearby symbols). It is interesting. :) I can do it. Would be
> happy, if someone could give me some advices.
We don't do any kerning. No need to change algorithm.
>
> Problem2.png
> text = "@KEYMAP_LONG@"
> t is misprinted
>
> Problem1.png
> text = "short short short
> HereWeHaveSomeVeryLongWordSoItCannotBePrintedEntirelyOnOneLine"
> See how the line-breaking works.
>
>
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 294 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-17 7:01 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-04-17 9:02 ` Vladimir Testov
2013-04-17 11:16 ` Vladimir Testov
2013-04-17 11:39 ` Vladimir Testov
0 siblings, 2 replies; 14+ messages in thread
From: Vladimir Testov @ 2013-04-17 9:02 UTC (permalink / raw)
To: grub-devel; +Cc: Vladimir 'φ-coder/phcoder' Serbinenko
[-- Attachment #1: Type: text/plain, Size: 3496 bytes --]
On Wednesday, April 17, 2013 09:01:47 AM Vladimir 'φ-coder/phcoder' Serbinenko
wrote:
> Don't write any line-breaking at all yourself.
I did not write any line-breaking. It is existing line-breaking. And it have
one algorithmic problem. Do not see any problem if I will fix the problem.
The problem persists when we have some long word which cannot be printed
entirely on one line...
> > 2) There is funny handling of UTF-8 symbols. Each symbol have
> > "device_width" parameter,
> > which is used in calculation of string's length.
>
> Where is it used? Show exactly. It must be some leftover code.
> We don't do any kerning. No need to change algorithm.
O.k. Here it is.
from grub-core/font/font.c line 1387 function blit_comb :
> do_blit (combining_glyphs[i],
> main_glyph->device_width
> + combining_glyphs[i]->offset_x,
> -(combining_glyphs[i]->height
> + combining_glyphs[i]->offset_y), &ctx);
> add_device_width (combining_glyphs[i]->device_width, &ctx);
> }
> }
> }
> add_device_width ((above_rightx >
> below_rightx ? above_rightx : below_rightx) -
> (main_glyph->offset_x + main_glyph->width), &ctx);
> add_device_width (above_leftx - main_glyph->offset_x, &ctx);
> if (glyph && glyph->device_width < min_devwidth)
> glyph->device_width = min_devwidth;
> if (device_width && *device_width < min_devwidth)
> *device_width = min_devwidth;
***device_width is changed sometimes.
from grub-core/font/font.c line 1458 function grub_font_construct_dry_run :
> if (device_width)
> *device_width = main_glyph->device_width;
>
> if (!glyph_id->ncomb && !glyph_id->attributes)
> return main_glyph;
>
> combining_glyphs = grub_malloc (sizeof (combining_glyphs[0])
> * glyph_id->ncomb);
> if (glyph_id->ncomb && !combining_glyphs)
> {
> grub_errno = GRUB_ERR_NONE;
> return main_glyph;
> }
>
> for (i = 0; i < glyph_id->ncomb; i++)
> combining_glyphs[i]
> = grub_font_get_glyph_with_fallback (main_glyph->font,
> glyph_id->combining[i].code);
>
> blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs,
> device_width);
> if (combining_glyphs_out)
> *combining_glyphs_out = combining_glyphs;
> else
> grub_free (combining_glyphs);
>
> return main_glyph;
***return value *device_width set to main_glyph->device_width before
main_glyph->device_width is changed during execution of blit_comb
If we want to get device_width of some glyph - we use function
get_constructed_device_width. It returns device_width parameter of the asked
glyph with parameter *device_width of the function
grub_font_construct_dry_run.
When we actually construct glyph, we take device_width from glyph-
>device_width.
The most adequate way to find device_width of grub_unicode_glyph is to call
grub_font_get_constructed_device_width. But it is miscalculated in some cases.
So these two values are different in some cases (This is all about problem 2)
Suggested patch to fix this problem (second one) is attached.
I will remake the patch for multistring support for the upstream version.
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
[-- Attachment #2: grub-get_constructed_device_width-fixed.patch --]
[-- Type: text/x-patch, Size: 521 bytes --]
diff -Naur grub/grub-core/font/font.c grub-new/grub-core/font/font.c
--- grub/grub-core/font/font.c 2013-03-28 23:28:47.784178000 +0400
+++ grub-new/grub-core/font/font.c 2013-04-17 12:21:53.682367388 +0400
@@ -1476,6 +1476,11 @@
blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs,
device_width);
+
+ /* The value could have been changed */
+ if (device_width)
+ *device_width = main_glyph->device_width;
+
if (combining_glyphs_out)
*combining_glyphs_out = combining_glyphs;
else
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-17 9:02 ` Vladimir Testov
@ 2013-04-17 11:16 ` Vladimir Testov
2013-04-17 11:39 ` Vladimir Testov
1 sibling, 0 replies; 14+ messages in thread
From: Vladimir Testov @ 2013-04-17 11:16 UTC (permalink / raw)
To: grub-devel; +Cc: Vladimir 'φ-coder/phcoder' Serbinenko
On Wednesday, April 17, 2013 01:02:44 PM Vladimir Testov wrote:
> Suggested patch to fix this problem (second one) is attached.
Nope, it won't help. I'll think again...
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-17 9:02 ` Vladimir Testov
2013-04-17 11:16 ` Vladimir Testov
@ 2013-04-17 11:39 ` Vladimir Testov
2013-04-17 12:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-04-23 11:58 ` Vladimir Testov
1 sibling, 2 replies; 14+ messages in thread
From: Vladimir Testov @ 2013-04-17 11:39 UTC (permalink / raw)
To: grub-devel; +Cc: Vladimir 'φ-coder/phcoder' Serbinenko
On Wednesday, April 17, 2013 01:02:44 PM Vladimir Testov wrote:
> O.k. Here it is.
>
> from grub-core/font/font.c line 1387 function blit_comb :
> > do_blit (combining_glyphs[i],
> >
> > main_glyph->device_width
> >
> > + combining_glyphs[i]->offset_x,
> > -(combining_glyphs[i]->height
> >
> > + combining_glyphs[i]->offset_y), &ctx);
> >
> > add_device_width (combining_glyphs[i]->device_width, &ctx);
> >
> > }
> >
> > }
> >
> > }
> >
> > add_device_width ((above_rightx >
> >
> > below_rightx ? above_rightx : below_rightx) -
> >
> > (main_glyph->offset_x + main_glyph->width), &ctx);
> >
> > add_device_width (above_leftx - main_glyph->offset_x, &ctx);
> > if (glyph && glyph->device_width < min_devwidth)
> >
> > glyph->device_width = min_devwidth;
> >
> > if (device_width && *device_width < min_devwidth)
> >
> > *device_width = min_devwidth;
>
> ***device_width is changed sometimes.
>
> from grub-core/font/font.c line 1458 function grub_font_construct_dry_run :
> > if (device_width)
> >
> > *device_width = main_glyph->device_width;
> >
> > if (!glyph_id->ncomb && !glyph_id->attributes)
> >
> > return main_glyph;
> >
> > combining_glyphs = grub_malloc (sizeof (combining_glyphs[0])
> >
> > * glyph_id->ncomb);
> >
> > if (glyph_id->ncomb && !combining_glyphs)
> >
> > {
> >
> > grub_errno = GRUB_ERR_NONE;
> > return main_glyph;
> >
> > }
> >
> > for (i = 0; i < glyph_id->ncomb; i++)
> >
> > combining_glyphs[i]
> >
> > = grub_font_get_glyph_with_fallback (main_glyph->font,
> >
> > glyph_id->combining[i].code);
> >
> > blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs,
> >
> > device_width);
> >
> > if (combining_glyphs_out)
> >
> > *combining_glyphs_out = combining_glyphs;
> >
> > else
> >
> > grub_free (combining_glyphs);
> >
> > return main_glyph;
>
> ***return value *device_width set to main_glyph->device_width before
> main_glyph->device_width is changed during execution of blit_comb
>
> If we want to get device_width of some glyph - we use function
> get_constructed_device_width. It returns device_width parameter of the asked
> glyph with parameter *device_width of the function
> grub_font_construct_dry_run.
>
> When we actually construct glyph, we take device_width from glyph-
>
> >device_width.
>
> The most adequate way to find device_width of grub_unicode_glyph is to call
> grub_font_get_constructed_device_width. But it is miscalculated in some
> cases.
>
> So these two values are different in some cases (This is all about problem
> 2)
>
> Suggested patch to fix this problem (second one) is attached.
>
> I will remake the patch for multistring support for the upstream version.
Looks like I've misunderstood something... Sorry. Can't see where the problem
is...
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-17 11:39 ` Vladimir Testov
@ 2013-04-17 12:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-04-23 11:58 ` Vladimir Testov
1 sibling, 0 replies; 14+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-04-17 12:41 UTC (permalink / raw)
To: Vladimir Testov; +Cc: grub-devel
[-- Attachment #1: Type: text/plain, Size: 177 bytes --]
> Looks like I've misunderstood something... Sorry. Can't see where the problem
> is...
>
blit_comb has dry run mode and it's what's used to get constructed length.
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 294 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] multistring support in gui_label
2013-04-17 11:39 ` Vladimir Testov
2013-04-17 12:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-04-23 11:58 ` Vladimir Testov
2013-04-23 16:26 ` [RFC][PATCH] " Vladimir Testov
1 sibling, 1 reply; 14+ messages in thread
From: Vladimir Testov @ 2013-04-23 11:58 UTC (permalink / raw)
To: grub-devel, arvidjaar; +Cc: Vladimir 'φ-coder/phcoder' Serbinenko
[-- Attachment #1: Type: text/plain, Size: 202 bytes --]
Meanwhile,
patch was rebuild for upstream version
still has two problems I've mentioned before
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
[-- Attachment #2: grub-label-multistring.patch --]
[-- Type: text/x-patch, Size: 7704 bytes --]
diff -Naur grub-new2/grub-core/gfxmenu/font.c grub-new3/grub-core/gfxmenu/font.c
--- grub-new2/grub-core/gfxmenu/font.c 2013-04-08 13:00:36.000000000 +0400
+++ grub-new3/grub-core/gfxmenu/font.c 2013-04-23 15:55:02.793444845 +0400
@@ -75,6 +75,95 @@
return GRUB_ERR_NONE;
}
+/* Printing function for grub_font_draw_multiline. */
+static grub_err_t
+print_line (grub_font_t font, grub_video_color_t color,
+ int start_x, int baseline_y,
+ struct grub_unicode_glyph *pos, struct grub_unicode_glyph *end)
+{
+ struct grub_font_glyph *glyph;
+ while (pos != end)
+ {
+ grub_err_t err;
+ glyph = grub_font_construct_glyph (font, pos);
+ if (!glyph)
+ return grub_errno;
+ err = grub_font_draw_glyph (glyph, color, start_x, baseline_y);
+ start_x += glyph->device_width;
+ grub_free (glyph);
+ if (err)
+ return err;
+ pos ++;
+ }
+ return GRUB_ERR_NONE;
+}
+
+/* Get character's printing width. */
+static grub_ssize_t
+font_getcharwidth (const struct grub_unicode_glyph *c, void *font)
+{
+ return grub_font_get_constructed_device_width (font, c);
+}
+
+/* Analog of grub_font_draw_line with multiline output. */
+grub_err_t
+grub_font_draw_multiline (const char *str, grub_font_t font,
+ grub_video_color_t color,
+ int baseline_y, int font_height,
+ int max_width, int max_height,
+ int align)
+{
+ int x;
+ grub_uint32_t *logical;
+ grub_ssize_t logical_len, visual_len;
+ struct grub_unicode_glyph *visual, *ptr, *pos;
+
+ logical_len = grub_utf8_to_ucs4_alloc (str, &logical, 0);
+ if (logical_len < 0)
+ return grub_errno;
+
+ visual_len = grub_bidi_logical_to_visual (logical, logical_len, &visual,
+ font_getcharwidth, font, max_width, 0, 0, 0, 0);
+ grub_free (logical);
+ if (visual_len < 0)
+ return grub_errno;
+
+ pos = visual;
+ for (ptr = visual, x = 0; ptr <= visual + visual_len; ptr++)
+ {
+ if (baseline_y > max_height)
+ break;
+ if (ptr->base == '\n' || ptr == visual + visual_len)
+ {
+ if (align == 1)
+ x = (max_width - x) / 2;
+ else if (align == 2)
+ x = max_width - x;
+ else
+ x = 0;
+
+ grub_err_t err;
+ err = print_line(font, color, x, baseline_y, pos, ptr);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ baseline_y += font_height;
+ x = 0;
+ while ((ptr + 1 < visual + visual_len)
+ && ((ptr + 1)->base == ' '
+ || (ptr + 1)->base == '\t'))
+ ptr ++;
+ pos = ptr + 1;
+ }
+ else
+ x += grub_font_get_constructed_device_width (font, ptr);
+ }
+
+ grub_free (visual);
+
+ return GRUB_ERR_NONE;
+}
+
/* Get the width in pixels of the specified UTF-8 string, when rendered in
in the specified font (but falling back on other fonts for glyphs that
are missing). */
diff -Naur grub-new2/grub-core/gfxmenu/gui_label.c grub-new3/grub-core/gfxmenu/gui_label.c
--- grub-new2/grub-core/gfxmenu/gui_label.c 2013-02-25 16:54:27.000000000 +0400
+++ grub-new3/grub-core/gfxmenu/gui_label.c 2013-04-19 04:01:17.925936541 +0400
@@ -46,6 +46,7 @@
grub_video_rect_t bounds;
char *id;
int visible;
+ int multiline;
char *text;
char *template;
grub_font_t font;
@@ -91,28 +92,46 @@
return;
/* Calculate the starting x coordinate. */
- int left_x;
- if (self->align == align_left)
- left_x = 0;
- else if (self->align == align_center)
- left_x = (self->bounds.width
- - grub_font_get_string_width (self->font, self->text)) / 2;
- else if (self->align == align_right)
- left_x = (self->bounds.width
- - grub_font_get_string_width (self->font, self->text));
- else
- return; /* Invalid alignment. */
+ int left_x = 0;
+ if (!self->multiline)
+ {
+ if (self->align == align_left)
+ left_x = 0;
+ else if (self->align == align_center)
+ left_x = (self->bounds.width
+ - grub_font_get_string_width (self->font, self->text)) / 2;
+ 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;
+ 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));
+ if (!self->multiline)
+ grub_font_draw_string (self->text,
+ self->font,
+ grub_video_map_rgba_color (self->color),
+ left_x,
+ grub_font_get_ascent (self->font));
+ else
+ {
+ int font_height = grub_font_get_max_char_height (self->font);
+ int max_width = self->bounds.width;
+ int max_height = self->bounds.height;
+ grub_font_draw_multiline (self->text,
+ self->font,
+ grub_video_map_rgba_color (self->color),
+ grub_font_get_ascent (self->font),
+ font_height,
+ max_width,
+ max_height,
+ self->align);
+ }
grub_gui_restore_viewport (&vpsave);
}
@@ -148,9 +167,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
@@ -218,6 +243,10 @@
{
self->visible = grub_strcmp (value, "false") != 0;
}
+ else if (grub_strcmp (name, "multiline") == 0)
+ {
+ self->multiline = grub_strcmp (value, "false") != 0;
+ }
else if (grub_strcmp (name, "id") == 0)
{
grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
@@ -257,6 +286,7 @@
return 0;
label->comp.ops = &label_ops;
label->visible = 1;
+ label->multiline = 0;
label->text = grub_strdup ("");
label->font = grub_font_get ("Unknown Regular 16");
label->color.red = 0;
diff -Naur grub-new2/include/grub/gfxmenu_view.h grub-new3/include/grub/gfxmenu_view.h
--- grub-new2/include/grub/gfxmenu_view.h 2013-02-25 16:54:27.000000000 +0400
+++ grub-new3/include/grub/gfxmenu_view.h 2013-04-19 04:01:17.926936694 +0400
@@ -66,6 +66,12 @@
grub_font_t font,
grub_video_color_t color,
int left_x, int baseline_y);
+grub_err_t grub_font_draw_multiline (const char *str,
+ grub_font_t font,
+ grub_video_color_t color,
+ int baseline_y, int font_height,
+ int max_width, int max_height,
+ int align);
int grub_font_get_string_width (grub_font_t font,
const char *str);
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH] multistring support in gui_label
@ 2013-03-22 15:58 Vladimir Testov
2013-04-03 7:20 ` Vladimir 'φ-coder/phcoder' Serbinenko
0 siblings, 1 reply; 14+ messages in thread
From: Vladimir Testov @ 2013-03-22 15:58 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 161 bytes --]
muiltistring changed to multiline
(now we have multiline)
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
[-- Attachment #2: grub-2.00-label-multistring.patch --]
[-- Type: text/x-patch, Size: 8302 bytes --]
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;
}
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] multistring support in gui_label
@ 2013-03-21 17:17 Vladimir Testov
2013-03-21 18:12 ` Gerard Butler
0 siblings, 1 reply; 14+ messages in thread
From: Vladimir Testov @ 2013-03-21 17:17 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 997 bytes --]
This time I've managed not to break backward compatibility.
New option in label - "multistring"
It is "false" by default.
when it is set to "true" (not "false") text is beeing output on multiple
lines.
see screenshots included
let me know if I've made smth wrong.
Thanks. :)
_______________
theme.txt:
+ label {
left = 100
top = 20
height = 100
width = 600
color = "cyan"
align = "right"
text = "@KEYMAP_LONG@"
multistring = "true"
}
+ label {
left = 100
top = 120
height = 300
width = 60
color = "cyan"
align = "right"
text = "@KEYMAP_LONG@"
multistring = "true"
}
+ label {
left = 20
top = 50
height = 600
width = 1
color = "cyan"
align = "right"
text = "@KEYMAP_LONG@"
multistring = "true"
}
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
[-- Attachment #2: grub-2.00-label-multistring.patch --]
[-- Type: text/x-patch, Size: 8318 bytes --]
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-21 20:36:26.574105575 +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 multistring;
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_multistring (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->multistring)
+ label_paint_multistring(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->multistring)
+ {
+ *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, "multistring") == 0)
+ {
+ self->multistring = 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->multistring = 0;
return (grub_gui_component_t) label;
}
[-- Attachment #3: after-label.png --]
[-- Type: image/png, Size: 13233 bytes --]
[-- Attachment #4: before-label.png --]
[-- Type: image/png, Size: 10475 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH] multistring support in gui_label
2013-03-21 17:17 Vladimir Testov
@ 2013-03-21 18:12 ` Gerard Butler
0 siblings, 0 replies; 14+ messages in thread
From: Gerard Butler @ 2013-03-21 18:12 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 1460 bytes --]
Kind of a nitpick, but I think it would be better to call it multi line support instead.
From: vladimir.testov@rosalab.ru
To: grub-devel@gnu.org
Subject: [PATCH] multistring support in gui_label
Date: Thu, 21 Mar 2013 21:17:51 +0400
This time I've managed not to break backward compatibility.
New option in label - "multistring"
It is "false" by default.
when it is set to "true" (not "false") text is beeing output on multiple
lines.
see screenshots included
let me know if I've made smth wrong.
Thanks. :)
_______________
theme.txt:
+ label {
left = 100
top = 20
height = 100
width = 600
color = "cyan"
align = "right"
text = "@KEYMAP_LONG@"
multistring = "true"
}
+ label {
left = 100
top = 120
height = 300
width = 60
color = "cyan"
align = "right"
text = "@KEYMAP_LONG@"
multistring = "true"
}
+ label {
left = 20
top = 50
height = 600
width = 1
color = "cyan"
align = "right"
text = "@KEYMAP_LONG@"
multistring = "true"
}
--
With best regards,
_______________________________
Vladimir Testov, ROSA Laboratory.
www.rosalab.ru
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
[-- Attachment #2: Type: text/html, Size: 2178 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-04-23 16:27 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-16 9:04 [PATCH] multistring support in gui_label Vladimir Testov
2013-04-16 17:10 ` Andrey Borzenkov
2013-04-17 6:56 ` Vladimir Testov
2013-04-17 7:01 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-04-17 9:02 ` Vladimir Testov
2013-04-17 11:16 ` Vladimir Testov
2013-04-17 11:39 ` Vladimir Testov
2013-04-17 12:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-04-23 11:58 ` Vladimir Testov
2013-04-23 16:26 ` [RFC][PATCH] " Vladimir Testov
-- strict thread matches above, loose matches on Subject: below --
2013-03-22 15:58 [PATCH] " Vladimir Testov
2013-04-03 7:20 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-03-21 17:17 Vladimir Testov
2013-03-21 18:12 ` Gerard Butler
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).