From 9a17588459f2bc876c7b3f4c9d86b0489ca1bc5b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 29 Dec 2009 17:31:02 +0100 Subject: [PATCH] Initial support for scalable gfxmenu --- gfxmenu/gui_box.c | 232 +++++++++++++++++++------------- gfxmenu/gui_canvas.c | 120 ++++++++--------- gfxmenu/gui_circular_progress.c | 52 +------ gfxmenu/gui_image.c | 38 +----- gfxmenu/gui_label.c | 36 +---- gfxmenu/gui_list.c | 64 +++------ gfxmenu/gui_progress_bar.c | 48 +------ gfxmenu/gui_string_util.c | 38 ------ gfxmenu/theme_loader.c | 104 ++++++++------ gfxmenu/view.c | 4 +- include/grub/gui.h | 59 +++++++- include/grub/gui_string_util.h | 2 - include/grub/video.h | 8 +- 13 files changed, 368 insertions(+), 437 deletions(-) diff --git a/gfxmenu/gui_box.c b/gfxmenu/gui_box.c index 4fe131f98..45028e5b1 100644 --- a/gfxmenu/gui_box.c +++ b/gfxmenu/gui_box.c @@ -32,17 +32,16 @@ struct component_node typedef struct grub_gui_box *grub_gui_box_t; typedef void (*layout_func_t) (grub_gui_box_t self, int modify_layout, - int *width, int *height); + unsigned *minimal_width, + unsigned *minimal_height); struct grub_gui_box { - struct grub_gui_container_ops *container; + struct grub_gui_container container; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; /* Doubly linked list of components with dummy head & tail nodes. */ struct component_node chead; @@ -87,82 +86,158 @@ box_is_instance (void *vself __attribute__((unused)), const char *type) static void layout_horizontally (grub_gui_box_t self, int modify_layout, - int *width, int *height) + unsigned *min_width, unsigned *min_height) { /* Start at the left (chead) and set the x coordinates as we go right. */ /* All components have their width set to the box's width. */ struct component_node *cur; - int x = 0; - if (height) - *height = 0; + unsigned w = 0, mwfrac = 0, h = 0, x = 0; + grub_fixed_unsigned_t wfrac = 0; + int bogus_frac = 0; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) { grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + if (!c->ishfrac && c->h > 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; + } + } + if (wfrac > GRUB_FIXED_1 || (w > 0 && wfrac == GRUB_FIXED_1)) + bogus_frac = 1; + + if (min_width) + { + if (wfrac < GRUB_FIXED_1) + *min_width = grub_fixed_ufu_divide (w, GRUB_FIXED_1 - wfrac); + else + *min_width = w; + if (*min_width < w + mwfrac) + *min_width = w + mwfrac; + } + if (min_height) + *min_height = h; + + if (!modify_layout) + return; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { grub_video_rect_t r; + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; - c->ops->get_preferred_size (c, &r.width, &r.height); + r.x = x; + r.y = 0; + r.width = 32; + r.height = h; - /* Check and possibly update the maximum width, if non-null. */ - if (height && r.height > *height) - *height = r.height; + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); - /* Set the component's bounds, if the flag is set. */ - if (modify_layout) - { - r.x = x; - r.y = 0; - /* Width comes from the component's preferred size. */ - r.height = self->bounds.height; - c->ops->set_bounds (c, &r); - } + if (!c->iswfrac) + r.width = c->w; + if (c->iswfrac && !bogus_frac) + r.width = grub_fixed_ufu_multiply (self->bounds.width, c->wfrac); + + if (r.width < mw) + r.width = mw; + + c->ops->set_bounds (c, &r); x += r.width; } - - /* Return the sum of the children's preferred widths. */ - if (width) - *width = x; } static void layout_vertically (grub_gui_box_t self, int modify_layout, - int *width, int *height) + unsigned *min_width, unsigned *min_height) { - /* Start at the top (chead) and set the y coordinates as we go down. */ - /* All components have their width set to the vbox's width. */ + /* Start at the top (chead) and set the y coordinates as we go rdown. */ + /* All components have their height set to the box's height. */ struct component_node *cur; - int y = 0; - if (width) - *width = 0; + unsigned h = 0, mhfrac = 0, w = 0, y = 0; + grub_fixed_unsigned_t hfrac = 0; + int bogus_frac = 0; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) { grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + if (!c->iswfrac && c->w > 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; + } + } + if (hfrac > GRUB_FIXED_1 || (h > 0 && hfrac == GRUB_FIXED_1)) + bogus_frac = 1; + + if (min_height) + { + if (hfrac < GRUB_FIXED_1) + *min_height = grub_fixed_ufu_divide (h, GRUB_FIXED_1 - hfrac); + else + *min_height = h; + if (*min_height < h + mhfrac) + *min_height = h + mhfrac; + } + if (min_width) + *min_width = w; + + if (!modify_layout) + return; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { grub_video_rect_t r; + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; - c->ops->get_preferred_size (c, &r.width, &r.height); + r.x = 0; + r.y = y; + r.width = w; + r.height = 32; - /* Check and possibly update the maximum width, if non-null. */ - if (width && r.width > *width) - *width = r.width; + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); - /* Set the component's bounds, if the flag is set. */ - if (modify_layout) - { - r.x = 0; - r.y = y; - r.width = self->bounds.width; - /* Height comes from the component's preferred size. */ - c->ops->set_bounds (c, &r); - } + if (!c->ishfrac) + r.height = c->h; + if (c->ishfrac) + r.height = grub_fixed_ufu_multiply (self->bounds.height, c->hfrac); + + if (r.height < mh) + r.height = mh; + + c->ops->set_bounds (c, &r); y += r.height; } - - /* Return the sum of the children's preferred heights. */ - if (height) - *height = y; } static void @@ -213,16 +288,10 @@ box_get_bounds (void *vself, grub_video_rect_t *bounds) /* The box's preferred size is based on the preferred sizes of its children. */ static void -box_get_preferred_size (void *vself, int *width, int *height) +box_get_minimal_size (void *vself, unsigned *width, unsigned *height) { grub_gui_box_t self = vself; self->layout_func (self, 0, width, height); /* Just calculate the size. */ - - /* Allow preferred dimensions to override the computed dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -241,15 +310,6 @@ box_set_property (void *vself, const char *name, const char *value) else self->id = 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } return grub_errno; } @@ -303,21 +363,22 @@ box_iterate_children (void *vself, cb (cur->component, userdata); } +static struct grub_gui_component_ops box_comp_ops = + { + .destroy = box_destroy, + .get_id = box_get_id, + .is_instance = box_is_instance, + .paint = box_paint, + .set_parent = box_set_parent, + .get_parent = box_get_parent, + .set_bounds = box_set_bounds, + .get_bounds = box_get_bounds, + .get_minimal_size = box_get_minimal_size, + .set_property = box_set_property + }; + static struct grub_gui_container_ops box_ops = { - .component = - { - .destroy = box_destroy, - .get_id = box_get_id, - .is_instance = box_is_instance, - .paint = box_paint, - .set_parent = box_set_parent, - .get_parent = box_get_parent, - .set_bounds = box_set_bounds, - .get_bounds = box_get_bounds, - .get_preferred_size = box_get_preferred_size, - .set_property = box_set_property - }, .add = box_add, .remove = box_remove, .iterate_children = box_iterate_children @@ -329,24 +390,13 @@ static grub_gui_box_t box_new (layout_func_t layout_func) { grub_gui_box_t box; - box = grub_malloc (sizeof (*box)); + box = grub_zalloc (sizeof (*box)); if (! box) return 0; - box->container = &box_ops; - box->parent = 0; - box->bounds.x = 0; - box->bounds.y = 0; - box->bounds.width = 0; - box->bounds.height = 0; - box->id = 0; - box->preferred_width = -1; - box->preferred_height = -1; - box->chead.component = 0; - box->chead.prev = 0; + box->container.ops = &box_ops; + box->container.component.ops = &box_comp_ops; box->chead.next = &box->ctail; - box->ctail.component = 0; box->ctail.prev = &box->chead; - box->ctail.next = 0; box->layout_func = layout_func; return box; } diff --git a/gfxmenu/gui_canvas.c b/gfxmenu/gui_canvas.c index d155364d7..8b55b2a73 100644 --- a/gfxmenu/gui_canvas.c +++ b/gfxmenu/gui_canvas.c @@ -32,13 +32,11 @@ struct component_node struct grub_gui_canvas { - struct grub_gui_container_ops *container; + struct grub_gui_container container; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; /* Component list (dummy head node). */ struct component_node components; }; @@ -88,22 +86,52 @@ canvas_paint (void *vself, const grub_video_rect_t *region) grub_gui_set_viewport (&self->bounds, &vpsave); for (cur = self->components.next; cur; cur = cur->next) { - int pw; - int ph; grub_video_rect_t r; grub_gui_component_t comp; comp = cur->component; - /* Give the child its preferred size. */ - comp->ops->get_preferred_size (comp, &pw, &ph); - comp->ops->get_bounds (comp, &r); - if (r.width != pw || r.height != ph) - { - r.width = pw; - r.height = ph; - comp->ops->set_bounds (comp, &r); - } + 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); + + 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; + } + + comp->ops->set_bounds (comp, &r); /* Paint the child. */ if (grub_video_have_common_points (region, &r)) @@ -140,20 +168,6 @@ canvas_get_bounds (void *vself, grub_video_rect_t *bounds) *bounds = self->bounds; } -static void -canvas_get_preferred_size (void *vself, int *width, int *height) -{ - grub_gui_canvas_t self = vself; - *width = 0; - *height = 0; - - /* Allow preferred dimensions to override the empty dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; -} - static grub_err_t canvas_set_property (void *vself, const char *name, const char *value) { @@ -170,15 +184,6 @@ canvas_set_property (void *vself, const char *name, const char *value) else self->id = 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } return grub_errno; } @@ -227,21 +232,21 @@ canvas_iterate_children (void *vself, cb (cur->component, userdata); } +static struct grub_gui_component_ops canvas_comp_ops = +{ + .destroy = canvas_destroy, + .get_id = canvas_get_id, + .is_instance = canvas_is_instance, + .paint = canvas_paint, + .set_parent = canvas_set_parent, + .get_parent = canvas_get_parent, + .set_bounds = canvas_set_bounds, + .get_bounds = canvas_get_bounds, + .set_property = canvas_set_property +}; + static struct grub_gui_container_ops canvas_ops = { - .component = - { - .destroy = canvas_destroy, - .get_id = canvas_get_id, - .is_instance = canvas_is_instance, - .paint = canvas_paint, - .set_parent = canvas_set_parent, - .get_parent = canvas_get_parent, - .set_bounds = canvas_set_bounds, - .get_bounds = canvas_get_bounds, - .get_preferred_size = canvas_get_preferred_size, - .set_property = canvas_set_property - }, .add = canvas_add, .remove = canvas_remove, .iterate_children = canvas_iterate_children @@ -251,19 +256,10 @@ grub_gui_container_t grub_gui_canvas_new (void) { grub_gui_canvas_t canvas; - canvas = grub_malloc (sizeof (*canvas)); + canvas = grub_zalloc (sizeof (*canvas)); if (! canvas) return 0; - canvas->container = &canvas_ops; - canvas->parent = 0; - canvas->bounds.x = 0; - canvas->bounds.y = 0; - canvas->bounds.width = 0; - canvas->bounds.height = 0; - canvas->id = 0; - canvas->preferred_width = -1; - canvas->preferred_height = -1; - canvas->components.component = 0; - canvas->components.next = 0; + canvas->container.ops = &canvas_ops; + canvas->container.component.ops = &canvas_comp_ops; return (grub_gui_container_t) canvas; } diff --git a/gfxmenu/gui_circular_progress.c b/gfxmenu/gui_circular_progress.c index f3c8bc3af..e57d1c236 100644 --- a/gfxmenu/gui_circular_progress.c +++ b/gfxmenu/gui_circular_progress.c @@ -28,13 +28,11 @@ struct grub_gui_circular_progress { - struct grub_gui_component_ops *circprog_ops; + struct grub_gui_component comp; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; int start; int end; @@ -209,21 +207,6 @@ circprog_get_bounds (void *vself, grub_video_rect_t *bounds) *bounds = self->bounds; } -static void -circprog_get_preferred_size (void *vself, int *width, int *height) -{ - circular_progress_t self = vself; - - *width = 0; - *height = 0; - - /* Allow preferred dimensions to override the circprog dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; -} - static grub_err_t circprog_set_property (void *vself, const char *name, const char *value) { @@ -270,15 +253,6 @@ circprog_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "visible") == 0) { self->visible = grub_strcmp (value, "false") != 0; @@ -304,7 +278,6 @@ static struct grub_gui_component_ops circprog_ops = .get_parent = circprog_get_parent, .set_bounds = circprog_set_bounds, .get_bounds = circprog_get_bounds, - .get_preferred_size = circprog_get_preferred_size, .set_property = circprog_set_property }; @@ -312,32 +285,13 @@ grub_gui_component_t grub_gui_circular_progress_new (void) { circular_progress_t self; - self = grub_malloc (sizeof (*self)); + self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->circprog_ops = &circprog_ops; - self->parent = 0; - self->bounds.x = 0; - self->bounds.y = 0; - self->bounds.width = 0; - self->bounds.height = 0; - self->id = 0; - self->preferred_width = -1; - self->preferred_height = -1; + self->comp.ops = &circprog_ops; self->visible = 1; - self->start = 0; - self->end = 0; - self->value = 0; self->num_ticks = 64; self->start_angle = -64; - self->ticks_disappear = 0; - - self->theme_dir = 0; - self->need_to_load_pixmaps = 0; - self->center_file = 0; - self->tick_file = 0; - self->center_bitmap = 0; - self->tick_bitmap = 0; return (grub_gui_component_t) self; } diff --git a/gfxmenu/gui_image.c b/gfxmenu/gui_image.c index eb2ff1ee0..ef8bcbe9a 100644 --- a/gfxmenu/gui_image.c +++ b/gfxmenu/gui_image.c @@ -26,13 +26,11 @@ struct grub_gui_image { - struct grub_gui_component_ops *image; + struct grub_gui_component component; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; struct grub_video_bitmap *raw_bitmap; struct grub_video_bitmap *bitmap; }; @@ -172,8 +170,9 @@ image_get_bounds (void *vself, grub_video_rect_t *bounds) *bounds = self->bounds; } +/* FIXME: inform rendering system it's not forced minimum. */ static void -image_get_preferred_size (void *vself, int *width, int *height) +image_get_minimal_size (void *vself, unsigned *width, unsigned *height) { grub_gui_image_t self = vself; @@ -187,12 +186,6 @@ image_get_preferred_size (void *vself, int *width, int *height) *width = 0; *height = 0; } - - /* Allow preferred dimensions to override the image dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -217,15 +210,6 @@ image_set_property (void *vself, const char *name, const char *value) grub_gui_image_t self = vself; if (grub_strcmp (name, "file") == 0) return load_image (self, value); - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -247,7 +231,7 @@ static struct grub_gui_component_ops image_ops = .get_parent = image_get_parent, .set_bounds = image_set_bounds, .get_bounds = image_get_bounds, - .get_preferred_size = image_get_preferred_size, + .get_minimal_size = image_get_minimal_size, .set_property = image_set_property }; @@ -255,20 +239,10 @@ grub_gui_component_t grub_gui_image_new (void) { grub_gui_image_t image; - image = grub_malloc (sizeof (*image)); + image = grub_zalloc (sizeof (*image)); if (! image) return 0; - image->image = &image_ops; - image->parent = 0; - image->bounds.x = 0; - image->bounds.y = 0; - image->bounds.width = 0; - image->bounds.height = 0; - image->id = 0; - image->preferred_width = -1; - image->preferred_height = -1; - image->raw_bitmap = 0; - image->bitmap = 0; + image->component.ops = &image_ops; return (grub_gui_component_t) image; } diff --git a/gfxmenu/gui_label.c b/gfxmenu/gui_label.c index 30474f52f..b2835ea1a 100644 --- a/gfxmenu/gui_label.c +++ b/gfxmenu/gui_label.c @@ -39,13 +39,11 @@ enum align_mode { struct grub_gui_label { - struct grub_gui_component_ops *label; + struct grub_gui_component comp; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; char *text; grub_font_t font; @@ -140,18 +138,12 @@ label_get_bounds (void *vself, grub_video_rect_t *bounds) } static void -label_get_preferred_size (void *vself, int *width, int *height) +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)); - - /* Allow preferred dimensions to override the computed dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -189,16 +181,6 @@ label_set_property (void *vself, const char *name, const char *value) { self->visible = grub_strcmp (value, "false") != 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) == GRUB_ERR_NONE) - { - self->preferred_width = w; - self->preferred_height = h; - } - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -220,7 +202,7 @@ static struct grub_gui_component_ops label_ops = .get_parent = label_get_parent, .set_bounds = label_set_bounds, .get_bounds = label_get_bounds, - .get_preferred_size = label_get_preferred_size, + .get_minimal_size = label_get_minimal_size, .set_property = label_set_property }; @@ -228,18 +210,10 @@ grub_gui_component_t grub_gui_label_new (void) { grub_gui_label_t label; - label = grub_malloc (sizeof (*label)); + label = grub_zalloc (sizeof (*label)); if (! label) return 0; - label->label = &label_ops; - label->parent = 0; - label->bounds.x = 0; - label->bounds.y = 0; - label->bounds.width = 0; - label->bounds.height = 0; - label->id = 0; - label->preferred_width = -1; - label->preferred_height = -1; + label->comp.ops = &label_ops; label->visible = 1; label->text = grub_strdup (""); label->font = grub_font_get ("Helvetica 10"); diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index bf6d94657..c55cfd85c 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -26,13 +26,11 @@ struct grub_gui_list_impl { - struct grub_gui_list_ops *list_ops; + struct grub_gui_list list; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; int icon_width; @@ -357,7 +355,7 @@ list_get_bounds (void *vself, grub_video_rect_t *bounds) } static void -list_get_preferred_size (void *vself, int *width, int *height) +list_get_minimal_size (void *vself, unsigned *width, unsigned *height) { list_impl_t self = vself; @@ -387,12 +385,6 @@ list_get_preferred_size (void *vself, int *width, int *height) *width = 0; *height = 0; } - - /* Allow preferred dimensions to override the computed dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -507,15 +499,6 @@ list_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "id") == 0) { grub_free (self->id); @@ -538,21 +521,22 @@ list_set_view_info (void *vself, self->menu = menu; } +static struct grub_gui_component_ops list_comp_ops = + { + .destroy = list_destroy, + .get_id = list_get_id, + .is_instance = list_is_instance, + .paint = list_paint, + .set_parent = list_set_parent, + .get_parent = list_get_parent, + .set_bounds = list_set_bounds, + .get_bounds = list_get_bounds, + .get_minimal_size = list_get_minimal_size, + .set_property = list_set_property + }; + static struct grub_gui_list_ops list_ops = { - .component_ops = - { - .destroy = list_destroy, - .get_id = list_get_id, - .is_instance = list_is_instance, - .paint = list_paint, - .set_parent = list_set_parent, - .get_parent = list_get_parent, - .set_bounds = list_set_bounds, - .get_bounds = list_get_bounds, - .get_preferred_size = list_get_preferred_size, - .set_property = list_set_property - }, .set_view_info = list_set_view_info }; @@ -564,19 +548,13 @@ grub_gui_list_new (void) grub_gui_color_t default_fg_color; grub_gui_color_t default_bg_color; - self = grub_malloc (sizeof (*self)); + self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->list_ops = &list_ops; - self->parent = 0; - self->bounds.x = 0; - self->bounds.y = 0; - self->bounds.width = 0; - self->bounds.height = 0; - self->id = 0; - self->preferred_width = -1; - self->preferred_height = -1; + self->list.ops = &list_ops; + self->list.component.ops = &list_comp_ops; + self->visible = 1; default_font = grub_font_get ("Helvetica 12"); @@ -617,7 +595,7 @@ grub_gui_list_new (void) self->icon_manager = grub_gfxmenu_icon_manager_new (); if (! self->icon_manager) { - self->list_ops->component_ops.destroy (self); + self->list.component.ops->destroy (self); return 0; } grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c index 498711169..9af93cff5 100644 --- a/gfxmenu/gui_progress_bar.c +++ b/gfxmenu/gui_progress_bar.c @@ -27,13 +27,11 @@ struct grub_gui_progress_bar { - struct grub_gui_component_ops *progress_bar; + struct grub_gui_component component; grub_gui_container_t parent; grub_video_rect_t bounds; char *id; - int preferred_width; - int preferred_height; int visible; int start; int end; @@ -221,18 +219,11 @@ progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds) } static void -progress_bar_get_preferred_size (void *vself, int *width, int *height) +progress_bar_get_minimal_size (void *vself __attribute__ ((unused)), + unsigned *width, unsigned *height) { - grub_gui_progress_bar_t self = vself; - *width = 200; *height = 28; - - /* Allow preferred dimensions to override the progress_bar dimensions. */ - if (self->preferred_width >= 0) - *width = self->preferred_width; - if (self->preferred_height >= 0) - *height = self->preferred_height; } static grub_err_t @@ -296,15 +287,6 @@ progress_bar_set_property (void *vself, const char *name, const char *value) grub_free (self->theme_dir); self->theme_dir = value ? grub_strdup (value) : 0; } - else if (grub_strcmp (name, "preferred_size") == 0) - { - int w; - int h; - if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE) - return grub_errno; - self->preferred_width = w; - self->preferred_height = h; - } else if (grub_strcmp (name, "visible") == 0) { self->visible = grub_strcmp (value, "false") != 0; @@ -334,7 +316,7 @@ static struct grub_gui_component_ops progress_bar_ops = .get_parent = progress_bar_get_parent, .set_bounds = progress_bar_set_bounds, .get_bounds = progress_bar_get_bounds, - .get_preferred_size = progress_bar_get_preferred_size, + .get_minimal_size = progress_bar_get_minimal_size, .set_property = progress_bar_set_property }; @@ -342,22 +324,11 @@ grub_gui_component_t grub_gui_progress_bar_new (void) { grub_gui_progress_bar_t self; - self = grub_malloc (sizeof (*self)); + self = grub_zalloc (sizeof (*self)); if (! self) return 0; - self->progress_bar = &progress_bar_ops; - self->parent = 0; - self->bounds.x = 0; - self->bounds.y = 0; - self->bounds.width = 0; - self->bounds.height = 0; - self->id = 0; - self->preferred_width = -1; - self->preferred_height = -1; + self->component.ops = &progress_bar_ops; self->visible = 1; - self->start = 0; - self->end = 0; - self->value = 0; self->show_text = 1; self->text = grub_strdup (""); self->font = grub_font_get ("Helvetica 10"); @@ -369,12 +340,5 @@ grub_gui_progress_bar_new (void) self->bg_color = gray; self->fg_color = lightgray; - self->theme_dir = 0; - self->need_to_recreate_pixmaps = 0; - self->bar_pattern = 0; - self->highlight_pattern = 0; - self->bar_box = 0; - self->highlight_box = 0; - return (grub_gui_component_t) self; } diff --git a/gfxmenu/gui_string_util.c b/gfxmenu/gui_string_util.c index 8ea7c497b..8c51e396a 100644 --- a/gfxmenu/gui_string_util.c +++ b/gfxmenu/gui_string_util.c @@ -325,41 +325,3 @@ grub_gui_parse_color (const char *s, grub_gui_color_t *color) *color = c; return grub_errno; } - -/* Parse a value in the form "(x, y)", storing the first element (x) into - *PX and the second element (y) into *PY. - Returns GRUB_ERR_NONE if successfully parsed. */ -grub_err_t -grub_gui_parse_2_tuple (const char *s, int *px, int *py) -{ - int x; - int y; - - while (*s && grub_isspace (*s)) - s++; - if (*s != '(') - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "missing `(' in 2-tuple `%s'", s); - - /* Skip the opening parentheses. */ - s++; - if (*s == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "unexpected end of 2-tuple after `(' in `%s'", s); - - /* Parse the first element. */ - x = grub_strtol (s, 0, 10); - if ((s = grub_strchr (s, ',')) == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "missing comma in 2-tuple `%s'", s); - - /* Skip the element separator (the comma). */ - s++; - /* Parse the second element. */ - y = grub_strtol (s, 0, 10); - - *px = x; - *py = y; - - return grub_errno; -} diff --git a/gfxmenu/theme_loader.c b/gfxmenu/theme_loader.c index 3512c7bf1..29bc1d2a6 100644 --- a/gfxmenu/theme_loader.c +++ b/gfxmenu/theme_loader.c @@ -510,35 +510,73 @@ read_object (struct parsebuf *p, grub_gui_container_t parent) } /* Handle the property value. */ - if (grub_strcmp (property, "position") == 0) + if (grub_strcmp (property, "left") == 0) { - /* Special case for position value. */ - int x; - int y; - - if (grub_gui_parse_2_tuple (value, &x, &y) == GRUB_ERR_NONE) - { - grub_video_rect_t r; - component->ops->get_bounds (component, &r); - r.x = x; - r.y = y; - component->ops->set_bounds (component, &r); - } + 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; + } } - else if (grub_strcmp (property, "size") == 0) + else if (grub_strcmp (property, "top") == 0) { - /* Special case for size value. */ - int w; - int h; - - if (grub_gui_parse_2_tuple (value, &w, &h) == GRUB_ERR_NONE) - { - grub_video_rect_t r; - component->ops->get_bounds (component, &r); - r.width = w; - r.height = h; - component->ops->set_bounds (component, &r); - } + 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; + } + } + 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; + } + } + 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; + } } else { @@ -552,16 +590,6 @@ read_object (struct parsebuf *p, grub_gui_container_t parent) goto cleanup; } - /* Set the object's size to its preferred size unless the user has - explicitly specified the size. */ - component->ops->get_bounds (component, &bounds); - if (bounds.width == -1 || bounds.height == -1) - { - component->ops->get_preferred_size (component, - &bounds.width, &bounds.height); - component->ops->set_bounds (component, &bounds); - } - cleanup: grub_free (name); return grub_errno; @@ -665,7 +693,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) } if (view->canvas) - view->canvas->ops->component.destroy (view->canvas); + view->canvas->component.ops->destroy (view->canvas); view->canvas = grub_gui_canvas_new (); ((grub_gui_component_t) view->canvas) @@ -708,7 +736,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) fail: if (view->canvas) { - view->canvas->ops->component.destroy (view->canvas); + view->canvas->component.ops->destroy (view->canvas); view->canvas = 0; } diff --git a/gfxmenu/view.c b/gfxmenu/view.c index e2348b6ef..414541dda 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -146,7 +146,7 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) grub_free (view->progress_message_text); grub_free (view->theme_path); if (view->canvas) - view->canvas->ops->component.destroy (view->canvas); + view->canvas->component.ops->destroy (view->canvas); grub_free (view); set_text_mode (); @@ -354,7 +354,7 @@ grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, redraw_background (view, region); if (view->canvas) - view->canvas->ops->component.paint (view->canvas, region); + view->canvas->component.ops->paint (view->canvas, region); draw_title (view); if (grub_video_have_common_points (&view->progress_message_frame, region)) draw_message (view); diff --git a/include/grub/gui.h b/include/grub/gui.h index 385c0962b..873d29e76 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -55,14 +55,13 @@ struct grub_gui_component_ops grub_gui_container_t (*get_parent) (void *self); void (*set_bounds) (void *self, const grub_video_rect_t *bounds); void (*get_bounds) (void *self, grub_video_rect_t *bounds); - void (*get_preferred_size) (void *self, int *width, int *height); + void (*get_minimal_size) (void *self, unsigned *width, unsigned *height); grub_err_t (*set_property) (void *self, const char *name, const char *value); void (*repaint) (void *self, int second_pass); }; struct grub_gui_container_ops { - struct grub_gui_component_ops component; void (*add) (void *self, grub_gui_component_t comp); void (*remove) (void *self, grub_gui_component_t comp); void (*iterate_children) (void *self, @@ -71,24 +70,78 @@ struct grub_gui_container_ops struct grub_gui_list_ops { - struct grub_gui_component_ops component_ops; void (*set_view_info) (void *self, const char *theme_path, grub_gfxmenu_model_t menu); }; +typedef grub_uint32_t grub_fixed_unsigned_t; +#define GRUB_FIXED_1 0x10000 + +static inline unsigned +grub_fixed_ufu_divide (grub_uint32_t a, grub_fixed_unsigned_t b) +{ + return (a << 16) / b; +} + +static inline grub_fixed_unsigned_t +grub_fixed_fuf_divide (grub_fixed_unsigned_t a, grub_uint32_t b) +{ + return a / b; +} + +static inline unsigned +grub_fixed_ufu_multiply (grub_uint32_t a, grub_fixed_unsigned_t b) +{ + return (a * b) >> 16; +} + +static inline unsigned +grub_fixed_to_unsigned (grub_fixed_unsigned_t in) +{ + return in >> 16; +} + +static inline grub_fixed_unsigned_t +grub_unsigned_to_fixed (unsigned in) +{ + return in << 16; +} + 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; + }; }; struct grub_gui_container { + struct grub_gui_component component; struct grub_gui_container_ops *ops; }; struct grub_gui_list { + struct grub_gui_component component; struct grub_gui_list_ops *ops; }; diff --git a/include/grub/gui_string_util.h b/include/grub/gui_string_util.h index 7b5fbb3ea..1baa2eede 100644 --- a/include/grub/gui_string_util.h +++ b/include/grub/gui_string_util.h @@ -34,6 +34,4 @@ int grub_gui_get_named_color (const char *name, grub_gui_color_t *color); grub_err_t grub_gui_parse_color (const char *s, grub_gui_color_t *color); -grub_err_t grub_gui_parse_2_tuple (const char *s, int *px, int *py); - #endif /* GRUB_GUI_STRING_UTIL_HEADER */ diff --git a/include/grub/video.h b/include/grub/video.h index 833df04c8..868e87871 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -160,10 +160,10 @@ struct grub_video_mode_info /* A 2D rectangle type. */ struct grub_video_rect { - int x; - int y; - int width; - int height; + unsigned x; + unsigned y; + unsigned width; + unsigned height; }; typedef struct grub_video_rect grub_video_rect_t;