gui_canvas.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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_video_area_status_t canvas_area_status;
  76. grub_video_get_area_status (&canvas_area_status);
  77. grub_gui_set_viewport (&self->bounds, &vpsave);
  78. for (cur = self->components.next; cur; cur = cur->next)
  79. {
  80. grub_video_rect_t r;
  81. grub_gui_component_t comp;
  82. signed x, y, w, h;
  83. comp = cur->component;
  84. w = grub_fixed_sfs_multiply (self->bounds.width, comp->wfrac) + comp->w;
  85. h = grub_fixed_sfs_multiply (self->bounds.height, comp->hfrac) + comp->h;
  86. x = grub_fixed_sfs_multiply (self->bounds.width, comp->xfrac) + comp->x;
  87. y = grub_fixed_sfs_multiply (self->bounds.height, comp->yfrac) + comp->y;
  88. if (comp->ops->get_minimal_size)
  89. {
  90. unsigned mw;
  91. unsigned mh;
  92. comp->ops->get_minimal_size (comp, &mw, &mh);
  93. if (w < (signed) mw)
  94. w = mw;
  95. if (h < (signed) mh)
  96. h = mh;
  97. }
  98. /* Sanity checks. */
  99. if (w <= 0)
  100. w = 32;
  101. if (h <= 0)
  102. h = 32;
  103. if (x >= (signed) self->bounds.width)
  104. x = self->bounds.width - 32;
  105. if (y >= (signed) self->bounds.height)
  106. y = self->bounds.height - 32;
  107. if (x < 0)
  108. x = 0;
  109. if (y < 0)
  110. y = 0;
  111. if (x + w >= (signed) self->bounds.width)
  112. w = self->bounds.width - x;
  113. if (y + h >= (signed) self->bounds.height)
  114. h = self->bounds.height - y;
  115. r.x = x;
  116. r.y = y;
  117. r.width = w;
  118. r.height = h;
  119. comp->ops->set_bounds (comp, &r);
  120. if (!grub_video_have_common_points (region, &r))
  121. continue;
  122. /* Paint the child. */
  123. if (canvas_area_status == GRUB_VIDEO_AREA_ENABLED
  124. && grub_video_bounds_inside_region (&r, region))
  125. grub_video_set_area_status (GRUB_VIDEO_AREA_DISABLED);
  126. comp->ops->paint (comp, region);
  127. if (canvas_area_status == GRUB_VIDEO_AREA_ENABLED)
  128. grub_video_set_area_status (GRUB_VIDEO_AREA_ENABLED);
  129. }
  130. grub_gui_restore_viewport (&vpsave);
  131. }
  132. static void
  133. canvas_set_parent (void *vself, grub_gui_container_t parent)
  134. {
  135. grub_gui_canvas_t self = vself;
  136. self->parent = parent;
  137. }
  138. static grub_gui_container_t
  139. canvas_get_parent (void *vself)
  140. {
  141. grub_gui_canvas_t self = vself;
  142. return self->parent;
  143. }
  144. static void
  145. canvas_set_bounds (void *vself, const grub_video_rect_t *bounds)
  146. {
  147. grub_gui_canvas_t self = vself;
  148. self->bounds = *bounds;
  149. }
  150. static void
  151. canvas_get_bounds (void *vself, grub_video_rect_t *bounds)
  152. {
  153. grub_gui_canvas_t self = vself;
  154. *bounds = self->bounds;
  155. }
  156. static grub_err_t
  157. canvas_set_property (void *vself, const char *name, const char *value)
  158. {
  159. grub_gui_canvas_t self = vself;
  160. if (grub_strcmp (name, "id") == 0)
  161. {
  162. grub_free (self->id);
  163. if (value)
  164. {
  165. self->id = grub_strdup (value);
  166. if (! self->id)
  167. return grub_errno;
  168. }
  169. else
  170. self->id = 0;
  171. }
  172. return grub_errno;
  173. }
  174. static void
  175. canvas_add (void *vself, grub_gui_component_t comp)
  176. {
  177. grub_gui_canvas_t self = vself;
  178. struct component_node *node;
  179. node = grub_malloc (sizeof (*node));
  180. if (! node)
  181. return; /* Note: probably should handle the error. */
  182. node->component = comp;
  183. node->next = self->components.next;
  184. self->components.next = node;
  185. comp->ops->set_parent (comp, (grub_gui_container_t) self);
  186. }
  187. static void
  188. canvas_remove (void *vself, grub_gui_component_t comp)
  189. {
  190. grub_gui_canvas_t self = vself;
  191. struct component_node *cur;
  192. struct component_node *prev;
  193. prev = &self->components;
  194. for (cur = self->components.next; cur; prev = cur, cur = cur->next)
  195. {
  196. if (cur->component == comp)
  197. {
  198. /* Unlink 'cur' from the list. */
  199. prev->next = cur->next;
  200. /* Free the node's memory (but don't destroy the component). */
  201. grub_free (cur);
  202. /* Must not loop again, since 'cur' would be dereferenced! */
  203. return;
  204. }
  205. }
  206. }
  207. static void
  208. canvas_iterate_children (void *vself,
  209. grub_gui_component_callback cb, void *userdata)
  210. {
  211. grub_gui_canvas_t self = vself;
  212. struct component_node *cur;
  213. for (cur = self->components.next; cur; cur = cur->next)
  214. cb (cur->component, userdata);
  215. }
  216. static struct grub_gui_component_ops canvas_comp_ops =
  217. {
  218. .destroy = canvas_destroy,
  219. .get_id = canvas_get_id,
  220. .is_instance = canvas_is_instance,
  221. .paint = canvas_paint,
  222. .set_parent = canvas_set_parent,
  223. .get_parent = canvas_get_parent,
  224. .set_bounds = canvas_set_bounds,
  225. .get_bounds = canvas_get_bounds,
  226. .set_property = canvas_set_property
  227. };
  228. static struct grub_gui_container_ops canvas_ops =
  229. {
  230. .add = canvas_add,
  231. .remove = canvas_remove,
  232. .iterate_children = canvas_iterate_children
  233. };
  234. grub_gui_container_t
  235. grub_gui_canvas_new (void)
  236. {
  237. grub_gui_canvas_t canvas;
  238. canvas = grub_zalloc (sizeof (*canvas));
  239. if (! canvas)
  240. return 0;
  241. canvas->container.ops = &canvas_ops;
  242. canvas->container.component.ops = &canvas_comp_ops;
  243. return (grub_gui_container_t) canvas;
  244. }