diff --git a/gfxmenu/gui_box.c b/gfxmenu/gui_box.c index 45028e5b1..38b15f96d 100644 --- a/gfxmenu/gui_box.c +++ b/gfxmenu/gui_box.c @@ -93,7 +93,7 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, struct component_node *cur; unsigned w = 0, mwfrac = 0, h = 0, x = 0; - grub_fixed_unsigned_t wfrac = 0; + grub_fixed_signed_t wfrac = 0; int bogus_frac = 0; for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) @@ -104,17 +104,14 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->ishfrac && c->h > h) + if (c->h > (signed) h) h = c->h; if (mh > h) h = mh; - if (!c->iswfrac) - w += mw > c->w ? mw : c->w; - if (c->iswfrac) - { - wfrac += c->wfrac; - mwfrac += mw; - } + wfrac += c->wfrac; + w += c->w; + if (mw - c->w > 0) + mwfrac += mw - c->w; } if (wfrac > GRUB_FIXED_1 || (w > 0 && wfrac == GRUB_FIXED_1)) bogus_frac = 1; @@ -122,7 +119,7 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, if (min_width) { if (wfrac < GRUB_FIXED_1) - *min_width = grub_fixed_ufu_divide (w, GRUB_FIXED_1 - wfrac); + *min_width = grub_fixed_sfs_divide (w, GRUB_FIXED_1 - wfrac); else *min_width = w; if (*min_width < w + mwfrac) @@ -142,16 +139,14 @@ layout_horizontally (grub_gui_box_t self, int modify_layout, r.x = x; r.y = 0; - r.width = 32; r.height = h; if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->iswfrac) - r.width = c->w; - if (c->iswfrac && !bogus_frac) - r.width = grub_fixed_ufu_multiply (self->bounds.width, c->wfrac); + r.width = c->w; + if (!bogus_frac) + r.width += grub_fixed_sfs_multiply (self->bounds.width, c->wfrac); if (r.width < mw) r.width = mw; @@ -171,7 +166,7 @@ layout_vertically (grub_gui_box_t self, int modify_layout, struct component_node *cur; unsigned h = 0, mhfrac = 0, w = 0, y = 0; - grub_fixed_unsigned_t hfrac = 0; + grub_fixed_signed_t hfrac = 0; int bogus_frac = 0; for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) @@ -182,17 +177,14 @@ layout_vertically (grub_gui_box_t self, int modify_layout, if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->iswfrac && c->w > w) + if (c->w > (signed) w) w = c->w; if (mw > w) w = mw; - if (!c->ishfrac) - h += mh > c->h ? mh : c->h; - if (c->ishfrac) - { - hfrac += c->hfrac; - mhfrac += mh; - } + hfrac += c->hfrac; + h += c->h; + if (mh - c->h > 0) + mhfrac += mh - c->h; } if (hfrac > GRUB_FIXED_1 || (h > 0 && hfrac == GRUB_FIXED_1)) bogus_frac = 1; @@ -200,7 +192,7 @@ layout_vertically (grub_gui_box_t self, int modify_layout, if (min_height) { if (hfrac < GRUB_FIXED_1) - *min_height = grub_fixed_ufu_divide (h, GRUB_FIXED_1 - hfrac); + *min_height = grub_fixed_sfs_divide (h, GRUB_FIXED_1 - hfrac); else *min_height = h; if (*min_height < h + mhfrac) @@ -221,15 +213,13 @@ layout_vertically (grub_gui_box_t self, int modify_layout, r.x = 0; r.y = y; r.width = w; - r.height = 32; if (c->ops->get_minimal_size) c->ops->get_minimal_size (c, &mw, &mh); - if (!c->ishfrac) - r.height = c->h; - if (c->ishfrac) - r.height = grub_fixed_ufu_multiply (self->bounds.height, c->hfrac); + r.height = c->h; + if (!bogus_frac) + r.height += grub_fixed_sfs_multiply (self->bounds.height, c->hfrac); if (r.height < mh) r.height = mh; diff --git a/gfxmenu/gui_canvas.c b/gfxmenu/gui_canvas.c index 8b55b2a73..b3919c2d3 100644 --- a/gfxmenu/gui_canvas.c +++ b/gfxmenu/gui_canvas.c @@ -88,49 +88,51 @@ canvas_paint (void *vself, const grub_video_rect_t *region) { grub_video_rect_t r; grub_gui_component_t comp; + signed x, y, w, h; comp = cur->component; - r.x = 0; - r.y = 0; - r.width = 32; - r.height = 32; - - if (!comp->iswfrac && comp->w) - r.width = comp->w; - - if (!comp->ishfrac && comp->h) - r.height = comp->h; - - if (!comp->isxfrac && comp->x) - r.x = comp->x; - - if (!comp->isyfrac && comp->y) - r.y = comp->y; - - if (comp->ishfrac && comp->hfrac) - r.height = grub_fixed_ufu_multiply (self->bounds.height, comp->hfrac); - - if (comp->iswfrac && comp->wfrac) - r.width = grub_fixed_ufu_multiply (self->bounds.width, comp->wfrac); - - if (comp->isxfrac && comp->xfrac) - r.x = grub_fixed_ufu_multiply (self->bounds.width, comp->xfrac); - - if (comp->isyfrac && comp->yfrac) - r.y = grub_fixed_ufu_multiply (self->bounds.height, comp->yfrac); + w = grub_fixed_sfs_multiply (self->bounds.width, comp->wfrac) + comp->w; + h = grub_fixed_sfs_multiply (self->bounds.height, comp->hfrac) + comp->h; + x = grub_fixed_sfs_multiply (self->bounds.width, comp->xfrac) + comp->x; + y = grub_fixed_sfs_multiply (self->bounds.height, comp->yfrac) + comp->y; if (comp->ops->get_minimal_size) { unsigned mw; unsigned mh; comp->ops->get_minimal_size (comp, &mw, &mh); - if (r.width < mw) - r.width = mw; - if (r.height < mh) - r.height = mh; + if (w < (signed) mw) + w = mw; + if (h < (signed) mh) + h = mh; } + /* Sanity checks. */ + if (w <= 0) + w = 32; + if (h <= 0) + h = 32; + + if (x >= (signed) self->bounds.width) + x = self->bounds.width - 32; + if (y >= (signed) self->bounds.height) + y = self->bounds.height - 32; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + if (x + w >= (signed) self->bounds.width) + w = self->bounds.width - x; + if (y + h >= (signed) self->bounds.height) + h = self->bounds.height - y; + + r.x = x; + r.y = y; + r.width = w; + r.height = h; comp->ops->set_bounds (comp, &r); /* Paint the child. */ diff --git a/gfxmenu/theme_loader.c b/gfxmenu/theme_loader.c index 29bc1d2a6..09637d6b4 100644 --- a/gfxmenu/theme_loader.c +++ b/gfxmenu/theme_loader.c @@ -361,6 +361,40 @@ read_expression (struct parsebuf *p) return grub_new_substring (p->buf, start, end); } +static grub_err_t +parse_proportional_spec (char *value, signed *abs, grub_fixed_signed_t *prop) +{ + signed num; + char *ptr; + int sig = 0; + *abs = 0; + *prop = 0; + ptr = value; + while (*ptr) + { + sig = 0; + + while (*ptr == '-' || *ptr == '+') + { + if (*ptr == '-') + sig = !sig; + ptr++; + } + + num = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + if (sig) + num = -num; + if (*ptr == '%') + *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100); + else + *abs += num; + } + return GRUB_ERR_NONE; +} + + /* Read a GUI object specification from the theme file. Any components created will be added to the GUI container PARENT. */ static grub_err_t @@ -511,78 +545,16 @@ read_object (struct parsebuf *p, grub_gui_container_t parent) /* Handle the property value. */ if (grub_strcmp (property, "left") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->isxfrac = 1; - component->xfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->isxfrac = 0; - component->x = num; - } - } + parse_proportional_spec (value, &component->x, &component->xfrac); else if (grub_strcmp (property, "top") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->isyfrac = 1; - component->yfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->isyfrac = 0; - component->y = num; - } - } + parse_proportional_spec (value, &component->y, &component->yfrac); else if (grub_strcmp (property, "width") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->iswfrac = 1; - component->wfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->iswfrac = 0; - component->w = num; - } - } + parse_proportional_spec (value, &component->w, &component->wfrac); else if (grub_strcmp (property, "height") == 0) - { - unsigned num; - char *ptr; - num = grub_strtoul (value, &ptr, 0); - if (*ptr == '%') - { - component->ishfrac = 1; - component->hfrac - = grub_fixed_fuf_divide (grub_unsigned_to_fixed (num), 100); - } - else - { - component->ishfrac = 0; - component->h = num; - } - } + parse_proportional_spec (value, &component->h, &component->hfrac); else - { - /* General property handling. */ - component->ops->set_property (component, property, value); - } + /* General property handling. */ + component->ops->set_property (component, property, value); grub_free (value); grub_free (property); diff --git a/include/grub/gui.h b/include/grub/gui.h index 9cfbdde81..6f8f44805 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -74,62 +74,50 @@ struct grub_gui_list_ops grub_gfxmenu_view_t view); }; -typedef grub_uint32_t grub_fixed_unsigned_t; +typedef signed grub_fixed_signed_t; #define GRUB_FIXED_1 0x10000 -static inline unsigned -grub_fixed_ufu_divide (grub_uint32_t a, grub_fixed_unsigned_t b) +static inline signed +grub_fixed_sfs_divide (signed a, grub_fixed_signed_t b) { - return (a << 16) / b; + return (a * GRUB_FIXED_1) / b; } -static inline grub_fixed_unsigned_t -grub_fixed_fuf_divide (grub_fixed_unsigned_t a, grub_uint32_t b) +static inline grub_fixed_signed_t +grub_fixed_fsf_divide (grub_fixed_signed_t a, signed b) { return a / b; } -static inline unsigned -grub_fixed_ufu_multiply (grub_uint32_t a, grub_fixed_unsigned_t b) +static inline signed +grub_fixed_sfs_multiply (signed a, grub_fixed_signed_t b) { - return (a * b) >> 16; + return (a * b) / GRUB_FIXED_1; } -static inline unsigned -grub_fixed_to_unsigned (grub_fixed_unsigned_t in) +static inline signed +grub_fixed_to_signed (grub_fixed_signed_t in) { - return in >> 16; + return in / GRUB_FIXED_1; } -static inline grub_fixed_unsigned_t -grub_unsigned_to_fixed (unsigned in) +static inline grub_fixed_signed_t +grub_signed_to_fixed (signed in) { - return in << 16; + return in * GRUB_FIXED_1; } struct grub_gui_component { struct grub_gui_component_ops *ops; - int isxfrac:1; - int isyfrac:1; - int iswfrac:1; - int ishfrac:1; - union { - unsigned x; - grub_fixed_unsigned_t xfrac; - }; - union { - unsigned y; - grub_fixed_unsigned_t yfrac; - }; - union { - unsigned w; - grub_fixed_unsigned_t wfrac; - }; - union { - unsigned h; - grub_fixed_unsigned_t hfrac; - }; + signed x; + grub_fixed_signed_t xfrac; + signed y; + grub_fixed_signed_t yfrac; + signed w; + grub_fixed_signed_t wfrac; + signed h; + grub_fixed_signed_t hfrac; }; struct grub_gui_container