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