gui_progress_bar.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /* gui_progress_bar.c - GUI progress bar component. */
  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/font.h>
  23. #include <grub/gui_string_util.h>
  24. #include <grub/gfxmenu_view.h>
  25. #include <grub/gfxwidgets.h>
  26. #include <grub/i18n.h>
  27. struct grub_gui_progress_bar
  28. {
  29. struct grub_gui_progress progress;
  30. grub_gui_container_t parent;
  31. grub_video_rect_t bounds;
  32. char *id;
  33. int visible;
  34. int start;
  35. int end;
  36. int value;
  37. int show_text;
  38. char *template;
  39. grub_font_t font;
  40. grub_gui_color_t text_color;
  41. grub_gui_color_t border_color;
  42. grub_gui_color_t bg_color;
  43. grub_gui_color_t fg_color;
  44. char *theme_dir;
  45. int need_to_recreate_pixmaps;
  46. int pixmapbar_available;
  47. char *bar_pattern;
  48. char *highlight_pattern;
  49. grub_gfxmenu_box_t bar_box;
  50. grub_gfxmenu_box_t highlight_box;
  51. };
  52. typedef struct grub_gui_progress_bar *grub_gui_progress_bar_t;
  53. static void
  54. progress_bar_destroy (void *vself)
  55. {
  56. grub_gui_progress_bar_t self = vself;
  57. grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
  58. grub_free (self);
  59. }
  60. static const char *
  61. progress_bar_get_id (void *vself)
  62. {
  63. grub_gui_progress_bar_t self = vself;
  64. return self->id;
  65. }
  66. static int
  67. progress_bar_is_instance (void *vself __attribute__((unused)), const char *type)
  68. {
  69. return grub_strcmp (type, "component") == 0;
  70. }
  71. static int
  72. check_pixmaps (grub_gui_progress_bar_t self)
  73. {
  74. if (!self->pixmapbar_available)
  75. return 0;
  76. if (self->need_to_recreate_pixmaps)
  77. {
  78. grub_gui_recreate_box (&self->bar_box,
  79. self->bar_pattern,
  80. self->theme_dir);
  81. grub_gui_recreate_box (&self->highlight_box,
  82. self->highlight_pattern,
  83. self->theme_dir);
  84. self->need_to_recreate_pixmaps = 0;
  85. }
  86. return (self->bar_box != 0 && self->highlight_box != 0);
  87. }
  88. static void
  89. draw_filled_rect_bar (grub_gui_progress_bar_t self)
  90. {
  91. /* Set the progress bar's frame. */
  92. grub_video_rect_t f;
  93. f.x = 1;
  94. f.y = 1;
  95. f.width = self->bounds.width - 2;
  96. f.height = self->bounds.height - 2;
  97. /* Border. */
  98. grub_video_fill_rect (grub_gui_map_color (self->border_color),
  99. f.x - 1, f.y - 1,
  100. f.width + 2, f.height + 2);
  101. /* Bar background. */
  102. int barwidth = (f.width
  103. * (self->value - self->start)
  104. / (self->end - self->start));
  105. grub_video_fill_rect (grub_gui_map_color (self->bg_color),
  106. f.x + barwidth, f.y,
  107. f.width - barwidth, f.height);
  108. /* Bar foreground. */
  109. grub_video_fill_rect (grub_gui_map_color (self->fg_color),
  110. f.x, f.y,
  111. barwidth, f.height);
  112. }
  113. static void
  114. draw_pixmap_bar (grub_gui_progress_bar_t self)
  115. {
  116. grub_gfxmenu_box_t bar = self->bar_box;
  117. grub_gfxmenu_box_t hl = self->highlight_box;
  118. int w = self->bounds.width;
  119. int h = self->bounds.height;
  120. int bar_l_pad = bar->get_left_pad (bar);
  121. int bar_r_pad = bar->get_right_pad (bar);
  122. int bar_t_pad = bar->get_top_pad (bar);
  123. int bar_b_pad = bar->get_bottom_pad (bar);
  124. int bar_h_pad = bar_l_pad + bar_r_pad;
  125. int bar_v_pad = bar_t_pad + bar_b_pad;
  126. int tracklen = w - bar_h_pad;
  127. int trackheight = h - bar_v_pad;
  128. int barwidth;
  129. bar->set_content_size (bar, tracklen, trackheight);
  130. barwidth = (tracklen * (self->value - self->start)
  131. / (self->end - self->start));
  132. hl->set_content_size (hl, barwidth, h - bar_v_pad);
  133. bar->draw (bar, 0, 0);
  134. hl->draw (hl, bar_l_pad, bar_t_pad);
  135. }
  136. static void
  137. draw_text (grub_gui_progress_bar_t self)
  138. {
  139. if (self->template)
  140. {
  141. grub_font_t font = self->font;
  142. grub_video_color_t text_color = grub_gui_map_color (self->text_color);
  143. int width = self->bounds.width;
  144. int height = self->bounds.height;
  145. char *text;
  146. text = grub_xasprintf (self->template,
  147. self->value > 0 ? self->value : -self->value);
  148. if (!text)
  149. {
  150. grub_print_error ();
  151. grub_errno = GRUB_ERR_NONE;
  152. return;
  153. }
  154. /* Center the text. */
  155. int text_width = grub_font_get_string_width (font, text);
  156. int x = (width - text_width) / 2;
  157. int y = ((height - grub_font_get_descent (font)) / 2
  158. + grub_font_get_ascent (font) / 2);
  159. grub_font_draw_string (text, font, text_color, x, y);
  160. }
  161. }
  162. static void
  163. progress_bar_paint (void *vself, const grub_video_rect_t *region)
  164. {
  165. grub_gui_progress_bar_t self = vself;
  166. grub_video_rect_t vpsave;
  167. if (! self->visible)
  168. return;
  169. if (!grub_video_have_common_points (region, &self->bounds))
  170. return;
  171. if (self->end == self->start)
  172. return;
  173. grub_gui_set_viewport (&self->bounds, &vpsave);
  174. if (check_pixmaps (self))
  175. draw_pixmap_bar (self);
  176. else
  177. draw_filled_rect_bar (self);
  178. draw_text (self);
  179. grub_gui_restore_viewport (&vpsave);
  180. }
  181. static void
  182. progress_bar_set_parent (void *vself, grub_gui_container_t parent)
  183. {
  184. grub_gui_progress_bar_t self = vself;
  185. self->parent = parent;
  186. }
  187. static grub_gui_container_t
  188. progress_bar_get_parent (void *vself)
  189. {
  190. grub_gui_progress_bar_t self = vself;
  191. return self->parent;
  192. }
  193. static void
  194. progress_bar_set_bounds (void *vself, const grub_video_rect_t *bounds)
  195. {
  196. grub_gui_progress_bar_t self = vself;
  197. self->bounds = *bounds;
  198. }
  199. static void
  200. progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds)
  201. {
  202. grub_gui_progress_bar_t self = vself;
  203. *bounds = self->bounds;
  204. }
  205. static void
  206. progress_bar_get_minimal_size (void *vself,
  207. unsigned *width, unsigned *height)
  208. {
  209. unsigned text_width = 0, text_height = 0;
  210. grub_gui_progress_bar_t self = vself;
  211. if (self->template)
  212. {
  213. text_width = grub_font_get_string_width (self->font, self->template);
  214. text_width += grub_font_get_string_width (self->font, "XXXXXXXXXX");
  215. text_height = grub_font_get_descent (self->font)
  216. + grub_font_get_ascent (self->font);
  217. }
  218. *width = 200;
  219. if (*width < text_width)
  220. *width = text_width;
  221. *height = 28;
  222. if (*height < text_height)
  223. *height = text_height;
  224. }
  225. static void
  226. progress_bar_set_state (void *vself, int visible, int start,
  227. int current, int end)
  228. {
  229. grub_gui_progress_bar_t self = vself;
  230. self->visible = visible;
  231. self->start = start;
  232. self->value = current;
  233. self->end = end;
  234. }
  235. static grub_err_t
  236. progress_bar_set_property (void *vself, const char *name, const char *value)
  237. {
  238. grub_gui_progress_bar_t self = vself;
  239. if (grub_strcmp (name, "text") == 0)
  240. {
  241. grub_free (self->template);
  242. if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_LONG@") == 0)
  243. value
  244. = _("The highlighted entry will be executed automatically in %ds.");
  245. else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_MIDDLE@") == 0)
  246. /* TRANSLATORS: 's' stands for seconds.
  247. It's a standalone timeout notification.
  248. Please use the short form in your language. */
  249. value = _("%ds remaining.");
  250. else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_SHORT@") == 0)
  251. /* TRANSLATORS: 's' stands for seconds.
  252. It's a standalone timeout notification.
  253. Please use the shortest form available in you language. */
  254. value = _("%ds");
  255. self->template = grub_strdup (value);
  256. }
  257. else if (grub_strcmp (name, "font") == 0)
  258. {
  259. self->font = grub_font_get (value);
  260. }
  261. else if (grub_strcmp (name, "text_color") == 0)
  262. {
  263. grub_gui_parse_color (value, &self->text_color);
  264. }
  265. else if (grub_strcmp (name, "border_color") == 0)
  266. {
  267. grub_gui_parse_color (value, &self->border_color);
  268. }
  269. else if (grub_strcmp (name, "bg_color") == 0)
  270. {
  271. grub_gui_parse_color (value, &self->bg_color);
  272. }
  273. else if (grub_strcmp (name, "fg_color") == 0)
  274. {
  275. grub_gui_parse_color (value, &self->fg_color);
  276. }
  277. else if (grub_strcmp (name, "bar_style") == 0)
  278. {
  279. self->need_to_recreate_pixmaps = 1;
  280. self->pixmapbar_available = 1;
  281. grub_free (self->bar_pattern);
  282. self->bar_pattern = value ? grub_strdup (value) : 0;
  283. }
  284. else if (grub_strcmp (name, "highlight_style") == 0)
  285. {
  286. self->need_to_recreate_pixmaps = 1;
  287. self->pixmapbar_available = 1;
  288. grub_free (self->highlight_pattern);
  289. self->highlight_pattern = value ? grub_strdup (value) : 0;
  290. }
  291. else if (grub_strcmp (name, "theme_dir") == 0)
  292. {
  293. self->need_to_recreate_pixmaps = 1;
  294. grub_free (self->theme_dir);
  295. self->theme_dir = value ? grub_strdup (value) : 0;
  296. }
  297. else if (grub_strcmp (name, "id") == 0)
  298. {
  299. grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
  300. grub_free (self->id);
  301. if (value)
  302. self->id = grub_strdup (value);
  303. else
  304. self->id = 0;
  305. /* if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID)
  306. == 0)*/
  307. grub_gfxmenu_timeout_register ((grub_gui_component_t) self,
  308. progress_bar_set_state);
  309. }
  310. return grub_errno;
  311. }
  312. static struct grub_gui_component_ops progress_bar_ops =
  313. {
  314. .destroy = progress_bar_destroy,
  315. .get_id = progress_bar_get_id,
  316. .is_instance = progress_bar_is_instance,
  317. .paint = progress_bar_paint,
  318. .set_parent = progress_bar_set_parent,
  319. .get_parent = progress_bar_get_parent,
  320. .set_bounds = progress_bar_set_bounds,
  321. .get_bounds = progress_bar_get_bounds,
  322. .get_minimal_size = progress_bar_get_minimal_size,
  323. .set_property = progress_bar_set_property
  324. };
  325. static struct grub_gui_progress_ops progress_bar_pb_ops =
  326. {
  327. .set_state = progress_bar_set_state
  328. };
  329. grub_gui_component_t
  330. grub_gui_progress_bar_new (void)
  331. {
  332. grub_gui_progress_bar_t self;
  333. self = grub_zalloc (sizeof (*self));
  334. if (! self)
  335. return 0;
  336. self->progress.ops = &progress_bar_pb_ops;
  337. self->progress.component.ops = &progress_bar_ops;
  338. self->visible = 1;
  339. self->font = grub_font_get ("Unknown Regular 16");
  340. grub_gui_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 };
  341. grub_gui_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 };
  342. grub_gui_color_t lightgray = { .red = 200, .green = 200, .blue = 200, .alpha = 255 };
  343. self->text_color = black;
  344. self->border_color = black;
  345. self->bg_color = gray;
  346. self->fg_color = lightgray;
  347. return (grub_gui_component_t) self;
  348. }