automake commit without merge history
This commit is contained in:
parent
265d68cd10
commit
8c41176882
810 changed files with 4980 additions and 2508 deletions
144
grub-core/gfxmenu/gfxmenu.c
Normal file
144
grub-core/gfxmenu/gfxmenu.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/* gfxmenu.c - Graphical menu interface controller. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/gfxterm.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/menu.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/gfxmenu_model.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
grub_gfxmenu_view_t cached_view;
|
||||
|
||||
static void
|
||||
grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
/* FIXME: Previously 't' changed to text menu is it necessary? */
|
||||
static grub_err_t
|
||||
grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
|
||||
{
|
||||
grub_gfxmenu_view_t view = NULL;
|
||||
const char *theme_path;
|
||||
struct grub_menu_viewer *instance;
|
||||
grub_err_t err;
|
||||
struct grub_video_mode_info mode_info;
|
||||
|
||||
theme_path = grub_env_get ("theme");
|
||||
if (! theme_path)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_gfxterm_fullscreen ();
|
||||
grub_error_pop ();
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified");
|
||||
}
|
||||
|
||||
instance = grub_zalloc (sizeof (*instance));
|
||||
if (!instance)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_gfxterm_fullscreen ();
|
||||
grub_error_pop ();
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
err = grub_video_get_info (&mode_info);
|
||||
if (err)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_gfxterm_fullscreen ();
|
||||
grub_error_pop ();
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!cached_view || grub_strcmp (cached_view->theme_path, theme_path) != 0
|
||||
|| cached_view->screen.width != mode_info.width
|
||||
|| cached_view->screen.height != mode_info.height)
|
||||
{
|
||||
grub_free (cached_view);
|
||||
/* Create the view. */
|
||||
cached_view = grub_gfxmenu_view_new (theme_path, mode_info.width,
|
||||
mode_info.height);
|
||||
}
|
||||
|
||||
if (! cached_view)
|
||||
{
|
||||
grub_free (instance);
|
||||
grub_error_push ();
|
||||
grub_gfxterm_fullscreen ();
|
||||
grub_error_pop ();
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
view = cached_view;
|
||||
|
||||
view->double_repaint = (mode_info.mode_type
|
||||
& GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)
|
||||
&& !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
|
||||
view->selected = entry;
|
||||
view->menu = menu;
|
||||
view->nested = nested;
|
||||
view->first_timeout = -1;
|
||||
|
||||
grub_gfxmenu_view_draw (view);
|
||||
|
||||
instance->data = view;
|
||||
instance->set_chosen_entry = grub_gfxmenu_set_chosen_entry;
|
||||
instance->fini = grub_gfxmenu_viewer_fini;
|
||||
instance->print_timeout = grub_gfxmenu_print_timeout;
|
||||
instance->clear_timeout = grub_gfxmenu_clear_timeout;
|
||||
|
||||
grub_menu_register_viewer (instance);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT (gfxmenu)
|
||||
{
|
||||
struct grub_term_output *term;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0)
|
||||
{
|
||||
grub_gfxterm_fullscreen ();
|
||||
break;
|
||||
}
|
||||
|
||||
grub_gfxmenu_try_hook = grub_gfxmenu_try;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (gfxmenu)
|
||||
{
|
||||
grub_gfxmenu_view_destroy (cached_view);
|
||||
grub_gfxmenu_try_hook = NULL;
|
||||
}
|
412
grub-core/gfxmenu/gui_box.c
Normal file
412
grub-core/gfxmenu/gui_box.c
Normal file
|
@ -0,0 +1,412 @@
|
|||
/* gui_box.c - GUI container that stack components. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
|
||||
struct component_node
|
||||
{
|
||||
grub_gui_component_t component;
|
||||
struct component_node *next;
|
||||
struct component_node *prev;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_box *grub_gui_box_t;
|
||||
|
||||
typedef void (*layout_func_t) (grub_gui_box_t self, int modify_layout,
|
||||
unsigned *minimal_width,
|
||||
unsigned *minimal_height);
|
||||
|
||||
struct grub_gui_box
|
||||
{
|
||||
struct grub_gui_container container;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
|
||||
/* Doubly linked list of components with dummy head & tail nodes. */
|
||||
struct component_node chead;
|
||||
struct component_node ctail;
|
||||
|
||||
/* The layout function: differs for vertical and horizontal boxes. */
|
||||
layout_func_t layout_func;
|
||||
};
|
||||
|
||||
static void
|
||||
box_destroy (void *vself)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
struct component_node *cur;
|
||||
struct component_node *next;
|
||||
for (cur = self->chead.next; cur != &self->ctail; cur = next)
|
||||
{
|
||||
/* Copy the 'next' pointer, since we need it for the next iteration,
|
||||
and we're going to free the memory it is stored in. */
|
||||
next = cur->next;
|
||||
/* Destroy the child component. */
|
||||
cur->component->ops->destroy (cur->component);
|
||||
/* Free the linked list node. */
|
||||
grub_free (cur);
|
||||
}
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static const char *
|
||||
box_get_id (void *vself)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
box_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return (grub_strcmp (type, "component") == 0
|
||||
|| grub_strcmp (type, "container") == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
layout_horizontally (grub_gui_box_t self, int modify_layout,
|
||||
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;
|
||||
unsigned w = 0, mwfrac = 0, h = 0, x = 0;
|
||||
grub_fixed_signed_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->h > (signed) h)
|
||||
h = c->h;
|
||||
if (mh > h)
|
||||
h = mh;
|
||||
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;
|
||||
|
||||
if (min_width)
|
||||
{
|
||||
if (wfrac < GRUB_FIXED_1)
|
||||
*min_width = grub_fixed_sfs_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;
|
||||
|
||||
r.x = x;
|
||||
r.y = 0;
|
||||
r.height = h;
|
||||
|
||||
if (c->ops->get_minimal_size)
|
||||
c->ops->get_minimal_size (c, &mw, &mh);
|
||||
|
||||
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;
|
||||
|
||||
c->ops->set_bounds (c, &r);
|
||||
|
||||
x += r.width;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
layout_vertically (grub_gui_box_t self, int modify_layout,
|
||||
unsigned *min_width, unsigned *min_height)
|
||||
{
|
||||
/* 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;
|
||||
unsigned h = 0, mhfrac = 0, w = 0, y = 0;
|
||||
grub_fixed_signed_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->w > (signed) w)
|
||||
w = c->w;
|
||||
if (mw > w)
|
||||
w = mw;
|
||||
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;
|
||||
|
||||
if (min_height)
|
||||
{
|
||||
if (hfrac < GRUB_FIXED_1)
|
||||
*min_height = grub_fixed_sfs_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;
|
||||
|
||||
r.x = 0;
|
||||
r.y = y;
|
||||
r.width = w;
|
||||
|
||||
if (c->ops->get_minimal_size)
|
||||
c->ops->get_minimal_size (c, &mw, &mh);
|
||||
|
||||
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;
|
||||
|
||||
c->ops->set_bounds (c, &r);
|
||||
|
||||
y += r.height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
box_paint (void *vself, const grub_video_rect_t *region)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
struct component_node *cur;
|
||||
grub_video_rect_t vpsave;
|
||||
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
|
||||
{
|
||||
grub_gui_component_t comp = cur->component;
|
||||
comp->ops->paint (comp, region);
|
||||
}
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
box_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
box_get_parent (void *vself)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
box_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
self->layout_func (self, 1, 0, 0); /* Relayout the children. */
|
||||
}
|
||||
|
||||
static void
|
||||
box_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
/* The box's preferred size is based on the preferred sizes
|
||||
of its children. */
|
||||
static void
|
||||
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. */
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
box_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
{
|
||||
self->id = grub_strdup (value);
|
||||
if (! self->id)
|
||||
return grub_errno;
|
||||
}
|
||||
else
|
||||
self->id = 0;
|
||||
}
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static void
|
||||
box_add (void *vself, grub_gui_component_t comp)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
struct component_node *node;
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (! node)
|
||||
return; /* Note: probably should handle the error. */
|
||||
node->component = comp;
|
||||
/* Insert the node before the tail. */
|
||||
node->prev = self->ctail.prev;
|
||||
node->prev->next = node;
|
||||
node->next = &self->ctail;
|
||||
node->next->prev = node;
|
||||
|
||||
comp->ops->set_parent (comp, (grub_gui_container_t) self);
|
||||
self->layout_func (self, 1, 0, 0); /* Relayout the children. */
|
||||
}
|
||||
|
||||
static void
|
||||
box_remove (void *vself, grub_gui_component_t comp)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
struct component_node *cur;
|
||||
for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
|
||||
{
|
||||
if (cur->component == comp)
|
||||
{
|
||||
/* Unlink 'cur' from the list. */
|
||||
cur->prev->next = cur->next;
|
||||
cur->next->prev = cur->prev;
|
||||
/* Free the node's memory (but don't destroy the component). */
|
||||
grub_free (cur);
|
||||
/* Must not loop again, since 'cur' would be dereferenced! */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
box_iterate_children (void *vself,
|
||||
grub_gui_component_callback cb, void *userdata)
|
||||
{
|
||||
grub_gui_box_t self = vself;
|
||||
struct component_node *cur;
|
||||
for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
|
||||
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 =
|
||||
{
|
||||
.add = box_add,
|
||||
.remove = box_remove,
|
||||
.iterate_children = box_iterate_children
|
||||
};
|
||||
|
||||
/* Box constructor. Specify the appropriate layout function to create
|
||||
a horizontal or vertical stacking box. */
|
||||
static grub_gui_box_t
|
||||
box_new (layout_func_t layout_func)
|
||||
{
|
||||
grub_gui_box_t box;
|
||||
box = grub_zalloc (sizeof (*box));
|
||||
if (! box)
|
||||
return 0;
|
||||
box->container.ops = &box_ops;
|
||||
box->container.component.ops = &box_comp_ops;
|
||||
box->chead.next = &box->ctail;
|
||||
box->ctail.prev = &box->chead;
|
||||
box->layout_func = layout_func;
|
||||
return box;
|
||||
}
|
||||
|
||||
/* Create a new container that stacks its child components horizontally,
|
||||
from left to right. Each child get a width corresponding to its
|
||||
preferred width. The height of each child is set the maximum of the
|
||||
preferred heights of all children. */
|
||||
grub_gui_container_t
|
||||
grub_gui_hbox_new (void)
|
||||
{
|
||||
return (grub_gui_container_t) box_new (layout_horizontally);
|
||||
}
|
||||
|
||||
/* Create a new container that stacks its child components verticallyj,
|
||||
from top to bottom. Each child get a height corresponding to its
|
||||
preferred height. The width of each child is set the maximum of the
|
||||
preferred widths of all children. */
|
||||
grub_gui_container_t
|
||||
grub_gui_vbox_new (void)
|
||||
{
|
||||
return (grub_gui_container_t) box_new (layout_vertically);
|
||||
}
|
267
grub-core/gfxmenu/gui_canvas.c
Normal file
267
grub-core/gfxmenu/gui_canvas.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/* gui_canvas.c - GUI container allowing manually placed components. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
|
||||
/* TODO Add layering so that components can be properly overlaid. */
|
||||
|
||||
struct component_node
|
||||
{
|
||||
grub_gui_component_t component;
|
||||
struct component_node *next;
|
||||
};
|
||||
|
||||
struct grub_gui_canvas
|
||||
{
|
||||
struct grub_gui_container container;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
/* Component list (dummy head node). */
|
||||
struct component_node components;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_canvas *grub_gui_canvas_t;
|
||||
|
||||
static void
|
||||
canvas_destroy (void *vself)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
struct component_node *cur;
|
||||
struct component_node *next;
|
||||
for (cur = self->components.next; cur; cur = next)
|
||||
{
|
||||
/* Copy the 'next' pointer, since we need it for the next iteration,
|
||||
and we're going to free the memory it is stored in. */
|
||||
next = cur->next;
|
||||
/* Destroy the child component. */
|
||||
cur->component->ops->destroy (cur->component);
|
||||
/* Free the linked list node. */
|
||||
grub_free (cur);
|
||||
}
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static const char *
|
||||
canvas_get_id (void *vself)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
canvas_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return (grub_strcmp (type, "component") == 0
|
||||
|| grub_strcmp (type, "container") == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_paint (void *vself, const grub_video_rect_t *region)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
struct component_node *cur;
|
||||
grub_video_rect_t vpsave;
|
||||
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
for (cur = self->components.next; cur; cur = cur->next)
|
||||
{
|
||||
grub_video_rect_t r;
|
||||
grub_gui_component_t comp;
|
||||
signed x, y, w, h;
|
||||
|
||||
comp = cur->component;
|
||||
|
||||
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 (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. */
|
||||
if (grub_video_have_common_points (region, &r))
|
||||
comp->ops->paint (comp, region);
|
||||
}
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
canvas_get_parent (void *vself)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
canvas_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
{
|
||||
self->id = grub_strdup (value);
|
||||
if (! self->id)
|
||||
return grub_errno;
|
||||
}
|
||||
else
|
||||
self->id = 0;
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_add (void *vself, grub_gui_component_t comp)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
struct component_node *node;
|
||||
node = grub_malloc (sizeof (*node));
|
||||
if (! node)
|
||||
return; /* Note: probably should handle the error. */
|
||||
node->component = comp;
|
||||
node->next = self->components.next;
|
||||
self->components.next = node;
|
||||
comp->ops->set_parent (comp, (grub_gui_container_t) self);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_remove (void *vself, grub_gui_component_t comp)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
struct component_node *cur;
|
||||
struct component_node *prev;
|
||||
prev = &self->components;
|
||||
for (cur = self->components.next; cur; prev = cur, cur = cur->next)
|
||||
{
|
||||
if (cur->component == comp)
|
||||
{
|
||||
/* Unlink 'cur' from the list. */
|
||||
prev->next = cur->next;
|
||||
/* Free the node's memory (but don't destroy the component). */
|
||||
grub_free (cur);
|
||||
/* Must not loop again, since 'cur' would be dereferenced! */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_iterate_children (void *vself,
|
||||
grub_gui_component_callback cb, void *userdata)
|
||||
{
|
||||
grub_gui_canvas_t self = vself;
|
||||
struct component_node *cur;
|
||||
for (cur = self->components.next; cur; cur = cur->next)
|
||||
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 =
|
||||
{
|
||||
.add = canvas_add,
|
||||
.remove = canvas_remove,
|
||||
.iterate_children = canvas_iterate_children
|
||||
};
|
||||
|
||||
grub_gui_container_t
|
||||
grub_gui_canvas_new (void)
|
||||
{
|
||||
grub_gui_canvas_t canvas;
|
||||
canvas = grub_zalloc (sizeof (*canvas));
|
||||
if (! canvas)
|
||||
return 0;
|
||||
canvas->container.ops = &canvas_ops;
|
||||
canvas->container.component.ops = &canvas_comp_ops;
|
||||
return (grub_gui_container_t) canvas;
|
||||
}
|
302
grub-core/gfxmenu/gui_circular_progress.c
Normal file
302
grub-core/gfxmenu/gui_circular_progress.c
Normal file
|
@ -0,0 +1,302 @@
|
|||
/* gui_circular_process.c - GUI circular progress indicator component. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/font.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/trig.h>
|
||||
|
||||
struct grub_gui_circular_progress
|
||||
{
|
||||
struct grub_gui_progress progress;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
int visible;
|
||||
int start;
|
||||
int end;
|
||||
int value;
|
||||
int num_ticks;
|
||||
int start_angle;
|
||||
int ticks_disappear;
|
||||
char *theme_dir;
|
||||
int need_to_load_pixmaps;
|
||||
char *center_file;
|
||||
char *tick_file;
|
||||
struct grub_video_bitmap *center_bitmap;
|
||||
struct grub_video_bitmap *tick_bitmap;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_circular_progress *circular_progress_t;
|
||||
|
||||
static void
|
||||
circprog_destroy (void *vself)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static const char *
|
||||
circprog_get_id (void *vself)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
circprog_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return grub_strcmp (type, "component") == 0;
|
||||
}
|
||||
|
||||
static struct grub_video_bitmap *
|
||||
load_bitmap (const char *dir, const char *file)
|
||||
{
|
||||
struct grub_video_bitmap *bitmap;
|
||||
char *abspath;
|
||||
|
||||
/* Check arguments. */
|
||||
if (! dir || ! file)
|
||||
return 0;
|
||||
|
||||
/* Resolve to an absolute path. */
|
||||
abspath = grub_resolve_relative_path (dir, file);
|
||||
if (! abspath)
|
||||
return 0;
|
||||
|
||||
/* Load the image. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_video_bitmap_load (&bitmap, abspath);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
grub_free (abspath);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static int
|
||||
check_pixmaps (circular_progress_t self)
|
||||
{
|
||||
if (self->need_to_load_pixmaps)
|
||||
{
|
||||
if (self->center_bitmap)
|
||||
grub_video_bitmap_destroy (self->center_bitmap);
|
||||
self->center_bitmap = load_bitmap (self->theme_dir, self->center_file);
|
||||
self->tick_bitmap = load_bitmap (self->theme_dir, self->tick_file);
|
||||
self->need_to_load_pixmaps = 0;
|
||||
}
|
||||
|
||||
return (self->center_bitmap != 0 && self->tick_bitmap != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
circprog_paint (void *vself, const grub_video_rect_t *region)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
|
||||
if (! self->visible)
|
||||
return;
|
||||
|
||||
if (!grub_video_have_common_points (region, &self->bounds))
|
||||
return;
|
||||
|
||||
if (! check_pixmaps (self))
|
||||
return;
|
||||
|
||||
grub_video_rect_t vpsave;
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
|
||||
int width = self->bounds.width;
|
||||
int height = self->bounds.height;
|
||||
int center_width = grub_video_bitmap_get_width (self->center_bitmap);
|
||||
int center_height = grub_video_bitmap_get_height (self->center_bitmap);
|
||||
int tick_width = grub_video_bitmap_get_width (self->tick_bitmap);
|
||||
int tick_height = grub_video_bitmap_get_height (self->tick_bitmap);
|
||||
grub_video_blit_bitmap (self->center_bitmap, GRUB_VIDEO_BLIT_BLEND,
|
||||
(width - center_width) / 2,
|
||||
(height - center_height) / 2, 0, 0,
|
||||
center_width, center_height);
|
||||
|
||||
int radius = width / 2 - tick_width / 2 - 1;
|
||||
int nticks;
|
||||
int tick_begin;
|
||||
int tick_end;
|
||||
if (self->end == self->start)
|
||||
nticks = 0;
|
||||
else
|
||||
nticks = (self->num_ticks
|
||||
* (self->value - self->start)
|
||||
/ (self->end - self->start));
|
||||
/* Do ticks appear or disappear as the value approached the end? */
|
||||
if (self->ticks_disappear)
|
||||
{
|
||||
tick_begin = nticks;
|
||||
tick_end = self->num_ticks - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tick_begin = 0;
|
||||
tick_end = nticks - 1;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = tick_begin; i < tick_end; i++)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int angle;
|
||||
|
||||
/* Calculate the location of the tick. */
|
||||
angle = self->start_angle + i * GRUB_TRIG_ANGLE_MAX / self->num_ticks;
|
||||
x = width / 2 + (grub_cos (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
|
||||
y = height / 2 + (grub_sin (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
|
||||
|
||||
/* Adjust (x,y) so the tick is centered. */
|
||||
x -= tick_width / 2;
|
||||
y -= tick_height / 2;
|
||||
|
||||
/* Draw the tick. */
|
||||
grub_video_blit_bitmap (self->tick_bitmap, GRUB_VIDEO_BLIT_BLEND,
|
||||
x, y, 0, 0, tick_width, tick_height);
|
||||
}
|
||||
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
circprog_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
circprog_get_parent (void *vself)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
circprog_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
circprog_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
circprog_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
if (grub_strcmp (name, "num_ticks") == 0)
|
||||
{
|
||||
self->num_ticks = grub_strtol (value, 0, 10);
|
||||
}
|
||||
else if (grub_strcmp (name, "start_angle") == 0)
|
||||
{
|
||||
self->start_angle = grub_strtol (value, 0, 10);
|
||||
}
|
||||
else if (grub_strcmp (name, "ticks_disappear") == 0)
|
||||
{
|
||||
self->ticks_disappear = grub_strcmp (value, "false") != 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "center_bitmap") == 0)
|
||||
{
|
||||
self->need_to_load_pixmaps = 1;
|
||||
grub_free (self->center_file);
|
||||
self->center_file = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "tick_bitmap") == 0)
|
||||
{
|
||||
self->need_to_load_pixmaps = 1;
|
||||
grub_free (self->tick_file);
|
||||
self->tick_file = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "theme_dir") == 0)
|
||||
{
|
||||
self->need_to_load_pixmaps = 1;
|
||||
grub_free (self->theme_dir);
|
||||
self->theme_dir = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
self->id = grub_strdup (value);
|
||||
else
|
||||
self->id = 0;
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static void
|
||||
circprog_set_state (void *vself, int visible, int start,
|
||||
int current, int end)
|
||||
{
|
||||
circular_progress_t self = vself;
|
||||
self->visible = visible;
|
||||
self->start = start;
|
||||
self->value = current;
|
||||
self->end = end;
|
||||
}
|
||||
|
||||
static struct grub_gui_component_ops circprog_ops =
|
||||
{
|
||||
.destroy = circprog_destroy,
|
||||
.get_id = circprog_get_id,
|
||||
.is_instance = circprog_is_instance,
|
||||
.paint = circprog_paint,
|
||||
.set_parent = circprog_set_parent,
|
||||
.get_parent = circprog_get_parent,
|
||||
.set_bounds = circprog_set_bounds,
|
||||
.get_bounds = circprog_get_bounds,
|
||||
.set_property = circprog_set_property
|
||||
};
|
||||
|
||||
static struct grub_gui_progress_ops circprog_prog_ops =
|
||||
{
|
||||
.set_state = circprog_set_state
|
||||
};
|
||||
|
||||
grub_gui_component_t
|
||||
grub_gui_circular_progress_new (void)
|
||||
{
|
||||
circular_progress_t self;
|
||||
self = grub_zalloc (sizeof (*self));
|
||||
if (! self)
|
||||
return 0;
|
||||
self->progress.ops = &circprog_prog_ops;
|
||||
self->progress.component.ops = &circprog_ops;
|
||||
self->visible = 1;
|
||||
self->num_ticks = 64;
|
||||
self->start_angle = -64;
|
||||
|
||||
return (grub_gui_component_t) self;
|
||||
}
|
269
grub-core/gfxmenu/gui_image.c
Normal file
269
grub-core/gfxmenu/gui_image.c
Normal file
|
@ -0,0 +1,269 @@
|
|||
/* gui_image.c - GUI component to display an image. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
|
||||
struct grub_gui_image
|
||||
{
|
||||
struct grub_gui_component component;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
char *theme_dir;
|
||||
struct grub_video_bitmap *raw_bitmap;
|
||||
struct grub_video_bitmap *bitmap;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_image *grub_gui_image_t;
|
||||
|
||||
static void
|
||||
image_destroy (void *vself)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
|
||||
/* Free the scaled bitmap, unless it's a reference to the raw bitmap. */
|
||||
if (self->bitmap && (self->bitmap != self->raw_bitmap))
|
||||
grub_video_bitmap_destroy (self->bitmap);
|
||||
if (self->raw_bitmap)
|
||||
grub_video_bitmap_destroy (self->raw_bitmap);
|
||||
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static const char *
|
||||
image_get_id (void *vself)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
image_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return grub_strcmp (type, "component") == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
image_paint (void *vself, const grub_video_rect_t *region)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
grub_video_rect_t vpsave;
|
||||
|
||||
if (! self->bitmap)
|
||||
return;
|
||||
if (!grub_video_have_common_points (region, &self->bounds))
|
||||
return;
|
||||
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
grub_video_blit_bitmap (self->bitmap, GRUB_VIDEO_BLIT_BLEND,
|
||||
0, 0, 0, 0,
|
||||
grub_video_bitmap_get_width (self->bitmap),
|
||||
grub_video_bitmap_get_height (self->bitmap));
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
image_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
image_get_parent (void *vself)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
rescale_image (grub_gui_image_t self)
|
||||
{
|
||||
if (! self->raw_bitmap)
|
||||
{
|
||||
if (self->bitmap)
|
||||
{
|
||||
grub_video_bitmap_destroy (self->bitmap);
|
||||
self->bitmap = 0;
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
unsigned width = self->bounds.width;
|
||||
unsigned height = self->bounds.height;
|
||||
|
||||
if (self->bitmap
|
||||
&& (grub_video_bitmap_get_width (self->bitmap) == width)
|
||||
&& (grub_video_bitmap_get_height (self->bitmap) == height))
|
||||
{
|
||||
/* Nothing to do; already the right size. */
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Free any old scaled bitmap,
|
||||
*unless* it's a reference to the raw bitmap. */
|
||||
if (self->bitmap && (self->bitmap != self->raw_bitmap))
|
||||
grub_video_bitmap_destroy (self->bitmap);
|
||||
|
||||
self->bitmap = 0;
|
||||
|
||||
/* Create a scaled bitmap, unless the requested size is the same
|
||||
as the raw size -- in that case a reference is made. */
|
||||
if (grub_video_bitmap_get_width (self->raw_bitmap) == width
|
||||
&& grub_video_bitmap_get_height (self->raw_bitmap) == height)
|
||||
{
|
||||
self->bitmap = self->raw_bitmap;
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Don't scale to an invalid size. */
|
||||
if (width == 0 || height == 0)
|
||||
return grub_errno;
|
||||
|
||||
/* Create the scaled bitmap. */
|
||||
grub_video_bitmap_create_scaled (&self->bitmap,
|
||||
width,
|
||||
height,
|
||||
self->raw_bitmap,
|
||||
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_error (grub_errno, "failed to scale bitmap for image component");
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static void
|
||||
image_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
rescale_image (self);
|
||||
}
|
||||
|
||||
static void
|
||||
image_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
/* FIXME: inform rendering system it's not forced minimum. */
|
||||
static void
|
||||
image_get_minimal_size (void *vself, unsigned *width, unsigned *height)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
|
||||
if (self->raw_bitmap)
|
||||
{
|
||||
*width = grub_video_bitmap_get_width (self->raw_bitmap);
|
||||
*height = grub_video_bitmap_get_height (self->raw_bitmap);
|
||||
}
|
||||
else
|
||||
{
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
load_image (grub_gui_image_t self, const char *path)
|
||||
{
|
||||
struct grub_video_bitmap *bitmap;
|
||||
if (grub_video_bitmap_load (&bitmap, path) != GRUB_ERR_NONE)
|
||||
return grub_errno;
|
||||
|
||||
if (self->bitmap && (self->bitmap != self->raw_bitmap))
|
||||
grub_video_bitmap_destroy (self->bitmap);
|
||||
if (self->raw_bitmap)
|
||||
grub_video_bitmap_destroy (self->raw_bitmap);
|
||||
|
||||
self->raw_bitmap = bitmap;
|
||||
return rescale_image (self);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
image_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
grub_gui_image_t self = vself;
|
||||
if (grub_strcmp (name, "theme_dir") == 0)
|
||||
{
|
||||
grub_free (self->theme_dir);
|
||||
self->theme_dir = grub_strdup (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "file") == 0)
|
||||
{
|
||||
char *absvalue;
|
||||
grub_err_t err;
|
||||
|
||||
/* Resolve to an absolute path. */
|
||||
if (! self->theme_dir)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unspecified theme_dir");
|
||||
absvalue = grub_resolve_relative_path (self->theme_dir, value);
|
||||
if (! absvalue)
|
||||
return grub_errno;
|
||||
|
||||
err = load_image (self, absvalue);
|
||||
grub_free (absvalue);
|
||||
|
||||
return err;
|
||||
}
|
||||
else if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
self->id = grub_strdup (value);
|
||||
else
|
||||
self->id = 0;
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static struct grub_gui_component_ops image_ops =
|
||||
{
|
||||
.destroy = image_destroy,
|
||||
.get_id = image_get_id,
|
||||
.is_instance = image_is_instance,
|
||||
.paint = image_paint,
|
||||
.set_parent = image_set_parent,
|
||||
.get_parent = image_get_parent,
|
||||
.set_bounds = image_set_bounds,
|
||||
.get_bounds = image_get_bounds,
|
||||
.get_minimal_size = image_get_minimal_size,
|
||||
.set_property = image_set_property
|
||||
};
|
||||
|
||||
grub_gui_component_t
|
||||
grub_gui_image_new (void)
|
||||
{
|
||||
grub_gui_image_t image;
|
||||
image = grub_zalloc (sizeof (*image));
|
||||
if (! image)
|
||||
return 0;
|
||||
image->component.ops = &image_ops;
|
||||
return (grub_gui_component_t) image;
|
||||
}
|
||||
|
226
grub-core/gfxmenu/gui_label.c
Normal file
226
grub-core/gfxmenu/gui_label.c
Normal file
|
@ -0,0 +1,226 @@
|
|||
/* gui_label.c - GUI component to display a line of text. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/font.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
|
||||
static const char *align_options[] =
|
||||
{
|
||||
"left",
|
||||
"center",
|
||||
"right",
|
||||
0
|
||||
};
|
||||
|
||||
enum align_mode {
|
||||
align_left,
|
||||
align_center,
|
||||
align_right
|
||||
};
|
||||
|
||||
struct grub_gui_label
|
||||
{
|
||||
struct grub_gui_component comp;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
int visible;
|
||||
char *text;
|
||||
grub_font_t font;
|
||||
grub_gui_color_t color;
|
||||
enum align_mode align;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_label *grub_gui_label_t;
|
||||
|
||||
static void
|
||||
label_destroy (void *vself)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
grub_free (self->text);
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static const char *
|
||||
label_get_id (void *vself)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
label_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return grub_strcmp (type, "component") == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
label_paint (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;
|
||||
|
||||
/* 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. */
|
||||
|
||||
grub_video_rect_t vpsave;
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
grub_font_draw_string (self->text,
|
||||
self->font,
|
||||
grub_gui_map_color (self->color),
|
||||
left_x,
|
||||
grub_font_get_ascent (self->font));
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
label_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
label_get_parent (void *vself)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
label_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
label_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
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));
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
label_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
if (grub_strcmp (name, "text") == 0)
|
||||
{
|
||||
grub_free (self->text);
|
||||
if (! value)
|
||||
value = "";
|
||||
self->text = grub_strdup (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "font") == 0)
|
||||
{
|
||||
self->font = grub_font_get (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "color") == 0)
|
||||
{
|
||||
grub_gui_parse_color (value, &self->color);
|
||||
}
|
||||
else if (grub_strcmp (name, "align") == 0)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; align_options[i]; i++)
|
||||
{
|
||||
if (grub_strcmp (align_options[i], value) == 0)
|
||||
{
|
||||
self->align = i; /* Set the alignment mode. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (grub_strcmp (name, "visible") == 0)
|
||||
{
|
||||
self->visible = grub_strcmp (value, "false") != 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
self->id = grub_strdup (value);
|
||||
else
|
||||
self->id = 0;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_gui_component_ops label_ops =
|
||||
{
|
||||
.destroy = label_destroy,
|
||||
.get_id = label_get_id,
|
||||
.is_instance = label_is_instance,
|
||||
.paint = label_paint,
|
||||
.set_parent = label_set_parent,
|
||||
.get_parent = label_get_parent,
|
||||
.set_bounds = label_set_bounds,
|
||||
.get_bounds = label_get_bounds,
|
||||
.get_minimal_size = label_get_minimal_size,
|
||||
.set_property = label_set_property
|
||||
};
|
||||
|
||||
grub_gui_component_t
|
||||
grub_gui_label_new (void)
|
||||
{
|
||||
grub_gui_label_t label;
|
||||
label = grub_zalloc (sizeof (*label));
|
||||
if (! label)
|
||||
return 0;
|
||||
label->comp.ops = &label_ops;
|
||||
label->visible = 1;
|
||||
label->text = grub_strdup ("");
|
||||
label->font = grub_font_get ("Unknown Regular 16");
|
||||
label->color.red = 0;
|
||||
label->color.green = 0;
|
||||
label->color.blue = 0;
|
||||
label->color.alpha = 255;
|
||||
label->align = align_left;
|
||||
return (grub_gui_component_t) label;
|
||||
}
|
612
grub-core/gfxmenu/gui_list.c
Normal file
612
grub-core/gfxmenu/gui_list.c
Normal file
|
@ -0,0 +1,612 @@
|
|||
/* gui_list.c - GUI component to display a selectable list of items. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
|
||||
struct grub_gui_list_impl
|
||||
{
|
||||
struct grub_gui_list list;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
int visible;
|
||||
|
||||
int icon_width;
|
||||
int icon_height;
|
||||
int item_height;
|
||||
int item_padding;
|
||||
int item_icon_space;
|
||||
int item_spacing;
|
||||
grub_font_t item_font;
|
||||
grub_font_t selected_item_font;
|
||||
grub_gui_color_t item_color;
|
||||
int selected_item_color_set;
|
||||
grub_gui_color_t selected_item_color;
|
||||
|
||||
int draw_scrollbar;
|
||||
int need_to_recreate_scrollbar;
|
||||
char *scrollbar_frame_pattern;
|
||||
char *scrollbar_thumb_pattern;
|
||||
grub_gfxmenu_box_t scrollbar_frame;
|
||||
grub_gfxmenu_box_t scrollbar_thumb;
|
||||
int scrollbar_width;
|
||||
|
||||
int first_shown_index;
|
||||
|
||||
int need_to_recreate_boxes;
|
||||
char *theme_dir;
|
||||
char *menu_box_pattern;
|
||||
char *selected_item_box_pattern;
|
||||
grub_gfxmenu_box_t menu_box;
|
||||
grub_gfxmenu_box_t selected_item_box;
|
||||
|
||||
grub_gfxmenu_icon_manager_t icon_manager;
|
||||
|
||||
grub_gfxmenu_view_t view;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_list_impl *list_impl_t;
|
||||
|
||||
static void
|
||||
list_destroy (void *vself)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
|
||||
grub_free (self->theme_dir);
|
||||
grub_free (self->menu_box_pattern);
|
||||
grub_free (self->selected_item_box_pattern);
|
||||
if (self->menu_box)
|
||||
self->menu_box->destroy (self->menu_box);
|
||||
if (self->selected_item_box)
|
||||
self->selected_item_box->destroy (self->selected_item_box);
|
||||
if (self->icon_manager)
|
||||
grub_gfxmenu_icon_manager_destroy (self->icon_manager);
|
||||
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static int
|
||||
get_num_shown_items (list_impl_t self)
|
||||
{
|
||||
int boxpad = self->item_padding;
|
||||
int item_vspace = self->item_spacing;
|
||||
int item_height = self->item_height;
|
||||
|
||||
grub_gfxmenu_box_t box = self->menu_box;
|
||||
int box_top_pad = box->get_top_pad (box);
|
||||
int box_bottom_pad = box->get_bottom_pad (box);
|
||||
|
||||
return (self->bounds.height + item_vspace - 2 * boxpad
|
||||
- box_top_pad - box_bottom_pad) / (item_height + item_vspace);
|
||||
}
|
||||
|
||||
static int
|
||||
check_boxes (list_impl_t self)
|
||||
{
|
||||
if (self->need_to_recreate_boxes)
|
||||
{
|
||||
grub_gui_recreate_box (&self->menu_box,
|
||||
self->menu_box_pattern,
|
||||
self->theme_dir);
|
||||
|
||||
grub_gui_recreate_box (&self->selected_item_box,
|
||||
self->selected_item_box_pattern,
|
||||
self->theme_dir);
|
||||
|
||||
self->need_to_recreate_boxes = 0;
|
||||
}
|
||||
|
||||
return (self->menu_box != 0 && self->selected_item_box != 0);
|
||||
}
|
||||
|
||||
static int
|
||||
check_scrollbar (list_impl_t self)
|
||||
{
|
||||
if (self->need_to_recreate_scrollbar)
|
||||
{
|
||||
grub_gui_recreate_box (&self->scrollbar_frame,
|
||||
self->scrollbar_frame_pattern,
|
||||
self->theme_dir);
|
||||
|
||||
grub_gui_recreate_box (&self->scrollbar_thumb,
|
||||
self->scrollbar_thumb_pattern,
|
||||
self->theme_dir);
|
||||
|
||||
self->need_to_recreate_scrollbar = 0;
|
||||
}
|
||||
|
||||
return (self->scrollbar_frame != 0 && self->scrollbar_thumb != 0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
list_get_id (void *vself)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
list_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return (grub_strcmp (type, "component") == 0
|
||||
|| grub_strcmp (type, "list") == 0);
|
||||
}
|
||||
|
||||
static struct grub_video_bitmap *
|
||||
get_item_icon (list_impl_t self, int item_index)
|
||||
{
|
||||
grub_menu_entry_t entry;
|
||||
entry = grub_menu_get_entry (self->view->menu, item_index);
|
||||
if (! entry)
|
||||
return 0;
|
||||
|
||||
return grub_gfxmenu_icon_manager_get_icon (self->icon_manager, entry);
|
||||
}
|
||||
|
||||
static void
|
||||
make_selected_item_visible (list_impl_t self)
|
||||
{
|
||||
int selected_index = self->view->selected;
|
||||
if (selected_index < 0)
|
||||
return; /* No item is selected. */
|
||||
int num_shown_items = get_num_shown_items (self);
|
||||
int last_shown_index = self->first_shown_index + (num_shown_items - 1);
|
||||
if (selected_index < self->first_shown_index)
|
||||
self->first_shown_index = selected_index;
|
||||
else if (selected_index > last_shown_index)
|
||||
self->first_shown_index = selected_index - (num_shown_items - 1);
|
||||
}
|
||||
|
||||
/* Draw a scrollbar on the menu. */
|
||||
static void
|
||||
draw_scrollbar (list_impl_t self,
|
||||
int value, int extent, int min, int max,
|
||||
int rightx, int topy, int height)
|
||||
{
|
||||
grub_gfxmenu_box_t frame = self->scrollbar_frame;
|
||||
grub_gfxmenu_box_t thumb = self->scrollbar_thumb;
|
||||
int frame_vertical_pad = (frame->get_top_pad (frame)
|
||||
+ frame->get_bottom_pad (frame));
|
||||
int frame_horizontal_pad = (frame->get_left_pad (frame)
|
||||
+ frame->get_right_pad (frame));
|
||||
int tracktop = topy + frame->get_top_pad (frame);
|
||||
int tracklen = height - frame_vertical_pad;
|
||||
frame->set_content_size (frame, self->scrollbar_width, tracklen);
|
||||
int thumby = tracktop + tracklen * (value - min) / (max - min);
|
||||
int thumbheight = tracklen * extent / (max - min) + 1;
|
||||
thumb->set_content_size (thumb,
|
||||
self->scrollbar_width - frame_horizontal_pad,
|
||||
thumbheight - (thumb->get_top_pad (thumb)
|
||||
+ thumb->get_bottom_pad (thumb)));
|
||||
frame->draw (frame,
|
||||
rightx - (self->scrollbar_width + frame_horizontal_pad),
|
||||
topy);
|
||||
thumb->draw (thumb,
|
||||
rightx - (self->scrollbar_width - frame->get_right_pad (frame)),
|
||||
thumby);
|
||||
}
|
||||
|
||||
/* Draw the list of items. */
|
||||
static void
|
||||
draw_menu (list_impl_t self, int width, int drawing_scrollbar,
|
||||
int num_shown_items)
|
||||
{
|
||||
if (! self->menu_box || ! self->selected_item_box)
|
||||
return;
|
||||
|
||||
int boxpad = self->item_padding;
|
||||
int icon_text_space = self->item_icon_space;
|
||||
int item_vspace = self->item_spacing;
|
||||
|
||||
int ascent = grub_font_get_ascent (self->item_font);
|
||||
int descent = grub_font_get_descent (self->item_font);
|
||||
int item_height = self->item_height;
|
||||
|
||||
make_selected_item_visible (self);
|
||||
|
||||
int scrollbar_h_space = drawing_scrollbar ? self->scrollbar_width : 0;
|
||||
|
||||
grub_gfxmenu_box_t selbox = self->selected_item_box;
|
||||
int sel_leftpad = selbox->get_left_pad (selbox);
|
||||
int item_top = boxpad;
|
||||
int item_left = boxpad + sel_leftpad;
|
||||
int menu_index;
|
||||
int visible_index;
|
||||
|
||||
for (visible_index = 0, menu_index = self->first_shown_index;
|
||||
visible_index < num_shown_items && menu_index < self->view->menu->size;
|
||||
visible_index++, menu_index++)
|
||||
{
|
||||
int is_selected = (menu_index == self->view->selected);
|
||||
|
||||
if (is_selected)
|
||||
{
|
||||
int sel_toppad = selbox->get_top_pad (selbox);
|
||||
selbox->set_content_size (selbox,
|
||||
(width - 2 * boxpad
|
||||
- scrollbar_h_space),
|
||||
item_height);
|
||||
selbox->draw (selbox,
|
||||
item_left - sel_leftpad,
|
||||
item_top - sel_toppad);
|
||||
}
|
||||
|
||||
struct grub_video_bitmap *icon;
|
||||
if ((icon = get_item_icon (self, menu_index)) != 0)
|
||||
grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND,
|
||||
item_left,
|
||||
item_top + (item_height - self->icon_height) / 2,
|
||||
0, 0, self->icon_width, self->icon_height);
|
||||
|
||||
const char *item_title =
|
||||
grub_menu_get_entry (self->view->menu, menu_index)->title;
|
||||
grub_font_t font =
|
||||
(is_selected && self->selected_item_font
|
||||
? self->selected_item_font
|
||||
: self->item_font);
|
||||
grub_gui_color_t text_color =
|
||||
((is_selected && self->selected_item_color_set)
|
||||
? self->selected_item_color
|
||||
: self->item_color);
|
||||
grub_font_draw_string (item_title,
|
||||
font,
|
||||
grub_gui_map_color (text_color),
|
||||
item_left + self->icon_width + icon_text_space,
|
||||
(item_top + (item_height - (ascent + descent))
|
||||
/ 2 + ascent));
|
||||
|
||||
item_top += item_height + item_vspace;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
list_paint (void *vself, const grub_video_rect_t *region)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
grub_video_rect_t vpsave;
|
||||
|
||||
if (! self->visible)
|
||||
return;
|
||||
if (!grub_video_have_common_points (region, &self->bounds))
|
||||
return;
|
||||
|
||||
check_boxes (self);
|
||||
|
||||
if (! self->menu_box || ! self->selected_item_box)
|
||||
return;
|
||||
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
{
|
||||
grub_gfxmenu_box_t box = self->menu_box;
|
||||
int box_left_pad = box->get_left_pad (box);
|
||||
int box_top_pad = box->get_top_pad (box);
|
||||
int box_right_pad = box->get_right_pad (box);
|
||||
int box_bottom_pad = box->get_bottom_pad (box);
|
||||
grub_video_rect_t vpsave2, content_rect;
|
||||
int num_shown_items = get_num_shown_items (self);
|
||||
int drawing_scrollbar = (self->draw_scrollbar
|
||||
&& (num_shown_items < self->view->menu->size)
|
||||
&& check_scrollbar (self));
|
||||
|
||||
content_rect.x = box_left_pad;
|
||||
content_rect.y = box_top_pad;
|
||||
content_rect.width = self->bounds.width - box_left_pad - box_right_pad;
|
||||
content_rect.height = self->bounds.height - box_top_pad - box_bottom_pad;
|
||||
|
||||
box->set_content_size (box, content_rect.width, content_rect.height);
|
||||
|
||||
box->draw (box, 0, 0);
|
||||
|
||||
grub_gui_set_viewport (&content_rect, &vpsave2);
|
||||
draw_menu (self, content_rect.width, drawing_scrollbar, num_shown_items);
|
||||
grub_gui_restore_viewport (&vpsave2);
|
||||
|
||||
if (drawing_scrollbar)
|
||||
draw_scrollbar (self,
|
||||
self->first_shown_index, num_shown_items,
|
||||
0, self->view->menu->size,
|
||||
self->bounds.width - box_right_pad
|
||||
+ self->scrollbar_width,
|
||||
box_top_pad + self->item_padding,
|
||||
self->bounds.height - box_top_pad - box_bottom_pad);
|
||||
}
|
||||
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
list_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
list_get_parent (void *vself)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
list_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
list_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
list_get_minimal_size (void *vself, unsigned *width, unsigned *height)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
|
||||
if (check_boxes (self))
|
||||
{
|
||||
int boxpad = self->item_padding;
|
||||
int item_vspace = self->item_spacing;
|
||||
int item_height = self->item_height;
|
||||
int num_items = 3;
|
||||
|
||||
grub_gfxmenu_box_t box = self->menu_box;
|
||||
int box_left_pad = box->get_left_pad (box);
|
||||
int box_top_pad = box->get_top_pad (box);
|
||||
int box_right_pad = box->get_right_pad (box);
|
||||
int box_bottom_pad = box->get_bottom_pad (box);
|
||||
unsigned width_s;
|
||||
|
||||
*width = grub_font_get_string_width (self->item_font, "Typical OS");
|
||||
width_s = grub_font_get_string_width (self->selected_item_font,
|
||||
"Typical OS");
|
||||
if (*width < width_s)
|
||||
*width = width_s;
|
||||
|
||||
*width += 2 * boxpad + box_left_pad + box_right_pad;
|
||||
|
||||
/* Set the menu box height to fit the items. */
|
||||
*height = (item_height * num_items
|
||||
+ item_vspace * (num_items - 1)
|
||||
+ 2 * boxpad
|
||||
+ box_top_pad + box_bottom_pad);
|
||||
}
|
||||
else
|
||||
{
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
list_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
if (grub_strcmp (name, "item_font") == 0)
|
||||
{
|
||||
self->item_font = grub_font_get (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "selected_item_font") == 0)
|
||||
{
|
||||
if (! value || grub_strcmp (value, "inherit") == 0)
|
||||
self->selected_item_font = 0;
|
||||
else
|
||||
self->selected_item_font = grub_font_get (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "item_color") == 0)
|
||||
{
|
||||
grub_gui_parse_color (value, &self->item_color);
|
||||
}
|
||||
else if (grub_strcmp (name, "selected_item_color") == 0)
|
||||
{
|
||||
if (! value || grub_strcmp (value, "inherit") == 0)
|
||||
{
|
||||
self->selected_item_color_set = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (grub_gui_parse_color (value, &self->selected_item_color)
|
||||
== GRUB_ERR_NONE)
|
||||
self->selected_item_color_set = 1;
|
||||
}
|
||||
}
|
||||
else if (grub_strcmp (name, "icon_width") == 0)
|
||||
{
|
||||
self->icon_width = grub_strtol (value, 0, 10);
|
||||
grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager,
|
||||
self->icon_width,
|
||||
self->icon_height);
|
||||
}
|
||||
else if (grub_strcmp (name, "icon_height") == 0)
|
||||
{
|
||||
self->icon_height = grub_strtol (value, 0, 10);
|
||||
grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager,
|
||||
self->icon_width,
|
||||
self->icon_height);
|
||||
}
|
||||
else if (grub_strcmp (name, "item_height") == 0)
|
||||
{
|
||||
self->item_height = grub_strtol (value, 0, 10);
|
||||
}
|
||||
else if (grub_strcmp (name, "item_padding") == 0)
|
||||
{
|
||||
self->item_padding = grub_strtol (value, 0, 10);
|
||||
}
|
||||
else if (grub_strcmp (name, "item_icon_space") == 0)
|
||||
{
|
||||
self->item_icon_space = grub_strtol (value, 0, 10);
|
||||
}
|
||||
else if (grub_strcmp (name, "item_spacing") == 0)
|
||||
{
|
||||
self->item_spacing = grub_strtol (value, 0, 10);
|
||||
}
|
||||
else if (grub_strcmp (name, "visible") == 0)
|
||||
{
|
||||
self->visible = grub_strcmp (value, "false") != 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "menu_pixmap_style") == 0)
|
||||
{
|
||||
self->need_to_recreate_boxes = 1;
|
||||
grub_free (self->menu_box_pattern);
|
||||
self->menu_box_pattern = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "selected_item_pixmap_style") == 0)
|
||||
{
|
||||
self->need_to_recreate_boxes = 1;
|
||||
grub_free (self->selected_item_box_pattern);
|
||||
self->selected_item_box_pattern = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "scrollbar_frame") == 0)
|
||||
{
|
||||
self->need_to_recreate_scrollbar = 1;
|
||||
grub_free (self->scrollbar_frame_pattern);
|
||||
self->scrollbar_frame_pattern = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "scrollbar_thumb") == 0)
|
||||
{
|
||||
self->need_to_recreate_scrollbar = 1;
|
||||
grub_free (self->scrollbar_thumb_pattern);
|
||||
self->scrollbar_thumb_pattern = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "scrollbar_width") == 0)
|
||||
{
|
||||
self->scrollbar_width = grub_strtol (value, 0, 10);
|
||||
}
|
||||
else if (grub_strcmp (name, "scrollbar") == 0)
|
||||
{
|
||||
self->draw_scrollbar = grub_strcmp (value, "false") != 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "theme_dir") == 0)
|
||||
{
|
||||
self->need_to_recreate_boxes = 1;
|
||||
grub_free (self->theme_dir);
|
||||
self->theme_dir = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
self->id = grub_strdup (value);
|
||||
else
|
||||
self->id = 0;
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Set necessary information that the gfxmenu view provides. */
|
||||
static void
|
||||
list_set_view_info (void *vself,
|
||||
grub_gfxmenu_view_t view)
|
||||
{
|
||||
list_impl_t self = vself;
|
||||
grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager,
|
||||
view->theme_path);
|
||||
self->view = view;
|
||||
}
|
||||
|
||||
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 =
|
||||
{
|
||||
.set_view_info = list_set_view_info
|
||||
};
|
||||
|
||||
grub_gui_component_t
|
||||
grub_gui_list_new (void)
|
||||
{
|
||||
list_impl_t self;
|
||||
grub_font_t default_font;
|
||||
grub_gui_color_t default_fg_color;
|
||||
grub_gui_color_t default_bg_color;
|
||||
|
||||
self = grub_zalloc (sizeof (*self));
|
||||
if (! self)
|
||||
return 0;
|
||||
|
||||
self->list.ops = &list_ops;
|
||||
self->list.component.ops = &list_comp_ops;
|
||||
|
||||
self->visible = 1;
|
||||
|
||||
default_font = grub_font_get ("Unknown Regular 16");
|
||||
default_fg_color = grub_gui_color_rgb (0, 0, 0);
|
||||
default_bg_color = grub_gui_color_rgb (255, 255, 255);
|
||||
|
||||
self->icon_width = 32;
|
||||
self->icon_height = 32;
|
||||
self->item_height = 42;
|
||||
self->item_padding = 14;
|
||||
self->item_icon_space = 4;
|
||||
self->item_spacing = 16;
|
||||
self->item_font = default_font;
|
||||
self->selected_item_font = 0; /* Default to using the item_font. */
|
||||
self->item_color = default_fg_color;
|
||||
self->selected_item_color_set = 0; /* Default to using the item_color. */
|
||||
self->selected_item_color = default_fg_color;
|
||||
|
||||
self->draw_scrollbar = 1;
|
||||
self->need_to_recreate_scrollbar = 1;
|
||||
self->scrollbar_frame = 0;
|
||||
self->scrollbar_thumb = 0;
|
||||
self->scrollbar_frame_pattern = 0;
|
||||
self->scrollbar_thumb_pattern = 0;
|
||||
self->scrollbar_width = 16;
|
||||
|
||||
self->first_shown_index = 0;
|
||||
|
||||
self->need_to_recreate_boxes = 0;
|
||||
self->theme_dir = 0;
|
||||
self->menu_box_pattern = 0;
|
||||
self->selected_item_box_pattern = 0;
|
||||
self->menu_box = grub_gfxmenu_create_box (0, 0);
|
||||
self->selected_item_box = grub_gfxmenu_create_box (0, 0);
|
||||
|
||||
self->icon_manager = grub_gfxmenu_icon_manager_new ();
|
||||
if (! self->icon_manager)
|
||||
{
|
||||
self->list.component.ops->destroy (self);
|
||||
return 0;
|
||||
}
|
||||
grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager,
|
||||
self->icon_width,
|
||||
self->icon_height);
|
||||
return (grub_gui_component_t) self;
|
||||
}
|
384
grub-core/gfxmenu/gui_progress_bar.c
Normal file
384
grub-core/gfxmenu/gui_progress_bar.c
Normal file
|
@ -0,0 +1,384 @@
|
|||
/* gui_progress_bar.c - GUI progress bar component. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/font.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
struct grub_gui_progress_bar
|
||||
{
|
||||
struct grub_gui_progress progress;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
int visible;
|
||||
int start;
|
||||
int end;
|
||||
int value;
|
||||
int show_text;
|
||||
char *template;
|
||||
grub_font_t font;
|
||||
grub_gui_color_t text_color;
|
||||
grub_gui_color_t border_color;
|
||||
grub_gui_color_t bg_color;
|
||||
grub_gui_color_t fg_color;
|
||||
|
||||
char *theme_dir;
|
||||
int need_to_recreate_pixmaps;
|
||||
int pixmapbar_available;
|
||||
char *bar_pattern;
|
||||
char *highlight_pattern;
|
||||
grub_gfxmenu_box_t bar_box;
|
||||
grub_gfxmenu_box_t highlight_box;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_progress_bar *grub_gui_progress_bar_t;
|
||||
|
||||
static void
|
||||
progress_bar_destroy (void *vself)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static const char *
|
||||
progress_bar_get_id (void *vself)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
progress_bar_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return grub_strcmp (type, "component") == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
check_pixmaps (grub_gui_progress_bar_t self)
|
||||
{
|
||||
if (!self->pixmapbar_available)
|
||||
return 0;
|
||||
if (self->need_to_recreate_pixmaps)
|
||||
{
|
||||
grub_gui_recreate_box (&self->bar_box,
|
||||
self->bar_pattern,
|
||||
self->theme_dir);
|
||||
|
||||
grub_gui_recreate_box (&self->highlight_box,
|
||||
self->highlight_pattern,
|
||||
self->theme_dir);
|
||||
|
||||
self->need_to_recreate_pixmaps = 0;
|
||||
}
|
||||
|
||||
return (self->bar_box != 0 && self->highlight_box != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_filled_rect_bar (grub_gui_progress_bar_t self)
|
||||
{
|
||||
/* Set the progress bar's frame. */
|
||||
grub_video_rect_t f;
|
||||
f.x = 1;
|
||||
f.y = 1;
|
||||
f.width = self->bounds.width - 2;
|
||||
f.height = self->bounds.height - 2;
|
||||
|
||||
/* Border. */
|
||||
grub_video_fill_rect (grub_gui_map_color (self->border_color),
|
||||
f.x - 1, f.y - 1,
|
||||
f.width + 2, f.height + 2);
|
||||
|
||||
/* Bar background. */
|
||||
int barwidth = (f.width
|
||||
* (self->value - self->start)
|
||||
/ (self->end - self->start));
|
||||
grub_video_fill_rect (grub_gui_map_color (self->bg_color),
|
||||
f.x + barwidth, f.y,
|
||||
f.width - barwidth, f.height);
|
||||
|
||||
/* Bar foreground. */
|
||||
grub_video_fill_rect (grub_gui_map_color (self->fg_color),
|
||||
f.x, f.y,
|
||||
barwidth, f.height);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_pixmap_bar (grub_gui_progress_bar_t self)
|
||||
{
|
||||
grub_gfxmenu_box_t bar = self->bar_box;
|
||||
grub_gfxmenu_box_t hl = self->highlight_box;
|
||||
int w = self->bounds.width;
|
||||
int h = self->bounds.height;
|
||||
int bar_l_pad = bar->get_left_pad (bar);
|
||||
int bar_r_pad = bar->get_right_pad (bar);
|
||||
int bar_t_pad = bar->get_top_pad (bar);
|
||||
int bar_b_pad = bar->get_bottom_pad (bar);
|
||||
int bar_h_pad = bar_l_pad + bar_r_pad;
|
||||
int bar_v_pad = bar_t_pad + bar_b_pad;
|
||||
int tracklen = w - bar_h_pad;
|
||||
int trackheight = h - bar_v_pad;
|
||||
int barwidth;
|
||||
|
||||
bar->set_content_size (bar, tracklen, trackheight);
|
||||
|
||||
barwidth = (tracklen * (self->value - self->start)
|
||||
/ (self->end - self->start));
|
||||
|
||||
hl->set_content_size (hl, barwidth, h - bar_v_pad);
|
||||
|
||||
bar->draw (bar, 0, 0);
|
||||
hl->draw (hl, bar_l_pad, bar_t_pad);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_text (grub_gui_progress_bar_t self)
|
||||
{
|
||||
if (self->template)
|
||||
{
|
||||
grub_font_t font = self->font;
|
||||
grub_video_color_t text_color = grub_gui_map_color (self->text_color);
|
||||
int width = self->bounds.width;
|
||||
int height = self->bounds.height;
|
||||
char *text;
|
||||
text = grub_xasprintf (self->template,
|
||||
self->value > 0 ? self->value : -self->value);
|
||||
if (!text)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
/* Center the text. */
|
||||
int text_width = grub_font_get_string_width (font, text);
|
||||
int x = (width - text_width) / 2;
|
||||
int y = ((height - grub_font_get_descent (font)) / 2
|
||||
+ grub_font_get_ascent (font) / 2);
|
||||
grub_font_draw_string (text, font, text_color, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
progress_bar_paint (void *vself, const grub_video_rect_t *region)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
grub_video_rect_t vpsave;
|
||||
|
||||
if (! self->visible)
|
||||
return;
|
||||
if (!grub_video_have_common_points (region, &self->bounds))
|
||||
return;
|
||||
|
||||
if (self->end == self->start)
|
||||
return;
|
||||
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
|
||||
if (check_pixmaps (self))
|
||||
draw_pixmap_bar (self);
|
||||
else
|
||||
draw_filled_rect_bar (self);
|
||||
|
||||
draw_text (self);
|
||||
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
progress_bar_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
progress_bar_get_parent (void *vself)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
progress_bar_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
progress_bar_get_minimal_size (void *vself,
|
||||
unsigned *width, unsigned *height)
|
||||
{
|
||||
unsigned text_width = 0, text_height = 0;
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
|
||||
if (self->template)
|
||||
{
|
||||
text_width = grub_font_get_string_width (self->font, self->template);
|
||||
text_width += grub_font_get_string_width (self->font, "XXXXXXXXXX");
|
||||
text_height = grub_font_get_descent (self->font)
|
||||
+ grub_font_get_ascent (self->font);
|
||||
}
|
||||
*width = 200;
|
||||
if (*width < text_width)
|
||||
*width = text_width;
|
||||
*height = 28;
|
||||
if (*height < text_height)
|
||||
*height = text_height;
|
||||
}
|
||||
|
||||
static void
|
||||
progress_bar_set_state (void *vself, int visible, int start,
|
||||
int current, int end)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
self->visible = visible;
|
||||
self->start = start;
|
||||
self->value = current;
|
||||
self->end = end;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
progress_bar_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
grub_gui_progress_bar_t self = vself;
|
||||
if (grub_strcmp (name, "text") == 0)
|
||||
{
|
||||
grub_free (self->template);
|
||||
if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_LONG@") == 0)
|
||||
value
|
||||
= _("The highlighted entry will be executed automatically in %ds.");
|
||||
else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_MIDDLE@") == 0)
|
||||
/* TRANSLATORS: 's' stands for seconds.
|
||||
It's a standalone timeout notification.
|
||||
Please use the short form in your language. */
|
||||
value = _("%ds remaining.");
|
||||
else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_SHORT@") == 0)
|
||||
/* TRANSLATORS: 's' stands for seconds.
|
||||
It's a standalone timeout notification.
|
||||
Please use the shortest form available in you language. */
|
||||
value = _("%ds");
|
||||
|
||||
self->template = grub_strdup (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "font") == 0)
|
||||
{
|
||||
self->font = grub_font_get (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "text_color") == 0)
|
||||
{
|
||||
grub_gui_parse_color (value, &self->text_color);
|
||||
}
|
||||
else if (grub_strcmp (name, "border_color") == 0)
|
||||
{
|
||||
grub_gui_parse_color (value, &self->border_color);
|
||||
}
|
||||
else if (grub_strcmp (name, "bg_color") == 0)
|
||||
{
|
||||
grub_gui_parse_color (value, &self->bg_color);
|
||||
}
|
||||
else if (grub_strcmp (name, "fg_color") == 0)
|
||||
{
|
||||
grub_gui_parse_color (value, &self->fg_color);
|
||||
}
|
||||
else if (grub_strcmp (name, "bar_style") == 0)
|
||||
{
|
||||
self->need_to_recreate_pixmaps = 1;
|
||||
self->pixmapbar_available = 1;
|
||||
grub_free (self->bar_pattern);
|
||||
self->bar_pattern = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "highlight_style") == 0)
|
||||
{
|
||||
self->need_to_recreate_pixmaps = 1;
|
||||
self->pixmapbar_available = 1;
|
||||
grub_free (self->highlight_pattern);
|
||||
self->highlight_pattern = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "theme_dir") == 0)
|
||||
{
|
||||
self->need_to_recreate_pixmaps = 1;
|
||||
grub_free (self->theme_dir);
|
||||
self->theme_dir = value ? grub_strdup (value) : 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
self->id = grub_strdup (value);
|
||||
else
|
||||
self->id = 0;
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static struct grub_gui_component_ops progress_bar_ops =
|
||||
{
|
||||
.destroy = progress_bar_destroy,
|
||||
.get_id = progress_bar_get_id,
|
||||
.is_instance = progress_bar_is_instance,
|
||||
.paint = progress_bar_paint,
|
||||
.set_parent = progress_bar_set_parent,
|
||||
.get_parent = progress_bar_get_parent,
|
||||
.set_bounds = progress_bar_set_bounds,
|
||||
.get_bounds = progress_bar_get_bounds,
|
||||
.get_minimal_size = progress_bar_get_minimal_size,
|
||||
.set_property = progress_bar_set_property
|
||||
};
|
||||
|
||||
static struct grub_gui_progress_ops progress_bar_pb_ops =
|
||||
{
|
||||
.set_state = progress_bar_set_state
|
||||
};
|
||||
|
||||
grub_gui_component_t
|
||||
grub_gui_progress_bar_new (void)
|
||||
{
|
||||
grub_gui_progress_bar_t self;
|
||||
self = grub_zalloc (sizeof (*self));
|
||||
if (! self)
|
||||
return 0;
|
||||
self->progress.ops = &progress_bar_pb_ops;
|
||||
self->progress.component.ops = &progress_bar_ops;
|
||||
self->visible = 1;
|
||||
self->font = grub_font_get ("Unknown Regular 16");
|
||||
grub_gui_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 };
|
||||
grub_gui_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 };
|
||||
grub_gui_color_t lightgray = { .red = 200, .green = 200, .blue = 200, .alpha = 255 };
|
||||
self->text_color = black;
|
||||
self->border_color = black;
|
||||
self->bg_color = gray;
|
||||
self->fg_color = lightgray;
|
||||
|
||||
return (grub_gui_component_t) self;
|
||||
}
|
327
grub-core/gfxmenu/gui_string_util.c
Normal file
327
grub-core/gfxmenu/gui_string_util.c
Normal file
|
@ -0,0 +1,327 @@
|
|||
/* gui_string_util.c - String utilities used by the GUI system. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
/* Create a new NUL-terminated string on the heap as a substring of BUF.
|
||||
The range of buf included is the half-open interval [START,END).
|
||||
The index START is inclusive, END is exclusive. */
|
||||
char *
|
||||
grub_new_substring (const char *buf,
|
||||
grub_size_t start, grub_size_t end)
|
||||
{
|
||||
if (end < start)
|
||||
return 0;
|
||||
grub_size_t len = end - start;
|
||||
char *s = grub_malloc (len + 1);
|
||||
if (! s)
|
||||
return 0;
|
||||
grub_memcpy (s, buf + start, len);
|
||||
s[len] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Eliminate "." and ".." path elements from PATH. A new heap-allocated
|
||||
string is returned. */
|
||||
static char *
|
||||
canonicalize_path (const char *path)
|
||||
{
|
||||
int i;
|
||||
const char *p;
|
||||
char *newpath = 0;
|
||||
|
||||
/* Count the path components in path. */
|
||||
int components = 1;
|
||||
for (p = path; *p; p++)
|
||||
if (*p == '/')
|
||||
components++;
|
||||
|
||||
char **path_array = grub_malloc (components * sizeof (*path_array));
|
||||
if (! path_array)
|
||||
return 0;
|
||||
|
||||
/* Initialize array elements to NULL pointers; in case once of the
|
||||
allocations fails, the cleanup code can just call grub_free() for all
|
||||
pointers in the array. */
|
||||
for (i = 0; i < components; i++)
|
||||
path_array[i] = 0;
|
||||
|
||||
/* Parse the path into path_array. */
|
||||
p = path;
|
||||
for (i = 0; i < components && p; i++)
|
||||
{
|
||||
/* Find the end of the path element. */
|
||||
const char *end = grub_strchr (p, '/');
|
||||
if (!end)
|
||||
end = p + grub_strlen (p);
|
||||
|
||||
/* Copy the element. */
|
||||
path_array[i] = grub_new_substring (p, 0, end - p);
|
||||
if (! path_array[i])
|
||||
goto cleanup;
|
||||
|
||||
/* Advance p to point to the start of the next element, or NULL. */
|
||||
if (*end)
|
||||
p = end + 1;
|
||||
else
|
||||
p = 0;
|
||||
}
|
||||
|
||||
/* Eliminate '.' and '..' elements from the path array. */
|
||||
int newpath_length = 0;
|
||||
for (i = components - 1; i >= 0; --i)
|
||||
{
|
||||
if (! grub_strcmp (path_array[i], "."))
|
||||
{
|
||||
grub_free (path_array[i]);
|
||||
path_array[i] = 0;
|
||||
}
|
||||
else if (! grub_strcmp (path_array[i], "..")
|
||||
&& i > 0)
|
||||
{
|
||||
/* Delete the '..' and the prior path element. */
|
||||
grub_free (path_array[i]);
|
||||
path_array[i] = 0;
|
||||
--i;
|
||||
grub_free (path_array[i]);
|
||||
path_array[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
newpath_length += grub_strlen (path_array[i]) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct a new path string. */
|
||||
newpath = grub_malloc (newpath_length + 1);
|
||||
if (! newpath)
|
||||
goto cleanup;
|
||||
|
||||
newpath[0] = '\0';
|
||||
char *newpath_end = newpath;
|
||||
int first = 1;
|
||||
for (i = 0; i < components; i++)
|
||||
{
|
||||
char *element = path_array[i];
|
||||
if (element)
|
||||
{
|
||||
/* For all components but the first, prefix with a slash. */
|
||||
if (! first)
|
||||
newpath_end = grub_stpcpy (newpath_end, "/");
|
||||
newpath_end = grub_stpcpy (newpath_end, element);
|
||||
first = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < components; i++)
|
||||
grub_free (path_array[i]);
|
||||
grub_free (path_array);
|
||||
|
||||
return newpath;
|
||||
}
|
||||
|
||||
/* Return a new heap-allocated string representing to absolute path
|
||||
to the file referred to by PATH. If PATH is an absolute path, then
|
||||
the returned path is a copy of PATH. If PATH is a relative path, then
|
||||
BASE is with PATH used to construct the absolute path. */
|
||||
char *
|
||||
grub_resolve_relative_path (const char *base, const char *path)
|
||||
{
|
||||
char *abspath;
|
||||
char *canonpath;
|
||||
char *p;
|
||||
grub_size_t l;
|
||||
|
||||
/* If PATH is an absolute path, then just use it as is. */
|
||||
if (path[0] == '/' || path[0] == '(')
|
||||
return canonicalize_path (path);
|
||||
|
||||
abspath = grub_malloc (grub_strlen (base) + grub_strlen (path) + 3);
|
||||
if (! abspath)
|
||||
return 0;
|
||||
|
||||
/* Concatenate BASE and PATH. */
|
||||
p = grub_stpcpy (abspath, base);
|
||||
l = grub_strlen (abspath);
|
||||
if (l == 0 || abspath[l-1] != '/')
|
||||
{
|
||||
*p = '/';
|
||||
p++;
|
||||
*p = 0;
|
||||
}
|
||||
grub_stpcpy (p, path);
|
||||
|
||||
canonpath = canonicalize_path (abspath);
|
||||
if (! canonpath)
|
||||
return abspath;
|
||||
|
||||
grub_free (abspath);
|
||||
return canonpath;
|
||||
}
|
||||
|
||||
/* Get the path of the directory where the file at FILE_PATH is located.
|
||||
FILE_PATH should refer to a file, not a directory. The returned path
|
||||
includes a trailing slash.
|
||||
This does not handle GRUB "(hd0,0)" paths properly yet since it only
|
||||
looks at slashes. */
|
||||
char *
|
||||
grub_get_dirname (const char *file_path)
|
||||
{
|
||||
int i;
|
||||
int last_slash;
|
||||
|
||||
last_slash = -1;
|
||||
for (i = grub_strlen (file_path) - 1; i >= 0; --i)
|
||||
{
|
||||
if (file_path[i] == '/')
|
||||
{
|
||||
last_slash = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (last_slash == -1)
|
||||
return grub_strdup ("/");
|
||||
|
||||
return grub_new_substring (file_path, 0, last_slash + 1);
|
||||
}
|
||||
|
||||
static __inline int
|
||||
my_isxdigit (char c)
|
||||
{
|
||||
return ((c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'f')
|
||||
|| (c >= 'A' && c <= 'F'));
|
||||
}
|
||||
|
||||
static int
|
||||
parse_hex_color_component (const char *s, unsigned start, unsigned end)
|
||||
{
|
||||
unsigned len;
|
||||
char buf[3];
|
||||
|
||||
len = end - start;
|
||||
/* Check the limits so we don't overrun the buffer. */
|
||||
if (len < 1 || len > 2)
|
||||
return 0;
|
||||
|
||||
if (len == 1)
|
||||
{
|
||||
buf[0] = s[start]; /* Get the first and only hex digit. */
|
||||
buf[1] = buf[0]; /* Duplicate the hex digit. */
|
||||
}
|
||||
else if (len == 2)
|
||||
{
|
||||
buf[0] = s[start];
|
||||
buf[1] = s[start + 1];
|
||||
}
|
||||
|
||||
buf[2] = '\0';
|
||||
|
||||
return grub_strtoul (buf, 0, 16);
|
||||
}
|
||||
|
||||
/* Parse a color string of the form "r, g, b", "#RGB", "#RGBA",
|
||||
"#RRGGBB", or "#RRGGBBAA". */
|
||||
grub_err_t
|
||||
grub_gui_parse_color (const char *s, grub_gui_color_t *color)
|
||||
{
|
||||
grub_gui_color_t c;
|
||||
|
||||
/* Skip whitespace. */
|
||||
while (*s && grub_isspace (*s))
|
||||
s++;
|
||||
|
||||
if (*s == '#')
|
||||
{
|
||||
/* HTML-style. Number if hex digits:
|
||||
[6] #RRGGBB [3] #RGB
|
||||
[8] #RRGGBBAA [4] #RGBA */
|
||||
|
||||
s++; /* Skip the '#'. */
|
||||
/* Count the hexits to determine the format. */
|
||||
int hexits = 0;
|
||||
const char *end = s;
|
||||
while (my_isxdigit (*end))
|
||||
{
|
||||
end++;
|
||||
hexits++;
|
||||
}
|
||||
|
||||
/* Parse the color components based on the format. */
|
||||
if (hexits == 3 || hexits == 4)
|
||||
{
|
||||
c.red = parse_hex_color_component (s, 0, 1);
|
||||
c.green = parse_hex_color_component (s, 1, 2);
|
||||
c.blue = parse_hex_color_component (s, 2, 3);
|
||||
if (hexits == 4)
|
||||
c.alpha = parse_hex_color_component (s, 3, 4);
|
||||
else
|
||||
c.alpha = 255;
|
||||
}
|
||||
else if (hexits == 6 || hexits == 8)
|
||||
{
|
||||
c.red = parse_hex_color_component (s, 0, 2);
|
||||
c.green = parse_hex_color_component (s, 2, 4);
|
||||
c.blue = parse_hex_color_component (s, 4, 6);
|
||||
if (hexits == 8)
|
||||
c.alpha = parse_hex_color_component (s, 6, 8);
|
||||
else
|
||||
c.alpha = 255;
|
||||
}
|
||||
else
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"invalid HTML-type color string `%s'", s);
|
||||
}
|
||||
else if (grub_isdigit (*s))
|
||||
{
|
||||
/* Comma separated decimal values. */
|
||||
c.red = grub_strtoul (s, 0, 0);
|
||||
if ((s = grub_strchr (s, ',')) == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"missing 1st comma separator in color `%s'", s);
|
||||
s++;
|
||||
c.green = grub_strtoul (s, 0, 0);
|
||||
if ((s = grub_strchr (s, ',')) == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"missing 2nd comma separator in color `%s'", s);
|
||||
s++;
|
||||
c.blue = grub_strtoul (s, 0, 0);
|
||||
if ((s = grub_strchr (s, ',')) == 0)
|
||||
c.alpha = 255;
|
||||
else
|
||||
{
|
||||
s++;
|
||||
c.alpha = grub_strtoul (s, 0, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! grub_gui_get_named_color (s, &c))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"invalid named color `%s'", s);
|
||||
}
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
*color = c;
|
||||
return grub_errno;
|
||||
}
|
101
grub-core/gfxmenu/gui_util.c
Normal file
101
grub-core/gfxmenu/gui_util.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* gui_util.c - GUI utility functions. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
|
||||
|
||||
struct find_by_id_state
|
||||
{
|
||||
const char *match_id;
|
||||
grub_gui_component_callback match_callback;
|
||||
void *match_userdata;
|
||||
};
|
||||
|
||||
static void
|
||||
find_by_id_recursively (grub_gui_component_t component, void *userdata)
|
||||
{
|
||||
struct find_by_id_state *state;
|
||||
const char *id;
|
||||
|
||||
state = (struct find_by_id_state *) userdata;
|
||||
id = component->ops->get_id (component);
|
||||
if (id && grub_strcmp (id, state->match_id) == 0)
|
||||
state->match_callback (component, state->match_userdata);
|
||||
|
||||
if (component->ops->is_instance (component, "container"))
|
||||
{
|
||||
grub_gui_container_t container;
|
||||
container = (grub_gui_container_t) component;
|
||||
container->ops->iterate_children (container,
|
||||
find_by_id_recursively,
|
||||
state);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_gui_find_by_id (grub_gui_component_t root,
|
||||
const char *id,
|
||||
grub_gui_component_callback cb,
|
||||
void *userdata)
|
||||
{
|
||||
struct find_by_id_state state;
|
||||
state.match_id = id;
|
||||
state.match_callback = cb;
|
||||
state.match_userdata = userdata;
|
||||
find_by_id_recursively (root, &state);
|
||||
}
|
||||
|
||||
|
||||
struct iterate_recursively_state
|
||||
{
|
||||
grub_gui_component_callback callback;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
static
|
||||
void iterate_recursively_cb (grub_gui_component_t component, void *userdata)
|
||||
{
|
||||
struct iterate_recursively_state *state;
|
||||
|
||||
state = (struct iterate_recursively_state *) userdata;
|
||||
state->callback (component, state->userdata);
|
||||
|
||||
if (component->ops->is_instance (component, "container"))
|
||||
{
|
||||
grub_gui_container_t container;
|
||||
container = (grub_gui_container_t) component;
|
||||
container->ops->iterate_children (container,
|
||||
iterate_recursively_cb,
|
||||
state);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_gui_iterate_recursively (grub_gui_component_t root,
|
||||
grub_gui_component_callback cb,
|
||||
void *userdata)
|
||||
{
|
||||
struct iterate_recursively_state state;
|
||||
state.callback = cb;
|
||||
state.userdata = userdata;
|
||||
iterate_recursively_cb (root, &state);
|
||||
}
|
263
grub-core/gfxmenu/icon_manager.c
Normal file
263
grub-core/gfxmenu/icon_manager.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
/* icon_manager.c - gfxmenu icon manager. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/menu.h>
|
||||
#include <grub/icon_manager.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
/* Currently hard coded to '.png' extension. */
|
||||
static const char icon_extension[] = ".png";
|
||||
|
||||
typedef struct icon_entry
|
||||
{
|
||||
char *class_name;
|
||||
struct grub_video_bitmap *bitmap;
|
||||
struct icon_entry *next;
|
||||
} *icon_entry_t;
|
||||
|
||||
struct grub_gfxmenu_icon_manager
|
||||
{
|
||||
char *theme_path;
|
||||
int icon_width;
|
||||
int icon_height;
|
||||
|
||||
/* Icon cache: linked list w/ dummy head node. */
|
||||
struct icon_entry cache;
|
||||
};
|
||||
|
||||
|
||||
/* Create a new icon manager and return a point to it. */
|
||||
grub_gfxmenu_icon_manager_t
|
||||
grub_gfxmenu_icon_manager_new (void)
|
||||
{
|
||||
grub_gfxmenu_icon_manager_t mgr;
|
||||
mgr = grub_malloc (sizeof (*mgr));
|
||||
if (! mgr)
|
||||
return 0;
|
||||
|
||||
mgr->theme_path = 0;
|
||||
mgr->icon_width = 0;
|
||||
mgr->icon_height = 0;
|
||||
|
||||
/* Initialize the dummy head node. */
|
||||
mgr->cache.class_name = 0;
|
||||
mgr->cache.bitmap = 0;
|
||||
mgr->cache.next = 0;
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
/* Destroy the icon manager MGR, freeing all resources used by it.
|
||||
|
||||
Note: Any bitmaps returned by grub_gfxmenu_icon_manager_get_icon()
|
||||
are destroyed and must not be used by the caller after this function
|
||||
is called. */
|
||||
void
|
||||
grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr)
|
||||
{
|
||||
grub_gfxmenu_icon_manager_clear_cache (mgr);
|
||||
grub_free (mgr->theme_path);
|
||||
grub_free (mgr);
|
||||
}
|
||||
|
||||
/* Clear the icon cache. */
|
||||
void
|
||||
grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr)
|
||||
{
|
||||
icon_entry_t cur;
|
||||
icon_entry_t next;
|
||||
for (cur = mgr->cache.next; cur; cur = next)
|
||||
{
|
||||
next = cur->next;
|
||||
grub_free (cur->class_name);
|
||||
grub_video_bitmap_destroy (cur->bitmap);
|
||||
grub_free (cur);
|
||||
}
|
||||
mgr->cache.next = 0;
|
||||
}
|
||||
|
||||
/* Set the theme path. If the theme path is changed, the icon cache
|
||||
is cleared. */
|
||||
void
|
||||
grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr,
|
||||
const char *path)
|
||||
{
|
||||
/* Clear the cache if the theme path has changed. */
|
||||
if (((mgr->theme_path == 0) != (path == 0))
|
||||
|| (grub_strcmp (mgr->theme_path, path) != 0))
|
||||
grub_gfxmenu_icon_manager_clear_cache (mgr);
|
||||
|
||||
grub_free (mgr->theme_path);
|
||||
mgr->theme_path = path ? grub_strdup (path) : 0;
|
||||
}
|
||||
|
||||
/* Set the icon size. When icons are requested from the icon manager,
|
||||
they are scaled to this size before being returned. If the size is
|
||||
changed, the icon cache is cleared. */
|
||||
void
|
||||
grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr,
|
||||
int width, int height)
|
||||
{
|
||||
/* If the width or height is changed, we must clear the cache, since the
|
||||
scaled bitmaps are stored in the cache. */
|
||||
if (width != mgr->icon_width || height != mgr->icon_height)
|
||||
grub_gfxmenu_icon_manager_clear_cache (mgr);
|
||||
|
||||
mgr->icon_width = width;
|
||||
mgr->icon_height = height;
|
||||
}
|
||||
|
||||
/* Try to load an icon for the specified CLASS_NAME in the directory DIR.
|
||||
Returns 0 if the icon could not be loaded, or returns a pointer to a new
|
||||
bitmap if it was successful. */
|
||||
static struct grub_video_bitmap *
|
||||
try_loading_icon (grub_gfxmenu_icon_manager_t mgr,
|
||||
const char *dir, const char *class_name)
|
||||
{
|
||||
char *path;
|
||||
int l;
|
||||
|
||||
path = grub_malloc (grub_strlen (dir) + grub_strlen (class_name)
|
||||
+ grub_strlen (icon_extension) + 3);
|
||||
if (! path)
|
||||
return 0;
|
||||
|
||||
grub_strcpy (path, dir);
|
||||
l = grub_strlen (path);
|
||||
if (path[l-1] != '/')
|
||||
{
|
||||
path[l] = '/';
|
||||
path[l+1] = 0;
|
||||
}
|
||||
grub_strcat (path, class_name);
|
||||
grub_strcat (path, icon_extension);
|
||||
|
||||
struct grub_video_bitmap *raw_bitmap;
|
||||
grub_video_bitmap_load (&raw_bitmap, path);
|
||||
grub_free (path);
|
||||
grub_errno = GRUB_ERR_NONE; /* Critical to clear the error!! */
|
||||
if (! raw_bitmap)
|
||||
return 0;
|
||||
|
||||
struct grub_video_bitmap *scaled_bitmap;
|
||||
grub_video_bitmap_create_scaled (&scaled_bitmap,
|
||||
mgr->icon_width, mgr->icon_height,
|
||||
raw_bitmap,
|
||||
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
|
||||
grub_video_bitmap_destroy (raw_bitmap);
|
||||
if (! scaled_bitmap)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_error (grub_errno, "failed to scale icon");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return scaled_bitmap;
|
||||
}
|
||||
|
||||
/* Get the icon for the specified class CLASS_NAME. If an icon for
|
||||
CLASS_NAME already exists in the cache, then a reference to the cached
|
||||
bitmap is returned. If it is not cached, then it is loaded and cached.
|
||||
If no icon could be could for CLASS_NAME, then 0 is returned. */
|
||||
static struct grub_video_bitmap *
|
||||
get_icon_by_class (grub_gfxmenu_icon_manager_t mgr, const char *class_name)
|
||||
{
|
||||
/* First check the icon cache. */
|
||||
icon_entry_t entry;
|
||||
for (entry = mgr->cache.next; entry; entry = entry->next)
|
||||
{
|
||||
if (grub_strcmp (entry->class_name, class_name) == 0)
|
||||
return entry->bitmap;
|
||||
}
|
||||
|
||||
if (! mgr->theme_path)
|
||||
return 0;
|
||||
|
||||
/* Otherwise, we search for an icon to load. */
|
||||
char *theme_dir = grub_get_dirname (mgr->theme_path);
|
||||
char *icons_dir;
|
||||
struct grub_video_bitmap *icon;
|
||||
icon = 0;
|
||||
/* First try the theme's own icons, from "grub/themes/NAME/icons/" */
|
||||
icons_dir = grub_resolve_relative_path (theme_dir, "icons/");
|
||||
if (icons_dir)
|
||||
{
|
||||
icon = try_loading_icon (mgr, icons_dir, class_name);
|
||||
grub_free (icons_dir);
|
||||
}
|
||||
|
||||
grub_free (theme_dir);
|
||||
if (! icon)
|
||||
{
|
||||
const char *icondir;
|
||||
|
||||
icondir = grub_env_get ("icondir");
|
||||
if (icondir)
|
||||
icon = try_loading_icon (mgr, icondir, class_name);
|
||||
}
|
||||
|
||||
/* No icon was found. */
|
||||
/* This should probably be noted in the cache, so that a search is not
|
||||
performed each time an icon for CLASS_NAME is requested. */
|
||||
if (! icon)
|
||||
return 0;
|
||||
|
||||
/* Insert a new cache entry for this icon. */
|
||||
entry = grub_malloc (sizeof (*entry));
|
||||
if (! entry)
|
||||
{
|
||||
grub_video_bitmap_destroy (icon);
|
||||
return 0;
|
||||
}
|
||||
entry->class_name = grub_strdup (class_name);
|
||||
entry->bitmap = icon;
|
||||
entry->next = mgr->cache.next;
|
||||
mgr->cache.next = entry; /* Link it into the cache. */
|
||||
return entry->bitmap;
|
||||
}
|
||||
|
||||
/* Get the best available icon for ENTRY. Beginning with the first class
|
||||
listed in the menu entry and proceeding forward, an icon for each class
|
||||
is searched for. The first icon found is returned. The returned icon
|
||||
is scaled to the size specified by
|
||||
grub_gfxmenu_icon_manager_set_icon_size().
|
||||
|
||||
Note: Bitmaps returned by this function are destroyed when the
|
||||
icon manager is destroyed.
|
||||
*/
|
||||
struct grub_video_bitmap *
|
||||
grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr,
|
||||
grub_menu_entry_t entry)
|
||||
{
|
||||
struct grub_menu_entry_class *c;
|
||||
struct grub_video_bitmap *icon;
|
||||
|
||||
/* Try each class in succession. */
|
||||
icon = 0;
|
||||
for (c = entry->classes->next; c && ! icon; c = c->next)
|
||||
icon = get_icon_by_class (mgr, c->name);
|
||||
return icon;
|
||||
}
|
0
grub-core/gfxmenu/model.c
Normal file
0
grub-core/gfxmenu/model.c
Normal file
209
grub-core/gfxmenu/named_colors.c
Normal file
209
grub-core/gfxmenu/named_colors.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/* named_colors.c - Named color values. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
struct named_color
|
||||
{
|
||||
const char *name;
|
||||
grub_gui_color_t color;
|
||||
};
|
||||
|
||||
/*
|
||||
Named color list generated from the list of SVG color keywords from
|
||||
<http://www.w3.org/TR/css3-color/#svg-color>,
|
||||
processed through the following Perl command:
|
||||
perl -ne 'chomp;split;print "{ \"$_[0]\", RGB_COLOR($_[2]) },\n"'
|
||||
*/
|
||||
|
||||
#define RGB_COLOR(r,g,b) {.red = r, .green = g, .blue = b, .alpha = 255}
|
||||
|
||||
static struct named_color named_colors[] =
|
||||
{
|
||||
{ "aliceblue", RGB_COLOR(240,248,255) },
|
||||
{ "antiquewhite", RGB_COLOR(250,235,215) },
|
||||
{ "aqua", RGB_COLOR(0,255,255) },
|
||||
{ "aquamarine", RGB_COLOR(127,255,212) },
|
||||
{ "azure", RGB_COLOR(240,255,255) },
|
||||
{ "beige", RGB_COLOR(245,245,220) },
|
||||
{ "bisque", RGB_COLOR(255,228,196) },
|
||||
{ "black", RGB_COLOR(0,0,0) },
|
||||
{ "blanchedalmond", RGB_COLOR(255,235,205) },
|
||||
{ "blue", RGB_COLOR(0,0,255) },
|
||||
{ "blueviolet", RGB_COLOR(138,43,226) },
|
||||
{ "brown", RGB_COLOR(165,42,42) },
|
||||
{ "burlywood", RGB_COLOR(222,184,135) },
|
||||
{ "cadetblue", RGB_COLOR(95,158,160) },
|
||||
{ "chartreuse", RGB_COLOR(127,255,0) },
|
||||
{ "chocolate", RGB_COLOR(210,105,30) },
|
||||
{ "coral", RGB_COLOR(255,127,80) },
|
||||
{ "cornflowerblue", RGB_COLOR(100,149,237) },
|
||||
{ "cornsilk", RGB_COLOR(255,248,220) },
|
||||
{ "crimson", RGB_COLOR(220,20,60) },
|
||||
{ "cyan", RGB_COLOR(0,255,255) },
|
||||
{ "darkblue", RGB_COLOR(0,0,139) },
|
||||
{ "darkcyan", RGB_COLOR(0,139,139) },
|
||||
{ "darkgoldenrod", RGB_COLOR(184,134,11) },
|
||||
{ "darkgray", RGB_COLOR(169,169,169) },
|
||||
{ "darkgreen", RGB_COLOR(0,100,0) },
|
||||
{ "darkgrey", RGB_COLOR(169,169,169) },
|
||||
{ "darkkhaki", RGB_COLOR(189,183,107) },
|
||||
{ "darkmagenta", RGB_COLOR(139,0,139) },
|
||||
{ "darkolivegreen", RGB_COLOR(85,107,47) },
|
||||
{ "darkorange", RGB_COLOR(255,140,0) },
|
||||
{ "darkorchid", RGB_COLOR(153,50,204) },
|
||||
{ "darkred", RGB_COLOR(139,0,0) },
|
||||
{ "darksalmon", RGB_COLOR(233,150,122) },
|
||||
{ "darkseagreen", RGB_COLOR(143,188,143) },
|
||||
{ "darkslateblue", RGB_COLOR(72,61,139) },
|
||||
{ "darkslategray", RGB_COLOR(47,79,79) },
|
||||
{ "darkslategrey", RGB_COLOR(47,79,79) },
|
||||
{ "darkturquoise", RGB_COLOR(0,206,209) },
|
||||
{ "darkviolet", RGB_COLOR(148,0,211) },
|
||||
{ "deeppink", RGB_COLOR(255,20,147) },
|
||||
{ "deepskyblue", RGB_COLOR(0,191,255) },
|
||||
{ "dimgray", RGB_COLOR(105,105,105) },
|
||||
{ "dimgrey", RGB_COLOR(105,105,105) },
|
||||
{ "dodgerblue", RGB_COLOR(30,144,255) },
|
||||
{ "firebrick", RGB_COLOR(178,34,34) },
|
||||
{ "floralwhite", RGB_COLOR(255,250,240) },
|
||||
{ "forestgreen", RGB_COLOR(34,139,34) },
|
||||
{ "fuchsia", RGB_COLOR(255,0,255) },
|
||||
{ "gainsboro", RGB_COLOR(220,220,220) },
|
||||
{ "ghostwhite", RGB_COLOR(248,248,255) },
|
||||
{ "gold", RGB_COLOR(255,215,0) },
|
||||
{ "goldenrod", RGB_COLOR(218,165,32) },
|
||||
{ "gray", RGB_COLOR(128,128,128) },
|
||||
{ "green", RGB_COLOR(0,128,0) },
|
||||
{ "greenyellow", RGB_COLOR(173,255,47) },
|
||||
{ "grey", RGB_COLOR(128,128,128) },
|
||||
{ "honeydew", RGB_COLOR(240,255,240) },
|
||||
{ "hotpink", RGB_COLOR(255,105,180) },
|
||||
{ "indianred", RGB_COLOR(205,92,92) },
|
||||
{ "indigo", RGB_COLOR(75,0,130) },
|
||||
{ "ivory", RGB_COLOR(255,255,240) },
|
||||
{ "khaki", RGB_COLOR(240,230,140) },
|
||||
{ "lavender", RGB_COLOR(230,230,250) },
|
||||
{ "lavenderblush", RGB_COLOR(255,240,245) },
|
||||
{ "lawngreen", RGB_COLOR(124,252,0) },
|
||||
{ "lemonchiffon", RGB_COLOR(255,250,205) },
|
||||
{ "lightblue", RGB_COLOR(173,216,230) },
|
||||
{ "lightcoral", RGB_COLOR(240,128,128) },
|
||||
{ "lightcyan", RGB_COLOR(224,255,255) },
|
||||
{ "lightgoldenrodyellow", RGB_COLOR(250,250,210) },
|
||||
{ "lightgray", RGB_COLOR(211,211,211) },
|
||||
{ "lightgreen", RGB_COLOR(144,238,144) },
|
||||
{ "lightgrey", RGB_COLOR(211,211,211) },
|
||||
{ "lightpink", RGB_COLOR(255,182,193) },
|
||||
{ "lightsalmon", RGB_COLOR(255,160,122) },
|
||||
{ "lightseagreen", RGB_COLOR(32,178,170) },
|
||||
{ "lightskyblue", RGB_COLOR(135,206,250) },
|
||||
{ "lightslategray", RGB_COLOR(119,136,153) },
|
||||
{ "lightslategrey", RGB_COLOR(119,136,153) },
|
||||
{ "lightsteelblue", RGB_COLOR(176,196,222) },
|
||||
{ "lightyellow", RGB_COLOR(255,255,224) },
|
||||
{ "lime", RGB_COLOR(0,255,0) },
|
||||
{ "limegreen", RGB_COLOR(50,205,50) },
|
||||
{ "linen", RGB_COLOR(250,240,230) },
|
||||
{ "magenta", RGB_COLOR(255,0,255) },
|
||||
{ "maroon", RGB_COLOR(128,0,0) },
|
||||
{ "mediumaquamarine", RGB_COLOR(102,205,170) },
|
||||
{ "mediumblue", RGB_COLOR(0,0,205) },
|
||||
{ "mediumorchid", RGB_COLOR(186,85,211) },
|
||||
{ "mediumpurple", RGB_COLOR(147,112,219) },
|
||||
{ "mediumseagreen", RGB_COLOR(60,179,113) },
|
||||
{ "mediumslateblue", RGB_COLOR(123,104,238) },
|
||||
{ "mediumspringgreen", RGB_COLOR(0,250,154) },
|
||||
{ "mediumturquoise", RGB_COLOR(72,209,204) },
|
||||
{ "mediumvioletred", RGB_COLOR(199,21,133) },
|
||||
{ "midnightblue", RGB_COLOR(25,25,112) },
|
||||
{ "mintcream", RGB_COLOR(245,255,250) },
|
||||
{ "mistyrose", RGB_COLOR(255,228,225) },
|
||||
{ "moccasin", RGB_COLOR(255,228,181) },
|
||||
{ "navajowhite", RGB_COLOR(255,222,173) },
|
||||
{ "navy", RGB_COLOR(0,0,128) },
|
||||
{ "oldlace", RGB_COLOR(253,245,230) },
|
||||
{ "olive", RGB_COLOR(128,128,0) },
|
||||
{ "olivedrab", RGB_COLOR(107,142,35) },
|
||||
{ "orange", RGB_COLOR(255,165,0) },
|
||||
{ "orangered", RGB_COLOR(255,69,0) },
|
||||
{ "orchid", RGB_COLOR(218,112,214) },
|
||||
{ "palegoldenrod", RGB_COLOR(238,232,170) },
|
||||
{ "palegreen", RGB_COLOR(152,251,152) },
|
||||
{ "paleturquoise", RGB_COLOR(175,238,238) },
|
||||
{ "palevioletred", RGB_COLOR(219,112,147) },
|
||||
{ "papayawhip", RGB_COLOR(255,239,213) },
|
||||
{ "peachpuff", RGB_COLOR(255,218,185) },
|
||||
{ "peru", RGB_COLOR(205,133,63) },
|
||||
{ "pink", RGB_COLOR(255,192,203) },
|
||||
{ "plum", RGB_COLOR(221,160,221) },
|
||||
{ "powderblue", RGB_COLOR(176,224,230) },
|
||||
{ "purple", RGB_COLOR(128,0,128) },
|
||||
{ "red", RGB_COLOR(255,0,0) },
|
||||
{ "rosybrown", RGB_COLOR(188,143,143) },
|
||||
{ "royalblue", RGB_COLOR(65,105,225) },
|
||||
{ "saddlebrown", RGB_COLOR(139,69,19) },
|
||||
{ "salmon", RGB_COLOR(250,128,114) },
|
||||
{ "sandybrown", RGB_COLOR(244,164,96) },
|
||||
{ "seagreen", RGB_COLOR(46,139,87) },
|
||||
{ "seashell", RGB_COLOR(255,245,238) },
|
||||
{ "sienna", RGB_COLOR(160,82,45) },
|
||||
{ "silver", RGB_COLOR(192,192,192) },
|
||||
{ "skyblue", RGB_COLOR(135,206,235) },
|
||||
{ "slateblue", RGB_COLOR(106,90,205) },
|
||||
{ "slategray", RGB_COLOR(112,128,144) },
|
||||
{ "slategrey", RGB_COLOR(112,128,144) },
|
||||
{ "snow", RGB_COLOR(255,250,250) },
|
||||
{ "springgreen", RGB_COLOR(0,255,127) },
|
||||
{ "steelblue", RGB_COLOR(70,130,180) },
|
||||
{ "tan", RGB_COLOR(210,180,140) },
|
||||
{ "teal", RGB_COLOR(0,128,128) },
|
||||
{ "thistle", RGB_COLOR(216,191,216) },
|
||||
{ "tomato", RGB_COLOR(255,99,71) },
|
||||
{ "turquoise", RGB_COLOR(64,224,208) },
|
||||
{ "violet", RGB_COLOR(238,130,238) },
|
||||
{ "wheat", RGB_COLOR(245,222,179) },
|
||||
{ "white", RGB_COLOR(255,255,255) },
|
||||
{ "whitesmoke", RGB_COLOR(245,245,245) },
|
||||
{ "yellow", RGB_COLOR(255,255,0) },
|
||||
{ "yellowgreen", RGB_COLOR(154,205,50) },
|
||||
{ 0, { 0, 0, 0, 0 } } /* Terminator. */
|
||||
};
|
||||
|
||||
/* Get the color named NAME. If the color was found, returns 1 and
|
||||
stores the color into *COLOR. If the color was not found, returns 0 and
|
||||
does not modify *COLOR. */
|
||||
int
|
||||
grub_gui_get_named_color (const char *name,
|
||||
grub_gui_color_t *color)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; named_colors[i].name; i++)
|
||||
{
|
||||
if (grub_strcmp (named_colors[i].name, name) == 0)
|
||||
{
|
||||
*color = named_colors[i].color;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
723
grub-core/gfxmenu/theme_loader.c
Normal file
723
grub-core/gfxmenu/theme_loader.c
Normal file
|
@ -0,0 +1,723 @@
|
|||
/* theme_loader.c - Theme file loader for gfxmenu. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/gui.h>
|
||||
|
||||
/* Construct a new box widget using ABSPATTERN to find the pixmap files for
|
||||
it, storing the new box instance at *BOXPTR.
|
||||
PATTERN should be of the form: "(hd0,0)/somewhere/style*.png".
|
||||
The '*' then gets substituted with the various pixmap names that the
|
||||
box uses. */
|
||||
static grub_err_t
|
||||
recreate_box_absolute (grub_gfxmenu_box_t *boxptr, const char *abspattern)
|
||||
{
|
||||
char *prefix;
|
||||
char *suffix;
|
||||
char *star;
|
||||
grub_gfxmenu_box_t box;
|
||||
|
||||
star = grub_strchr (abspattern, '*');
|
||||
if (! star)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"missing `*' in box pixmap pattern `%s'", abspattern);
|
||||
|
||||
/* Prefix: Get the part before the '*'. */
|
||||
prefix = grub_malloc (star - abspattern + 1);
|
||||
if (! prefix)
|
||||
return grub_errno;
|
||||
|
||||
grub_memcpy (prefix, abspattern, star - abspattern);
|
||||
prefix[star - abspattern] = '\0';
|
||||
|
||||
/* Suffix: Everything after the '*' is the suffix. */
|
||||
suffix = star + 1;
|
||||
|
||||
box = grub_gfxmenu_create_box (prefix, suffix);
|
||||
grub_free (prefix);
|
||||
if (! box)
|
||||
return grub_errno;
|
||||
|
||||
if (*boxptr)
|
||||
(*boxptr)->destroy (*boxptr);
|
||||
*boxptr = box;
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
||||
/* Construct a new box widget using PATTERN to find the pixmap files for it,
|
||||
storing the new widget at *BOXPTR. PATTERN should be of the form:
|
||||
"somewhere/style*.png". The '*' then gets substituted with the various
|
||||
pixmap names that the widget uses.
|
||||
|
||||
Important! The value of *BOXPTR must be initialized! It must either
|
||||
(1) Be 0 (a NULL pointer), or
|
||||
(2) Be a pointer to a valid 'grub_gfxmenu_box_t' instance.
|
||||
In this case, the previous instance is destroyed. */
|
||||
grub_err_t
|
||||
grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr,
|
||||
const char *pattern, const char *theme_dir)
|
||||
{
|
||||
char *abspattern;
|
||||
|
||||
/* Check arguments. */
|
||||
if (! pattern)
|
||||
{
|
||||
/* If no pixmap pattern is given, then just create an empty box. */
|
||||
if (*boxptr)
|
||||
(*boxptr)->destroy (*boxptr);
|
||||
*boxptr = grub_gfxmenu_create_box (0, 0);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
if (! theme_dir)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"styled box missing theme directory");
|
||||
|
||||
/* Resolve to an absolute path. */
|
||||
abspattern = grub_resolve_relative_path (theme_dir, pattern);
|
||||
if (! abspattern)
|
||||
return grub_errno;
|
||||
|
||||
/* Create the box. */
|
||||
recreate_box_absolute (boxptr, abspattern);
|
||||
grub_free (abspattern);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Set the specified property NAME on the view to the given string VALUE.
|
||||
The caller is responsible for the lifetimes of NAME and VALUE. */
|
||||
static grub_err_t
|
||||
theme_set_string (grub_gfxmenu_view_t view,
|
||||
const char *name,
|
||||
const char *value,
|
||||
const char *theme_dir,
|
||||
const char *filename,
|
||||
int line_num,
|
||||
int col_num)
|
||||
{
|
||||
if (! grub_strcmp ("title-font", name))
|
||||
view->title_font = grub_font_get (value);
|
||||
else if (! grub_strcmp ("message-font", name))
|
||||
view->message_font = grub_font_get (value);
|
||||
else if (! grub_strcmp ("terminal-font", name))
|
||||
{
|
||||
grub_free (view->terminal_font_name);
|
||||
view->terminal_font_name = grub_strdup (value);
|
||||
if (! view->terminal_font_name)
|
||||
return grub_errno;
|
||||
}
|
||||
else if (! grub_strcmp ("title-color", name))
|
||||
grub_gui_parse_color (value, &view->title_color);
|
||||
else if (! grub_strcmp ("message-color", name))
|
||||
grub_gui_parse_color (value, &view->message_color);
|
||||
else if (! grub_strcmp ("message-bg-color", name))
|
||||
grub_gui_parse_color (value, &view->message_bg_color);
|
||||
else if (! grub_strcmp ("desktop-image", name))
|
||||
{
|
||||
struct grub_video_bitmap *raw_bitmap;
|
||||
struct grub_video_bitmap *scaled_bitmap;
|
||||
char *path;
|
||||
path = grub_resolve_relative_path (theme_dir, value);
|
||||
if (! path)
|
||||
return grub_errno;
|
||||
if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_free (path);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_free(path);
|
||||
grub_video_bitmap_create_scaled (&scaled_bitmap,
|
||||
view->screen.width,
|
||||
view->screen.height,
|
||||
raw_bitmap,
|
||||
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
|
||||
grub_video_bitmap_destroy (raw_bitmap);
|
||||
if (! scaled_bitmap)
|
||||
{
|
||||
grub_error_push ();
|
||||
return grub_error (grub_errno, "error scaling desktop image");
|
||||
}
|
||||
|
||||
grub_video_bitmap_destroy (view->desktop_image);
|
||||
view->desktop_image = scaled_bitmap;
|
||||
}
|
||||
else if (! grub_strcmp ("desktop-color", name))
|
||||
grub_gui_parse_color (value, &view->desktop_color);
|
||||
else if (! grub_strcmp ("terminal-box", name))
|
||||
{
|
||||
grub_err_t err;
|
||||
err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
return err;
|
||||
}
|
||||
else if (! grub_strcmp ("title-text", name))
|
||||
{
|
||||
grub_free (view->title_text);
|
||||
view->title_text = grub_strdup (value);
|
||||
if (! view->title_text)
|
||||
return grub_errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"%s:%d:%d unknown property `%s'",
|
||||
filename, line_num, col_num, name);
|
||||
}
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
struct parsebuf
|
||||
{
|
||||
char *buf;
|
||||
int pos;
|
||||
int len;
|
||||
int line_num;
|
||||
int col_num;
|
||||
const char *filename;
|
||||
char *theme_dir;
|
||||
grub_gfxmenu_view_t view;
|
||||
};
|
||||
|
||||
static int
|
||||
has_more (struct parsebuf *p)
|
||||
{
|
||||
return p->pos < p->len;
|
||||
}
|
||||
|
||||
static int
|
||||
read_char (struct parsebuf *p)
|
||||
{
|
||||
if (has_more (p))
|
||||
{
|
||||
char c;
|
||||
c = p->buf[p->pos++];
|
||||
if (c == '\n')
|
||||
{
|
||||
p->line_num++;
|
||||
p->col_num = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->col_num++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
peek_char (struct parsebuf *p)
|
||||
{
|
||||
if (has_more (p))
|
||||
return p->buf[p->pos];
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
is_whitespace (char c)
|
||||
{
|
||||
return (c == ' '
|
||||
|| c == '\t'
|
||||
|| c == '\r'
|
||||
|| c == '\n'
|
||||
|| c == '\f');
|
||||
}
|
||||
|
||||
static void
|
||||
skip_whitespace (struct parsebuf *p)
|
||||
{
|
||||
while (has_more (p) && is_whitespace(peek_char (p)))
|
||||
read_char (p);
|
||||
}
|
||||
|
||||
static void
|
||||
advance_to_next_line (struct parsebuf *p)
|
||||
{
|
||||
int c;
|
||||
|
||||
/* Eat characters up to the newline. */
|
||||
do
|
||||
{
|
||||
c = read_char (p);
|
||||
}
|
||||
while (c != -1 && c != '\n');
|
||||
}
|
||||
|
||||
static int
|
||||
is_identifier_char (int c)
|
||||
{
|
||||
return (c != -1
|
||||
&& (grub_isalpha(c)
|
||||
|| grub_isdigit(c)
|
||||
|| c == '_'
|
||||
|| c == '-'));
|
||||
}
|
||||
|
||||
static char *
|
||||
read_identifier (struct parsebuf *p)
|
||||
{
|
||||
/* Index of the first character of the identifier in p->buf. */
|
||||
int start;
|
||||
/* Next index after the last character of the identifer in p->buf. */
|
||||
int end;
|
||||
|
||||
skip_whitespace (p);
|
||||
|
||||
/* Capture the start of the identifier. */
|
||||
start = p->pos;
|
||||
|
||||
/* Scan for the end. */
|
||||
while (is_identifier_char (peek_char (p)))
|
||||
read_char (p);
|
||||
end = p->pos;
|
||||
|
||||
if (end - start < 1)
|
||||
return 0;
|
||||
|
||||
return grub_new_substring (p->buf, start, end);
|
||||
}
|
||||
|
||||
static char *
|
||||
read_expression (struct parsebuf *p)
|
||||
{
|
||||
int start;
|
||||
int end;
|
||||
|
||||
skip_whitespace (p);
|
||||
if (peek_char (p) == '"')
|
||||
{
|
||||
/* Read as a quoted string.
|
||||
The quotation marks are not included in the expression value. */
|
||||
/* Skip opening quotation mark. */
|
||||
read_char (p);
|
||||
start = p->pos;
|
||||
while (has_more (p) && peek_char (p) != '"')
|
||||
read_char (p);
|
||||
end = p->pos;
|
||||
/* Skip the terminating quotation mark. */
|
||||
read_char (p);
|
||||
}
|
||||
else if (peek_char (p) == '(')
|
||||
{
|
||||
/* Read as a parenthesized string -- for tuples/coordinates. */
|
||||
/* The parentheses are included in the expression value. */
|
||||
int c;
|
||||
|
||||
start = p->pos;
|
||||
do
|
||||
{
|
||||
c = read_char (p);
|
||||
}
|
||||
while (c != -1 && c != ')');
|
||||
end = p->pos;
|
||||
}
|
||||
else if (has_more (p))
|
||||
{
|
||||
/* Read as a single word -- for numeric values or words without
|
||||
whitespace. */
|
||||
start = p->pos;
|
||||
while (has_more (p) && ! is_whitespace (peek_char (p)))
|
||||
read_char (p);
|
||||
end = p->pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The end of the theme file has been reached. */
|
||||
grub_error (GRUB_ERR_IO, "%s:%d:%d expression expected in theme file",
|
||||
p->filename, p->line_num, p->col_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
ptr++;
|
||||
}
|
||||
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
|
||||
read_object (struct parsebuf *p, grub_gui_container_t parent)
|
||||
{
|
||||
grub_video_rect_t bounds;
|
||||
|
||||
char *name;
|
||||
name = read_identifier (p);
|
||||
if (! name)
|
||||
goto cleanup;
|
||||
|
||||
grub_gui_component_t component = 0;
|
||||
if (grub_strcmp (name, "label") == 0)
|
||||
{
|
||||
component = grub_gui_label_new ();
|
||||
}
|
||||
else if (grub_strcmp (name, "image") == 0)
|
||||
{
|
||||
component = grub_gui_image_new ();
|
||||
}
|
||||
else if (grub_strcmp (name, "vbox") == 0)
|
||||
{
|
||||
component = (grub_gui_component_t) grub_gui_vbox_new ();
|
||||
}
|
||||
else if (grub_strcmp (name, "hbox") == 0)
|
||||
{
|
||||
component = (grub_gui_component_t) grub_gui_hbox_new ();
|
||||
}
|
||||
else if (grub_strcmp (name, "canvas") == 0)
|
||||
{
|
||||
component = (grub_gui_component_t) grub_gui_canvas_new ();
|
||||
}
|
||||
else if (grub_strcmp (name, "progress_bar") == 0)
|
||||
{
|
||||
component = grub_gui_progress_bar_new ();
|
||||
}
|
||||
else if (grub_strcmp (name, "circular_progress") == 0)
|
||||
{
|
||||
component = grub_gui_circular_progress_new ();
|
||||
}
|
||||
else if (grub_strcmp (name, "boot_menu") == 0)
|
||||
{
|
||||
component = grub_gui_list_new ();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown type. */
|
||||
grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'",
|
||||
p->filename, p->line_num, p->col_num, name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (! component)
|
||||
goto cleanup;
|
||||
|
||||
/* Inform the component about the theme so it can find its resources. */
|
||||
component->ops->set_property (component, "theme_dir", p->theme_dir);
|
||||
component->ops->set_property (component, "theme_path", p->filename);
|
||||
|
||||
/* Add the component as a child of PARENT. */
|
||||
bounds.x = 0;
|
||||
bounds.y = 0;
|
||||
bounds.width = -1;
|
||||
bounds.height = -1;
|
||||
component->ops->set_bounds (component, &bounds);
|
||||
parent->ops->add (parent, component);
|
||||
|
||||
skip_whitespace (p);
|
||||
if (read_char (p) != '{')
|
||||
{
|
||||
grub_error (GRUB_ERR_IO,
|
||||
"%s:%d:%d expected `{' after object type name `%s'",
|
||||
p->filename, p->line_num, p->col_num, name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (has_more (p))
|
||||
{
|
||||
skip_whitespace (p);
|
||||
|
||||
/* Check whether the end has been encountered. */
|
||||
if (peek_char (p) == '}')
|
||||
{
|
||||
/* Skip the closing brace. */
|
||||
read_char (p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (peek_char (p) == '#')
|
||||
{
|
||||
/* Skip comments. */
|
||||
advance_to_next_line (p);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peek_char (p) == '+')
|
||||
{
|
||||
/* Skip the '+'. */
|
||||
read_char (p);
|
||||
|
||||
/* Check whether this component is a container. */
|
||||
if (component->ops->is_instance (component, "container"))
|
||||
{
|
||||
/* Read the sub-object recursively and add it as a child. */
|
||||
if (read_object (p, (grub_gui_container_t) component) != 0)
|
||||
goto cleanup;
|
||||
/* After reading the sub-object, resume parsing, expecting
|
||||
another property assignment or sub-object definition. */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_error (GRUB_ERR_IO,
|
||||
"%s:%d:%d attempted to add object to non-container",
|
||||
p->filename, p->line_num, p->col_num);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
char *property;
|
||||
property = read_identifier (p);
|
||||
if (! property)
|
||||
{
|
||||
grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file",
|
||||
p->filename, p->line_num, p->col_num);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
skip_whitespace (p);
|
||||
if (read_char (p) != '=')
|
||||
{
|
||||
grub_error (GRUB_ERR_IO,
|
||||
"%s:%d:%d expected `=' after property name `%s'",
|
||||
p->filename, p->line_num, p->col_num, property);
|
||||
grub_free (property);
|
||||
goto cleanup;
|
||||
}
|
||||
skip_whitespace (p);
|
||||
|
||||
char *value;
|
||||
value = read_expression (p);
|
||||
if (! value)
|
||||
{
|
||||
grub_free (property);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Handle the property value. */
|
||||
if (grub_strcmp (property, "left") == 0)
|
||||
parse_proportional_spec (value, &component->x, &component->xfrac);
|
||||
else if (grub_strcmp (property, "top") == 0)
|
||||
parse_proportional_spec (value, &component->y, &component->yfrac);
|
||||
else if (grub_strcmp (property, "width") == 0)
|
||||
parse_proportional_spec (value, &component->w, &component->wfrac);
|
||||
else if (grub_strcmp (property, "height") == 0)
|
||||
parse_proportional_spec (value, &component->h, &component->hfrac);
|
||||
else
|
||||
/* General property handling. */
|
||||
component->ops->set_property (component, property, value);
|
||||
|
||||
grub_free (value);
|
||||
grub_free (property);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
grub_free (name);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
read_property (struct parsebuf *p)
|
||||
{
|
||||
char *name;
|
||||
|
||||
/* Read the property name. */
|
||||
name = read_identifier (p);
|
||||
if (! name)
|
||||
{
|
||||
advance_to_next_line (p);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Skip whitespace before separator. */
|
||||
skip_whitespace (p);
|
||||
|
||||
/* Read separator. */
|
||||
if (read_char (p) != ':')
|
||||
{
|
||||
grub_error (GRUB_ERR_IO,
|
||||
"%s:%d:%d missing separator after property name `%s'",
|
||||
p->filename, p->line_num, p->col_num, name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Skip whitespace after separator. */
|
||||
skip_whitespace (p);
|
||||
|
||||
/* Get the value based on its type. */
|
||||
if (peek_char (p) == '"')
|
||||
{
|
||||
/* String value (e.g., '"My string"'). */
|
||||
char *value = read_expression (p);
|
||||
if (! value)
|
||||
{
|
||||
grub_error (GRUB_ERR_IO, "%s:%d:%d missing property value",
|
||||
p->filename, p->line_num, p->col_num);
|
||||
goto done;
|
||||
}
|
||||
/* If theme_set_string results in an error, grub_errno will be returned
|
||||
below. */
|
||||
theme_set_string (p->view, name, value, p->theme_dir,
|
||||
p->filename, p->line_num, p->col_num);
|
||||
grub_free (value);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_error (GRUB_ERR_IO,
|
||||
"%s:%d:%d property value invalid; "
|
||||
"enclose literal values in quotes (\")",
|
||||
p->filename, p->line_num, p->col_num);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
grub_free (name);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Set properties on the view based on settings from the specified
|
||||
theme file. */
|
||||
grub_err_t
|
||||
grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path)
|
||||
{
|
||||
grub_file_t file;
|
||||
struct parsebuf p;
|
||||
|
||||
p.view = view;
|
||||
p.theme_dir = grub_get_dirname (theme_path);
|
||||
|
||||
file = grub_file_open (theme_path);
|
||||
if (! file)
|
||||
{
|
||||
grub_free (p.theme_dir);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
p.len = grub_file_size (file);
|
||||
p.buf = grub_malloc (p.len);
|
||||
p.pos = 0;
|
||||
p.line_num = 1;
|
||||
p.col_num = 1;
|
||||
p.filename = theme_path;
|
||||
if (! p.buf)
|
||||
{
|
||||
grub_file_close (file);
|
||||
grub_free (p.theme_dir);
|
||||
return grub_errno;
|
||||
}
|
||||
if (grub_file_read (file, p.buf, p.len) != p.len)
|
||||
{
|
||||
grub_free (p.buf);
|
||||
grub_file_close (file);
|
||||
grub_free (p.theme_dir);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
if (view->canvas)
|
||||
view->canvas->component.ops->destroy (view->canvas);
|
||||
|
||||
view->canvas = grub_gui_canvas_new ();
|
||||
((grub_gui_component_t) view->canvas)
|
||||
->ops->set_bounds ((grub_gui_component_t) view->canvas,
|
||||
&view->screen);
|
||||
|
||||
while (has_more (&p))
|
||||
{
|
||||
/* Skip comments (lines beginning with #). */
|
||||
if (peek_char (&p) == '#')
|
||||
{
|
||||
advance_to_next_line (&p);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find the first non-whitespace character. */
|
||||
skip_whitespace (&p);
|
||||
|
||||
/* Handle the content. */
|
||||
if (peek_char (&p) == '+')
|
||||
{
|
||||
/* Skip the '+'. */
|
||||
read_char (&p);
|
||||
read_object (&p, view->canvas);
|
||||
}
|
||||
else
|
||||
{
|
||||
read_property (&p);
|
||||
}
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set the new theme path. */
|
||||
grub_free (view->theme_path);
|
||||
view->theme_path = grub_strdup (theme_path);
|
||||
goto cleanup;
|
||||
|
||||
fail:
|
||||
if (view->canvas)
|
||||
{
|
||||
view->canvas->component.ops->destroy (view->canvas);
|
||||
view->canvas = 0;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
grub_free (p.buf);
|
||||
grub_file_close (file);
|
||||
grub_free (p.theme_dir);
|
||||
return grub_errno;
|
||||
}
|
486
grub-core/gfxmenu/view.c
Normal file
486
grub-core/gfxmenu/view.c
Normal file
|
@ -0,0 +1,486 @@
|
|||
/* view.c - Graphical menu interface MVC view. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/gfxterm.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/menu.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/icon_manager.h>
|
||||
|
||||
/* The component ID identifying GUI components to be updated as the timeout
|
||||
status changes. */
|
||||
#define TIMEOUT_COMPONENT_ID "__timeout__"
|
||||
|
||||
static void
|
||||
init_terminal (grub_gfxmenu_view_t view);
|
||||
static grub_video_rect_t term_rect;
|
||||
static grub_gfxmenu_view_t term_view;
|
||||
|
||||
/* Create a new view object, loading the theme specified by THEME_PATH and
|
||||
associating MODEL with the view. */
|
||||
grub_gfxmenu_view_t
|
||||
grub_gfxmenu_view_new (const char *theme_path,
|
||||
int width, int height)
|
||||
{
|
||||
grub_gfxmenu_view_t view;
|
||||
grub_font_t default_font;
|
||||
grub_gui_color_t default_fg_color;
|
||||
grub_gui_color_t default_bg_color;
|
||||
|
||||
view = grub_malloc (sizeof (*view));
|
||||
if (! view)
|
||||
return 0;
|
||||
|
||||
view->screen.x = 0;
|
||||
view->screen.y = 0;
|
||||
view->screen.width = width;
|
||||
view->screen.height = height;
|
||||
|
||||
default_font = grub_font_get ("Unknown Regular 16");
|
||||
default_fg_color = grub_gui_color_rgb (0, 0, 0);
|
||||
default_bg_color = grub_gui_color_rgb (255, 255, 255);
|
||||
|
||||
view->canvas = 0;
|
||||
|
||||
view->title_font = default_font;
|
||||
view->message_font = default_font;
|
||||
view->terminal_font_name = grub_strdup ("Fixed 10");
|
||||
view->title_color = default_fg_color;
|
||||
view->message_color = default_bg_color;
|
||||
view->message_bg_color = default_fg_color;
|
||||
view->desktop_image = 0;
|
||||
view->desktop_color = default_bg_color;
|
||||
view->terminal_box = grub_gfxmenu_create_box (0, 0);
|
||||
view->title_text = grub_strdup ("GRUB Boot Menu");
|
||||
view->progress_message_text = 0;
|
||||
view->theme_path = 0;
|
||||
|
||||
/* Set the timeout bar's frame. */
|
||||
view->progress_message_frame.width = view->screen.width * 4 / 5;
|
||||
view->progress_message_frame.height = 50;
|
||||
view->progress_message_frame.x = view->screen.x
|
||||
+ (view->screen.width - view->progress_message_frame.width) / 2;
|
||||
view->progress_message_frame.y = view->screen.y
|
||||
+ view->screen.height - 90 - 20 - view->progress_message_frame.height;
|
||||
|
||||
if (grub_gfxmenu_view_load_theme (view, theme_path) != 0)
|
||||
{
|
||||
grub_gfxmenu_view_destroy (view);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/* Destroy the view object. All used memory is freed. */
|
||||
void
|
||||
grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view)
|
||||
{
|
||||
if (!view)
|
||||
return;
|
||||
grub_video_bitmap_destroy (view->desktop_image);
|
||||
if (view->terminal_box)
|
||||
view->terminal_box->destroy (view->terminal_box);
|
||||
grub_free (view->terminal_font_name);
|
||||
grub_free (view->title_text);
|
||||
grub_free (view->progress_message_text);
|
||||
grub_free (view->theme_path);
|
||||
if (view->canvas)
|
||||
view->canvas->component.ops->destroy (view->canvas);
|
||||
grub_free (view);
|
||||
}
|
||||
|
||||
static void
|
||||
redraw_background (grub_gfxmenu_view_t view,
|
||||
const grub_video_rect_t *bounds)
|
||||
{
|
||||
if (view->desktop_image)
|
||||
{
|
||||
struct grub_video_bitmap *img = view->desktop_image;
|
||||
grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE,
|
||||
bounds->x, bounds->y,
|
||||
bounds->x - view->screen.x,
|
||||
bounds->y - view->screen.y,
|
||||
bounds->width, bounds->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_video_fill_rect (grub_gui_map_color (view->desktop_color),
|
||||
bounds->x, bounds->y,
|
||||
bounds->width, bounds->height);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_title (grub_gfxmenu_view_t view)
|
||||
{
|
||||
if (! view->title_text)
|
||||
return;
|
||||
|
||||
/* Center the title. */
|
||||
int title_width = grub_font_get_string_width (view->title_font,
|
||||
view->title_text);
|
||||
int x = (view->screen.width - title_width) / 2;
|
||||
int y = 40 + grub_font_get_ascent (view->title_font);
|
||||
grub_font_draw_string (view->title_text,
|
||||
view->title_font,
|
||||
grub_gui_map_color (view->title_color),
|
||||
x, y);
|
||||
}
|
||||
|
||||
struct progress_value_data
|
||||
{
|
||||
int visible;
|
||||
int start;
|
||||
int end;
|
||||
int value;
|
||||
};
|
||||
|
||||
static void
|
||||
update_timeout_visit (grub_gui_component_t component,
|
||||
void *userdata)
|
||||
{
|
||||
struct progress_value_data *pv;
|
||||
pv = (struct progress_value_data *) userdata;
|
||||
|
||||
((struct grub_gui_progress *) component)->ops
|
||||
->set_state ((struct grub_gui_progress *) component,
|
||||
pv->visible, pv->start, pv->value, pv->end);
|
||||
}
|
||||
|
||||
void
|
||||
grub_gfxmenu_print_timeout (int timeout, void *data)
|
||||
{
|
||||
struct grub_gfxmenu_view *view = data;
|
||||
|
||||
struct progress_value_data pv;
|
||||
|
||||
auto void redraw_timeout_visit (grub_gui_component_t component,
|
||||
void *userdata __attribute__ ((unused)));
|
||||
|
||||
auto void redraw_timeout_visit (grub_gui_component_t component,
|
||||
void *userdata __attribute__ ((unused)))
|
||||
{
|
||||
grub_video_rect_t bounds;
|
||||
component->ops->get_bounds (component, &bounds);
|
||||
grub_gfxmenu_view_redraw (view, &bounds);
|
||||
}
|
||||
|
||||
if (view->first_timeout == -1)
|
||||
view->first_timeout = timeout;
|
||||
|
||||
pv.visible = 1;
|
||||
pv.start = -(view->first_timeout + 1);
|
||||
pv.end = 0;
|
||||
pv.value = -timeout;
|
||||
|
||||
grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
|
||||
TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv);
|
||||
grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
|
||||
TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
|
||||
TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
|
||||
}
|
||||
|
||||
void
|
||||
grub_gfxmenu_clear_timeout (void *data)
|
||||
{
|
||||
struct progress_value_data pv;
|
||||
struct grub_gfxmenu_view *view = data;
|
||||
|
||||
auto void redraw_timeout_visit (grub_gui_component_t component,
|
||||
void *userdata __attribute__ ((unused)));
|
||||
|
||||
auto void redraw_timeout_visit (grub_gui_component_t component,
|
||||
void *userdata __attribute__ ((unused)))
|
||||
{
|
||||
grub_video_rect_t bounds;
|
||||
component->ops->get_bounds (component, &bounds);
|
||||
grub_gfxmenu_view_redraw (view, &bounds);
|
||||
}
|
||||
|
||||
pv.visible = 0;
|
||||
pv.start = 1;
|
||||
pv.end = 0;
|
||||
pv.value = 0;
|
||||
|
||||
grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
|
||||
TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv);
|
||||
grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
|
||||
TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
|
||||
TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
|
||||
}
|
||||
|
||||
static void
|
||||
update_menu_visit (grub_gui_component_t component,
|
||||
void *userdata)
|
||||
{
|
||||
grub_gfxmenu_view_t view;
|
||||
view = userdata;
|
||||
if (component->ops->is_instance (component, "list"))
|
||||
{
|
||||
grub_gui_list_t list = (grub_gui_list_t) component;
|
||||
list->ops->set_view_info (list, view);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update any boot menu components with the current menu model and
|
||||
theme path. */
|
||||
static void
|
||||
update_menu_components (grub_gfxmenu_view_t view)
|
||||
{
|
||||
grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
|
||||
update_menu_visit, view);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_message (grub_gfxmenu_view_t view)
|
||||
{
|
||||
char *text = view->progress_message_text;
|
||||
grub_video_rect_t f = view->progress_message_frame;
|
||||
if (! text)
|
||||
return;
|
||||
|
||||
grub_font_t font = view->message_font;
|
||||
grub_video_color_t color = grub_gui_map_color (view->message_color);
|
||||
|
||||
/* Border. */
|
||||
grub_video_fill_rect (color,
|
||||
f.x-1, f.y-1, f.width+2, f.height+2);
|
||||
/* Fill. */
|
||||
grub_video_fill_rect (grub_gui_map_color (view->message_bg_color),
|
||||
f.x, f.y, f.width, f.height);
|
||||
|
||||
/* Center the text. */
|
||||
int text_width = grub_font_get_string_width (font, text);
|
||||
int x = f.x + (f.width - text_width) / 2;
|
||||
int y = (f.y + (f.height - grub_font_get_descent (font)) / 2
|
||||
+ grub_font_get_ascent (font) / 2);
|
||||
grub_font_draw_string (text, font, color, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view,
|
||||
const grub_video_rect_t *region)
|
||||
{
|
||||
if (grub_video_have_common_points (&term_rect, region))
|
||||
grub_gfxterm_schedule_repaint ();
|
||||
|
||||
grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
|
||||
|
||||
redraw_background (view, region);
|
||||
if (view->canvas)
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
grub_gfxmenu_view_draw (grub_gfxmenu_view_t view)
|
||||
{
|
||||
init_terminal (view);
|
||||
|
||||
/* Clear the screen; there may be garbage left over in video memory. */
|
||||
grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
|
||||
view->screen.x, view->screen.y,
|
||||
view->screen.width, view->screen.height);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
|
||||
view->screen.x, view->screen.y,
|
||||
view->screen.width, view->screen.height);
|
||||
|
||||
update_menu_components (view);
|
||||
|
||||
grub_gfxmenu_view_redraw (view, &view->screen);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
grub_gfxmenu_view_redraw (view, &view->screen);
|
||||
}
|
||||
|
||||
static void
|
||||
redraw_menu_visit (grub_gui_component_t component,
|
||||
void *userdata)
|
||||
{
|
||||
grub_gfxmenu_view_t view;
|
||||
view = userdata;
|
||||
if (component->ops->is_instance (component, "list"))
|
||||
{
|
||||
grub_gui_list_t list;
|
||||
grub_video_rect_t bounds;
|
||||
|
||||
list = (grub_gui_list_t) component;
|
||||
component->ops->get_bounds (component, &bounds);
|
||||
grub_gfxmenu_view_redraw (view, &bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view)
|
||||
{
|
||||
update_menu_components (view);
|
||||
|
||||
grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
|
||||
redraw_menu_visit, view);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
{
|
||||
grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
|
||||
redraw_menu_visit, view);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_gfxmenu_set_chosen_entry (int entry, void *data)
|
||||
{
|
||||
grub_gfxmenu_view_t view = data;
|
||||
|
||||
view->selected = entry;
|
||||
grub_gfxmenu_redraw_menu (view);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_gfxmenu_draw_terminal_box (void)
|
||||
{
|
||||
grub_gfxmenu_box_t term_box;
|
||||
|
||||
term_box = term_view->terminal_box;
|
||||
if (!term_box)
|
||||
return;
|
||||
|
||||
term_box->set_content_size (term_box, term_rect.width,
|
||||
term_rect.height);
|
||||
|
||||
term_box->draw (term_box,
|
||||
term_rect.x - term_box->get_left_pad (term_box),
|
||||
term_rect.y - term_box->get_top_pad (term_box));
|
||||
grub_video_swap_buffers ();
|
||||
if (term_view->double_repaint)
|
||||
term_box->draw (term_box,
|
||||
term_rect.x - term_box->get_left_pad (term_box),
|
||||
term_rect.y - term_box->get_top_pad (term_box));
|
||||
}
|
||||
|
||||
static void
|
||||
init_terminal (grub_gfxmenu_view_t view)
|
||||
{
|
||||
term_rect.width = view->screen.width * 7 / 10;
|
||||
term_rect.height = view->screen.height * 7 / 10;
|
||||
|
||||
term_rect.x = view->screen.x + view->screen.width * (10 - 7) / 10 / 2;
|
||||
term_rect.y = view->screen.y + view->screen.height * (10 - 7) / 10 / 2;
|
||||
|
||||
term_view = view;
|
||||
|
||||
/* Note: currently there is no API for changing the gfxterm font
|
||||
on the fly, so whatever font the initially loaded theme specifies
|
||||
will be permanent. */
|
||||
grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, term_rect.x,
|
||||
term_rect.y,
|
||||
term_rect.width, term_rect.height,
|
||||
view->double_repaint, view->terminal_font_name, 3);
|
||||
grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box;
|
||||
}
|
||||
|
||||
/* FIXME: previously notifications were displayed in special case.
|
||||
Is it necessary?
|
||||
*/
|
||||
#if 0
|
||||
/* Sets MESSAGE as the progress message for the view.
|
||||
MESSAGE can be 0, in which case no message is displayed. */
|
||||
static void
|
||||
set_progress_message (grub_gfxmenu_view_t view, const char *message)
|
||||
{
|
||||
grub_free (view->progress_message_text);
|
||||
if (message)
|
||||
view->progress_message_text = grub_strdup (message);
|
||||
else
|
||||
view->progress_message_text = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
notify_booting (grub_menu_entry_t entry, void *userdata)
|
||||
{
|
||||
grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
|
||||
|
||||
char *s = grub_malloc (100 + grub_strlen (entry->title));
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
grub_sprintf (s, "Booting '%s'", entry->title);
|
||||
set_progress_message (view, s);
|
||||
grub_free (s);
|
||||
grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_fallback (grub_menu_entry_t entry, void *userdata)
|
||||
{
|
||||
grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
|
||||
|
||||
char *s = grub_malloc (100 + grub_strlen (entry->title));
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
grub_sprintf (s, "Falling back to '%s'", entry->title);
|
||||
set_progress_message (view, s);
|
||||
grub_free (s);
|
||||
grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_execution_failure (void *userdata __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static struct grub_menu_execute_callback execute_callback =
|
||||
{
|
||||
.notify_booting = notify_booting,
|
||||
.notify_fallback = notify_fallback,
|
||||
.notify_failure = notify_execution_failure
|
||||
};
|
||||
|
||||
#endif
|
313
grub-core/gfxmenu/widget-box.c
Normal file
313
grub-core/gfxmenu/widget-box.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
/* widget_box.c - Pixmap-stylized box widget. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
|
||||
enum box_pixmaps
|
||||
{
|
||||
BOX_PIXMAP_NW, BOX_PIXMAP_NE, BOX_PIXMAP_SE, BOX_PIXMAP_SW,
|
||||
BOX_PIXMAP_N, BOX_PIXMAP_E, BOX_PIXMAP_S, BOX_PIXMAP_W,
|
||||
BOX_PIXMAP_CENTER
|
||||
};
|
||||
|
||||
static const char *box_pixmap_names[] = {
|
||||
/* Corners: */
|
||||
"nw", "ne", "se", "sw",
|
||||
/* Sides: */
|
||||
"n", "e", "s", "w",
|
||||
/* Center: */
|
||||
"c"
|
||||
};
|
||||
|
||||
#define BOX_NUM_PIXMAPS (sizeof(box_pixmap_names)/sizeof(*box_pixmap_names))
|
||||
|
||||
static int
|
||||
get_height (struct grub_video_bitmap *bitmap)
|
||||
{
|
||||
if (bitmap)
|
||||
return grub_video_bitmap_get_height (bitmap);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_width (struct grub_video_bitmap *bitmap)
|
||||
{
|
||||
if (bitmap)
|
||||
return grub_video_bitmap_get_width (bitmap);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
blit (grub_gfxmenu_box_t self, int pixmap_index, int x, int y)
|
||||
{
|
||||
struct grub_video_bitmap *bitmap;
|
||||
bitmap = self->scaled_pixmaps[pixmap_index];
|
||||
if (! bitmap)
|
||||
return;
|
||||
grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_BLEND,
|
||||
x, y, 0, 0,
|
||||
grub_video_bitmap_get_width (bitmap),
|
||||
grub_video_bitmap_get_height (bitmap));
|
||||
}
|
||||
|
||||
static void
|
||||
draw (grub_gfxmenu_box_t self, int x, int y)
|
||||
{
|
||||
int height_n;
|
||||
int height_s;
|
||||
int height_e;
|
||||
int height_w;
|
||||
int width_n;
|
||||
int width_s;
|
||||
int width_e;
|
||||
int width_w;
|
||||
|
||||
height_n = get_height (self->scaled_pixmaps[BOX_PIXMAP_N]);
|
||||
height_s = get_height (self->scaled_pixmaps[BOX_PIXMAP_S]);
|
||||
height_e = get_height (self->scaled_pixmaps[BOX_PIXMAP_E]);
|
||||
height_w = get_height (self->scaled_pixmaps[BOX_PIXMAP_W]);
|
||||
width_n = get_width (self->scaled_pixmaps[BOX_PIXMAP_N]);
|
||||
width_s = get_width (self->scaled_pixmaps[BOX_PIXMAP_S]);
|
||||
width_e = get_width (self->scaled_pixmaps[BOX_PIXMAP_E]);
|
||||
width_w = get_width (self->scaled_pixmaps[BOX_PIXMAP_W]);
|
||||
|
||||
/* Draw sides. */
|
||||
blit (self, BOX_PIXMAP_N, x + width_w, y);
|
||||
blit (self, BOX_PIXMAP_S, x + width_w, y + height_n + self->content_height);
|
||||
blit (self, BOX_PIXMAP_E, x + width_w + self->content_width, y + height_n);
|
||||
blit (self, BOX_PIXMAP_W, x, y + height_n);
|
||||
|
||||
/* Draw corners. */
|
||||
blit (self, BOX_PIXMAP_NW, x, y);
|
||||
blit (self, BOX_PIXMAP_NE, x + width_w + self->content_width, y);
|
||||
blit (self, BOX_PIXMAP_SE,
|
||||
x + width_w + self->content_width,
|
||||
y + height_n + self->content_height);
|
||||
blit (self, BOX_PIXMAP_SW, x, y + height_n + self->content_height);
|
||||
|
||||
/* Draw center. */
|
||||
blit (self, BOX_PIXMAP_CENTER, x + width_w, y + height_n);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
scale_pixmap (grub_gfxmenu_box_t self, int i, int w, int h)
|
||||
{
|
||||
struct grub_video_bitmap **scaled = &self->scaled_pixmaps[i];
|
||||
struct grub_video_bitmap *raw = self->raw_pixmaps[i];
|
||||
|
||||
if (raw == 0)
|
||||
return grub_errno;
|
||||
|
||||
if (w == -1)
|
||||
w = grub_video_bitmap_get_width (raw);
|
||||
if (h == -1)
|
||||
h = grub_video_bitmap_get_height (raw);
|
||||
|
||||
if (*scaled == 0
|
||||
|| ((int) grub_video_bitmap_get_width (*scaled) != w)
|
||||
|| ((int) grub_video_bitmap_get_height (*scaled) != h))
|
||||
{
|
||||
if (*scaled)
|
||||
{
|
||||
grub_video_bitmap_destroy (*scaled);
|
||||
*scaled = 0;
|
||||
}
|
||||
|
||||
/* Don't try to create a bitmap with a zero dimension. */
|
||||
if (w != 0 && h != 0)
|
||||
grub_video_bitmap_create_scaled (scaled, w, h, raw,
|
||||
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_error (grub_errno,
|
||||
"failed to scale bitmap for styled box pixmap #%d", i);
|
||||
}
|
||||
}
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static void
|
||||
set_content_size (grub_gfxmenu_box_t self,
|
||||
int width, int height)
|
||||
{
|
||||
self->content_width = width;
|
||||
self->content_height = height;
|
||||
|
||||
/* Resize sides to match the width and height. */
|
||||
/* It is assumed that the corners width/height match the adjacent sides. */
|
||||
|
||||
/* Resize N and S sides to match width. */
|
||||
if (scale_pixmap(self, BOX_PIXMAP_N, width, -1) != GRUB_ERR_NONE)
|
||||
return;
|
||||
if (scale_pixmap(self, BOX_PIXMAP_S, width, -1) != GRUB_ERR_NONE)
|
||||
return;
|
||||
|
||||
/* Resize E and W sides to match height. */
|
||||
if (scale_pixmap(self, BOX_PIXMAP_E, -1, height) != GRUB_ERR_NONE)
|
||||
return;
|
||||
if (scale_pixmap(self, BOX_PIXMAP_W, -1, height) != GRUB_ERR_NONE)
|
||||
return;
|
||||
|
||||
/* Don't scale the corners--they are assumed to match the sides. */
|
||||
if (scale_pixmap(self, BOX_PIXMAP_NW, -1, -1) != GRUB_ERR_NONE)
|
||||
return;
|
||||
if (scale_pixmap(self, BOX_PIXMAP_SW, -1, -1) != GRUB_ERR_NONE)
|
||||
return;
|
||||
if (scale_pixmap(self, BOX_PIXMAP_NE, -1, -1) != GRUB_ERR_NONE)
|
||||
return;
|
||||
if (scale_pixmap(self, BOX_PIXMAP_SE, -1, -1) != GRUB_ERR_NONE)
|
||||
return;
|
||||
|
||||
/* Scale the center area. */
|
||||
if (scale_pixmap(self, BOX_PIXMAP_CENTER, width, height) != GRUB_ERR_NONE)
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
get_left_pad (grub_gfxmenu_box_t self)
|
||||
{
|
||||
return get_width (self->raw_pixmaps[BOX_PIXMAP_W]);
|
||||
}
|
||||
|
||||
static int
|
||||
get_top_pad (grub_gfxmenu_box_t self)
|
||||
{
|
||||
return get_height (self->raw_pixmaps[BOX_PIXMAP_N]);
|
||||
}
|
||||
|
||||
static int
|
||||
get_right_pad (grub_gfxmenu_box_t self)
|
||||
{
|
||||
return get_width (self->raw_pixmaps[BOX_PIXMAP_E]);
|
||||
}
|
||||
|
||||
static int
|
||||
get_bottom_pad (grub_gfxmenu_box_t self)
|
||||
{
|
||||
return get_height (self->raw_pixmaps[BOX_PIXMAP_S]);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy (grub_gfxmenu_box_t self)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < BOX_NUM_PIXMAPS; i++)
|
||||
{
|
||||
if (self->raw_pixmaps[i])
|
||||
grub_video_bitmap_destroy(self->raw_pixmaps[i]);
|
||||
self->raw_pixmaps[i] = 0;
|
||||
|
||||
if (self->scaled_pixmaps[i])
|
||||
grub_video_bitmap_destroy(self->scaled_pixmaps[i]);
|
||||
self->scaled_pixmaps[i] = 0;
|
||||
}
|
||||
grub_free (self->raw_pixmaps);
|
||||
self->raw_pixmaps = 0;
|
||||
grub_free (self->scaled_pixmaps);
|
||||
self->scaled_pixmaps = 0;
|
||||
|
||||
/* Free self: must be the last step! */
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
|
||||
/* Create a new box. If PIXMAPS_PREFIX and PIXMAPS_SUFFIX are both non-null,
|
||||
then an attempt is made to load the north, south, east, west, northwest,
|
||||
northeast, southeast, southwest, and center pixmaps.
|
||||
If either PIXMAPS_PREFIX or PIXMAPS_SUFFIX is 0, then no pixmaps are
|
||||
loaded, and the box has zero-width borders and is drawn transparent. */
|
||||
grub_gfxmenu_box_t
|
||||
grub_gfxmenu_create_box (const char *pixmaps_prefix,
|
||||
const char *pixmaps_suffix)
|
||||
{
|
||||
unsigned i;
|
||||
grub_gfxmenu_box_t box;
|
||||
|
||||
box = (grub_gfxmenu_box_t) grub_malloc (sizeof (*box));
|
||||
if (! box)
|
||||
return 0;
|
||||
|
||||
box->content_width = 0;
|
||||
box->content_height = 0;
|
||||
box->raw_pixmaps =
|
||||
(struct grub_video_bitmap **)
|
||||
grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *));
|
||||
box->scaled_pixmaps =
|
||||
(struct grub_video_bitmap **)
|
||||
grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *));
|
||||
|
||||
/* Initialize all pixmap pointers to NULL so that proper destruction can
|
||||
be performed if an error is encountered partway through construction. */
|
||||
for (i = 0; i < BOX_NUM_PIXMAPS; i++)
|
||||
box->raw_pixmaps[i] = 0;
|
||||
for (i = 0; i < BOX_NUM_PIXMAPS; i++)
|
||||
box->scaled_pixmaps[i] = 0;
|
||||
|
||||
/* Load the pixmaps. */
|
||||
for (i = 0; i < BOX_NUM_PIXMAPS; i++)
|
||||
{
|
||||
if (pixmaps_prefix && pixmaps_suffix)
|
||||
{
|
||||
char *path;
|
||||
char *path_end;
|
||||
|
||||
path = grub_malloc (grub_strlen (pixmaps_prefix)
|
||||
+ grub_strlen (box_pixmap_names[i])
|
||||
+ grub_strlen (pixmaps_suffix)
|
||||
+ 1);
|
||||
if (! path)
|
||||
goto fail_and_destroy;
|
||||
|
||||
/* Construct the specific path for this pixmap. */
|
||||
path_end = grub_stpcpy (path, pixmaps_prefix);
|
||||
path_end = grub_stpcpy (path_end, box_pixmap_names[i]);
|
||||
path_end = grub_stpcpy (path_end, pixmaps_suffix);
|
||||
|
||||
grub_video_bitmap_load (&box->raw_pixmaps[i], path);
|
||||
grub_free (path);
|
||||
|
||||
/* Ignore missing pixmaps. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
box->draw = draw;
|
||||
box->set_content_size = set_content_size;
|
||||
box->get_left_pad = get_left_pad;
|
||||
box->get_top_pad = get_top_pad;
|
||||
box->get_right_pad = get_right_pad;
|
||||
box->get_bottom_pad = get_bottom_pad;
|
||||
box->destroy = destroy;
|
||||
return box;
|
||||
|
||||
fail_and_destroy:
|
||||
destroy (box);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue