1 /* gui_canvas.c - GUI container allowing manually placed components. */
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/>.
21 #include <grub/misc.h>
23 #include <grub/gui_string_util.h>
25 /* TODO Add layering so that components can be properly overlaid. */
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
;
42 /* Component list (dummy head node). */
43 struct component_node components
;
46 typedef struct grub_gui_canvas
*grub_gui_canvas_t
;
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. */
59 /* Destroy the child component. */
60 cur
->component
->ops
->destroy (cur
->component
);
61 /* Free the linked list node. */
68 canvas_get_id (void *vself
)
70 grub_gui_canvas_t self
= vself
;
75 canvas_is_instance (void *vself
__attribute__((unused
)), const char *type
)
77 return (grub_strcmp (type
, "component") == 0
78 || grub_strcmp (type
, "container") == 0);
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
)
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
)
105 comp
->ops
->set_bounds (comp
, &r
);
108 /* Paint the child. */
109 comp
->ops
->paint (comp
);
111 grub_gui_restore_viewport (&vpsave
);
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
;
129 canvas_set_bounds (void *vself
, const grub_video_rect_t
*bounds
)
131 grub_gui_canvas_t self
= vself
;
132 self
->bounds
= *bounds
;
136 canvas_get_bounds (void *vself
, grub_video_rect_t
*bounds
)
138 grub_gui_canvas_t self
= vself
;
139 *bounds
= self
->bounds
;
143 canvas_get_preferred_size (void *vself
, int *width
, int *height
)
145 grub_gui_canvas_t self
= vself
;
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
;
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
);
165 self
->id
= grub_strdup (value
);
172 else if (grub_strcmp (name
, "preferred_size") == 0)
176 if (grub_gui_parse_2_tuple (value
, &w
, &h
) != GRUB_ERR_NONE
)
178 self
->preferred_width
= w
;
179 self
->preferred_height
= h
;
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
));
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
);
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). */
213 /* Must not loop again, since 'cur' would be dereferenced! */
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
=
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
245 .remove
= canvas_remove
,
246 .iterate_children
= canvas_iterate_children
250 grub_gui_canvas_new (void)
252 grub_gui_canvas_t canvas
;
253 canvas
= grub_malloc (sizeof (*canvas
));
256 canvas
->container
= &canvas_ops
;
258 canvas
->bounds
.x
= 0;
259 canvas
->bounds
.y
= 0;
260 canvas
->bounds
.width
= 0;
261 canvas
->bounds
.height
= 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
;