gui_canvas.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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.
  5. *
  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.
  10. *
  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.
  15. *
  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/>.
  18. */
  19. #include <grub/mm.h>
  20. #include <grub/misc.h>
  21. #include <grub/gui.h>
  22. #include <grub/gui_string_util.h>
  23. /* TODO Add layering so that components can be properly overlaid. */
  24. struct component_node
  25. {
  26. grub_gui_component_t component;
  27. struct component_node *next;
  28. };
  29. struct grub_gui_canvas
  30. {
  31. struct grub_gui_container container;
  32. grub_gui_container_t parent;
  33. grub_video_rect_t bounds;
  34. char *id;
  35. /* Component list (dummy head node). */
  36. struct component_node components;
  37. };
  38. typedef struct grub_gui_canvas *grub_gui_canvas_t;
  39. static void
  40. canvas_destroy (void *vself)
  41. {
  42. grub_gui_canvas_t self = vself;
  43. struct component_node *cur;
  44. struct component_node *next;
  45. for (cur = self->components.next; cur; cur = next)
  46. {
  47. /* Copy the 'next' pointer, since we need it for the next iteration,
  48. and we're going to free the memory it is stored in. */
  49. next = cur->next;
  50. /* Destroy the child component. */
  51. cur->component->ops->destroy (cur->component);
  52. /* Free the linked list node. */
  53. grub_free (cur);
  54. }
  55. grub_free (self);
  56. }
  57. static const char *
  58. canvas_get_id (void *vself)
  59. {
  60. grub_gui_canvas_t self = vself;
  61. return self->id;
  62. }
  63. static int
  64. canvas_is_instance (void *vself __attribute__((unused)), const char *type)
  65. {
  66. return (grub_strcmp (type, "component") == 0
  67. || grub_strcmp (type, "container") == 0);
  68. }
  69. static void
  70. canvas_paint (void *vself, const grub_video_rect_t *region)
  71. {
  72. grub_gui_canvas_t self = vself;
  73. struct component_node *cur;
  74. grub_video_rect_t vpsave;
  75. grub_gui_set_viewport (&self->bounds, &vpsave);
  76. for (cur = self->components.next; cur; cur = cur->next)
  77. {
  78. grub_video_rect_t r;
  79. grub_gui_component_t comp;
  80. signed x, y, w, h;
  81. comp = cur->component;
  82. w = grub_fixed_sfs_multiply (self->bounds.width, comp->wfrac) + comp->w;
  83. h = grub_fixed_sfs_multiply (self->bounds.height, comp->hfrac) + comp->h;
  84. x = grub_fixed_sfs_multiply (self->bounds.width, comp->xfrac) + comp->x;
  85. y = grub_fixed_sfs_multiply (self->bounds.height, comp->yfrac) + comp->y;
  86. if (comp->ops->get_minimal_size)
  87. {
  88. unsigned mw;
  89. unsigned mh;
  90. comp->ops->get_minimal_size (comp, &mw, &mh);
  91. if (w < (signed) mw)
  92. w = mw;
  93. if (h < (signed) mh)
  94. h = mh;
  95. }
  96. /* Sanity checks. */
  97. if (w <= 0)
  98. w = 32;
  99. if (h <= 0)
  100. h = 32;
  101. if (x >= (signed) self->bounds.width)
  102. x = self->bounds.width - 32;
  103. if (y >= (signed) self->bounds.height)
  104. y = self->bounds.height - 32;
  105. if (x < 0)
  106. x = 0;
  107. if (y < 0)
  108. y = 0;
  109. if (x + w >= (signed) self->bounds.width)
  110. w = self->bounds.width - x;
  111. if (y + h >= (signed) self->bounds.height)
  112. h = self->bounds.height - y;
  113. r.x = x;
  114. r.y = y;
  115. r.width = w;
  116. r.height = h;
  117. comp->ops->set_bounds (comp, &r);
  118. /* Paint the child. */
  119. if (grub_video_have_common_points (region, &r))
  120. comp->ops->paint (comp, region);
  121. }
  122. grub_gui_restore_viewport (&vpsave);
  123. }
  124. static void
  125. canvas_set_parent (void *vself, grub_gui_container_t parent)
  126. {
  127. grub_gui_canvas_t self = vself;
  128. self->parent = parent;
  129. }
  130. static grub_gui_container_t
  131. canvas_get_parent (void *vself)
  132. {
  133. grub_gui_canvas_t self = vself;
  134. return self->parent;
  135. }
  136. static void
  137. canvas_set_bounds (void *vself, const grub_video_rect_t *bounds)
  138. {
  139. grub_gui_canvas_t self = vself;
  140. self->bounds = *bounds;
  141. }
  142. static void
  143. canvas_get_bounds (void *vself, grub_video_rect_t *bounds)
  144. {
  145. grub_gui_canvas_t self = vself;
  146. *bounds = self->bounds;
  147. }
  148. static grub_err_t
  149. canvas_set_property (void *vself, const char *name, const char *value)
  150. {
  151. grub_gui_canvas_t self = vself;
  152. if (grub_strcmp (name, "id") == 0)
  153. {
  154. grub_free (self->id);
  155. if (value)
  156. {
  157. self->id = grub_strdup (value);
  158. if (! self->id)
  159. return grub_errno;
  160. }
  161. else
  162. self->id = 0;
  163. }
  164. return grub_errno;
  165. }
  166. static void
  167. canvas_add (void *vself, grub_gui_component_t comp)
  168. {
  169. grub_gui_canvas_t self = vself;
  170. struct component_node *node;
  171. node = grub_malloc (sizeof (*node));
  172. if (! node)
  173. return; /* Note: probably should handle the error. */
  174. node->component = comp;
  175. node->next = self->components.next;
  176. self->components.next = node;
  177. comp->ops->set_parent (comp, (grub_gui_container_t) self);
  178. }
  179. static void
  180. canvas_remove (void *vself, grub_gui_component_t comp)
  181. {
  182. grub_gui_canvas_t self = vself;
  183. struct component_node *cur;
  184. struct component_node *prev;
  185. prev = &self->components;
  186. for (cur = self->components.next; cur; prev = cur, cur = cur->next)
  187. {
  188. if (cur->component == comp)
  189. {
  190. /* Unlink 'cur' from the list. */
  191. prev->next = cur->next;
  192. /* Free the node's memory (but don't destroy the component). */
  193. grub_free (cur);
  194. /* Must not loop again, since 'cur' would be dereferenced! */
  195. return;
  196. }
  197. }
  198. }
  199. static void
  200. canvas_iterate_children (void *vself,
  201. grub_gui_component_callback cb, void *userdata)
  202. {
  203. grub_gui_canvas_t self = vself;
  204. struct component_node *cur;
  205. for (cur = self->components.next; cur; cur = cur->next)
  206. cb (cur->component, userdata);
  207. }
  208. static struct grub_gui_component_ops canvas_comp_ops =
  209. {
  210. .destroy = canvas_destroy,
  211. .get_id = canvas_get_id,
  212. .is_instance = canvas_is_instance,
  213. .paint = canvas_paint,
  214. .set_parent = canvas_set_parent,
  215. .get_parent = canvas_get_parent,
  216. .set_bounds = canvas_set_bounds,
  217. .get_bounds = canvas_get_bounds,
  218. .set_property = canvas_set_property
  219. };
  220. static struct grub_gui_container_ops canvas_ops =
  221. {
  222. .add = canvas_add,
  223. .remove = canvas_remove,
  224. .iterate_children = canvas_iterate_children
  225. };
  226. grub_gui_container_t
  227. grub_gui_canvas_new (void)
  228. {
  229. grub_gui_canvas_t canvas;
  230. canvas = grub_zalloc (sizeof (*canvas));
  231. if (! canvas)
  232. return 0;
  233. canvas->container.ops = &canvas_ops;
  234. canvas->container.component.ops = &canvas_comp_ops;
  235. return (grub_gui_container_t) canvas;
  236. }