Merge branch 'makefile' into haiku
[grub2/phcoder.git] / gfxmenu / gui_canvas.c
bloba2cd77df66b52ef304003023f9fe98e08adba232
1 /* gui_canvas.c - GUI container allowing manually placed components. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/mm.h>
21 #include <grub/misc.h>
22 #include <grub/gui.h>
23 #include <grub/gui_string_util.h>
25 /* TODO Add layering so that components can be properly overlaid. */
27 struct component_node
29 grub_gui_component_t component;
30 struct component_node *next;
33 struct grub_gui_canvas
35 struct grub_gui_container_ops *container;
37 grub_gui_container_t parent;
38 grub_video_rect_t bounds;
39 char *id;
40 int preferred_width;
41 int preferred_height;
42 /* Component list (dummy head node). */
43 struct component_node components;
46 typedef struct grub_gui_canvas *grub_gui_canvas_t;
48 static void
49 canvas_destroy (void *vself)
51 grub_gui_canvas_t self = vself;
52 struct component_node *cur;
53 struct component_node *next;
54 for (cur = self->components.next; cur; cur = next)
56 /* Copy the 'next' pointer, since we need it for the next iteration,
57 and we're going to free the memory it is stored in. */
58 next = cur->next;
59 /* Destroy the child component. */
60 cur->component->ops->destroy (cur->component);
61 /* Free the linked list node. */
62 grub_free (cur);
64 grub_free (self);
67 static const char *
68 canvas_get_id (void *vself)
70 grub_gui_canvas_t self = vself;
71 return self->id;
74 static int
75 canvas_is_instance (void *vself __attribute__((unused)), const char *type)
77 return (grub_strcmp (type, "component") == 0
78 || grub_strcmp (type, "container") == 0);
81 static void
82 canvas_paint (void *vself)
84 grub_gui_canvas_t self = vself;
85 struct component_node *cur;
86 grub_video_rect_t vpsave;
88 grub_gui_set_viewport (&self->bounds, &vpsave);
89 for (cur = self->components.next; cur; cur = cur->next)
91 int pw;
92 int ph;
93 grub_video_rect_t r;
94 grub_gui_component_t comp;
96 comp = cur->component;
98 /* Give the child its preferred size. */
99 comp->ops->get_preferred_size (comp, &pw, &ph);
100 comp->ops->get_bounds (comp, &r);
101 if (r.width != pw || r.height != ph)
103 r.width = pw;
104 r.height = ph;
105 comp->ops->set_bounds (comp, &r);
108 /* Paint the child. */
109 comp->ops->paint (comp);
111 grub_gui_restore_viewport (&vpsave);
114 static void
115 canvas_set_parent (void *vself, grub_gui_container_t parent)
117 grub_gui_canvas_t self = vself;
118 self->parent = parent;
121 static grub_gui_container_t
122 canvas_get_parent (void *vself)
124 grub_gui_canvas_t self = vself;
125 return self->parent;
128 static void
129 canvas_set_bounds (void *vself, const grub_video_rect_t *bounds)
131 grub_gui_canvas_t self = vself;
132 self->bounds = *bounds;
135 static void
136 canvas_get_bounds (void *vself, grub_video_rect_t *bounds)
138 grub_gui_canvas_t self = vself;
139 *bounds = self->bounds;
142 static void
143 canvas_get_preferred_size (void *vself, int *width, int *height)
145 grub_gui_canvas_t self = vself;
146 *width = 0;
147 *height = 0;
149 /* Allow preferred dimensions to override the empty dimensions. */
150 if (self->preferred_width >= 0)
151 *width = self->preferred_width;
152 if (self->preferred_height >= 0)
153 *height = self->preferred_height;
156 static grub_err_t
157 canvas_set_property (void *vself, const char *name, const char *value)
159 grub_gui_canvas_t self = vself;
160 if (grub_strcmp (name, "id") == 0)
162 grub_free (self->id);
163 if (value)
165 self->id = grub_strdup (value);
166 if (! self->id)
167 return grub_errno;
169 else
170 self->id = 0;
172 else if (grub_strcmp (name, "preferred_size") == 0)
174 int w;
175 int h;
176 if (grub_gui_parse_2_tuple (value, &w, &h) != GRUB_ERR_NONE)
177 return grub_errno;
178 self->preferred_width = w;
179 self->preferred_height = h;
181 return grub_errno;
184 static void
185 canvas_add (void *vself, grub_gui_component_t comp)
187 grub_gui_canvas_t self = vself;
188 struct component_node *node;
189 node = grub_malloc (sizeof (*node));
190 if (! node)
191 return; /* Note: probably should handle the error. */
192 node->component = comp;
193 node->next = self->components.next;
194 self->components.next = node;
195 comp->ops->set_parent (comp, (grub_gui_container_t) self);
198 static void
199 canvas_remove (void *vself, grub_gui_component_t comp)
201 grub_gui_canvas_t self = vself;
202 struct component_node *cur;
203 struct component_node *prev;
204 prev = &self->components;
205 for (cur = self->components.next; cur; prev = cur, cur = cur->next)
207 if (cur->component == comp)
209 /* Unlink 'cur' from the list. */
210 prev->next = cur->next;
211 /* Free the node's memory (but don't destroy the component). */
212 grub_free (cur);
213 /* Must not loop again, since 'cur' would be dereferenced! */
214 return;
219 static void
220 canvas_iterate_children (void *vself,
221 grub_gui_component_callback cb, void *userdata)
223 grub_gui_canvas_t self = vself;
224 struct component_node *cur;
225 for (cur = self->components.next; cur; cur = cur->next)
226 cb (cur->component, userdata);
229 static struct grub_gui_container_ops canvas_ops =
231 .component =
233 .destroy = canvas_destroy,
234 .get_id = canvas_get_id,
235 .is_instance = canvas_is_instance,
236 .paint = canvas_paint,
237 .set_parent = canvas_set_parent,
238 .get_parent = canvas_get_parent,
239 .set_bounds = canvas_set_bounds,
240 .get_bounds = canvas_get_bounds,
241 .get_preferred_size = canvas_get_preferred_size,
242 .set_property = canvas_set_property
244 .add = canvas_add,
245 .remove = canvas_remove,
246 .iterate_children = canvas_iterate_children
249 grub_gui_container_t
250 grub_gui_canvas_new (void)
252 grub_gui_canvas_t canvas;
253 canvas = grub_malloc (sizeof (*canvas));
254 if (! canvas)
255 return 0;
256 canvas->container = &canvas_ops;
257 canvas->parent = 0;
258 canvas->bounds.x = 0;
259 canvas->bounds.y = 0;
260 canvas->bounds.width = 0;
261 canvas->bounds.height = 0;
262 canvas->id = 0;
263 canvas->preferred_width = -1;
264 canvas->preferred_height = -1;
265 canvas->components.component = 0;
266 canvas->components.next = 0;
267 return (grub_gui_container_t) canvas;