]> git.proxmox.com Git - grub2.git/blob - gfxmenu/gui_circular_progress.c
Compute list size automatically
[grub2.git] / gfxmenu / gui_circular_progress.c
1 /* gui_circular_process.c - GUI circular progress indicator 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/trig.h>
28
29 struct grub_gui_circular_progress
30 {
31 struct grub_gui_component comp;
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 num_ticks;
41 int start_angle;
42 int ticks_disappear;
43 char *theme_dir;
44 int need_to_load_pixmaps;
45 char *center_file;
46 char *tick_file;
47 struct grub_video_bitmap *center_bitmap;
48 struct grub_video_bitmap *tick_bitmap;
49 };
50
51 typedef struct grub_gui_circular_progress *circular_progress_t;
52
53 static void
54 circprog_destroy (void *vself)
55 {
56 circular_progress_t self = vself;
57 grub_free (self);
58 }
59
60 static const char *
61 circprog_get_id (void *vself)
62 {
63 circular_progress_t self = vself;
64 return self->id;
65 }
66
67 static int
68 circprog_is_instance (void *vself __attribute__((unused)), const char *type)
69 {
70 return grub_strcmp (type, "component") == 0;
71 }
72
73 static struct grub_video_bitmap *
74 load_bitmap (const char *dir, const char *file)
75 {
76 struct grub_video_bitmap *bitmap;
77 char *abspath;
78
79 /* Check arguments. */
80 if (! dir || ! file)
81 return 0;
82
83 /* Resolve to an absolute path. */
84 abspath = grub_resolve_relative_path (dir, file);
85 if (! abspath)
86 return 0;
87
88 /* Load the image. */
89 grub_errno = GRUB_ERR_NONE;
90 grub_video_bitmap_load (&bitmap, abspath);
91 grub_errno = GRUB_ERR_NONE;
92
93 grub_free (abspath);
94 return bitmap;
95 }
96
97 static int
98 check_pixmaps (circular_progress_t self)
99 {
100 if (self->need_to_load_pixmaps)
101 {
102 if (self->center_bitmap)
103 grub_video_bitmap_destroy (self->center_bitmap);
104 self->center_bitmap = load_bitmap (self->theme_dir, self->center_file);
105 self->tick_bitmap = load_bitmap (self->theme_dir, self->tick_file);
106 self->need_to_load_pixmaps = 0;
107 }
108
109 return (self->center_bitmap != 0 && self->tick_bitmap != 0);
110 }
111
112 static void
113 circprog_paint (void *vself, const grub_video_rect_t *region)
114 {
115 circular_progress_t self = vself;
116
117 if (! self->visible)
118 return;
119
120 if (!grub_video_have_common_points (region, &self->bounds))
121 return;
122
123 if (! check_pixmaps (self))
124 return;
125
126 grub_video_rect_t vpsave;
127 grub_gui_set_viewport (&self->bounds, &vpsave);
128
129 int width = self->bounds.width;
130 int height = self->bounds.height;
131 int center_width = grub_video_bitmap_get_width (self->center_bitmap);
132 int center_height = grub_video_bitmap_get_height (self->center_bitmap);
133 int tick_width = grub_video_bitmap_get_width (self->tick_bitmap);
134 int tick_height = grub_video_bitmap_get_height (self->tick_bitmap);
135 grub_video_blit_bitmap (self->center_bitmap, GRUB_VIDEO_BLIT_BLEND,
136 (width - center_width) / 2,
137 (height - center_height) / 2, 0, 0,
138 center_width, center_height);
139
140 int radius = width / 2 - tick_width / 2 - 1;
141 int nticks = (self->num_ticks
142 * (self->value - self->start)
143 / (self->end - self->start));
144 int tick_begin;
145 int tick_end;
146 /* Do ticks appear or disappear as the value approached the end? */
147 if (self->ticks_disappear)
148 {
149 tick_begin = nticks;
150 tick_end = self->num_ticks - 1;
151 }
152 else
153 {
154 tick_begin = 0;
155 tick_end = nticks - 1;
156 }
157
158 int i;
159 for (i = tick_begin; i < tick_end; i++)
160 {
161 int x;
162 int y;
163 int angle;
164
165 /* Calculate the location of the tick. */
166 angle = self->start_angle + i * GRUB_TRIG_ANGLE_MAX / self->num_ticks;
167 x = width / 2 + (grub_cos (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
168 y = height / 2 + (grub_sin (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
169
170 /* Adjust (x,y) so the tick is centered. */
171 x -= tick_width / 2;
172 y -= tick_height / 2;
173
174 /* Draw the tick. */
175 grub_video_blit_bitmap (self->tick_bitmap, GRUB_VIDEO_BLIT_BLEND,
176 x, y, 0, 0, tick_width, tick_height);
177 }
178
179 grub_gui_restore_viewport (&vpsave);
180 }
181
182 static void
183 circprog_set_parent (void *vself, grub_gui_container_t parent)
184 {
185 circular_progress_t self = vself;
186 self->parent = parent;
187 }
188
189 static grub_gui_container_t
190 circprog_get_parent (void *vself)
191 {
192 circular_progress_t self = vself;
193 return self->parent;
194 }
195
196 static void
197 circprog_set_bounds (void *vself, const grub_video_rect_t *bounds)
198 {
199 circular_progress_t self = vself;
200 self->bounds = *bounds;
201 }
202
203 static void
204 circprog_get_bounds (void *vself, grub_video_rect_t *bounds)
205 {
206 circular_progress_t self = vself;
207 *bounds = self->bounds;
208 }
209
210 static grub_err_t
211 circprog_set_property (void *vself, const char *name, const char *value)
212 {
213 circular_progress_t self = vself;
214 if (grub_strcmp (name, "value") == 0)
215 {
216 self->value = grub_strtol (value, 0, 10);
217 }
218 else if (grub_strcmp (name, "start") == 0)
219 {
220 self->start = grub_strtol (value, 0, 10);
221 }
222 else if (grub_strcmp (name, "end") == 0)
223 {
224 self->end = grub_strtol (value, 0, 10);
225 }
226 else if (grub_strcmp (name, "num_ticks") == 0)
227 {
228 self->num_ticks = grub_strtol (value, 0, 10);
229 }
230 else if (grub_strcmp (name, "start_angle") == 0)
231 {
232 self->start_angle = grub_strtol (value, 0, 10);
233 }
234 else if (grub_strcmp (name, "ticks_disappear") == 0)
235 {
236 self->ticks_disappear = grub_strcmp (value, "false") != 0;
237 }
238 else if (grub_strcmp (name, "center_bitmap") == 0)
239 {
240 self->need_to_load_pixmaps = 1;
241 grub_free (self->center_file);
242 self->center_file = value ? grub_strdup (value) : 0;
243 }
244 else if (grub_strcmp (name, "tick_bitmap") == 0)
245 {
246 self->need_to_load_pixmaps = 1;
247 grub_free (self->tick_file);
248 self->tick_file = value ? grub_strdup (value) : 0;
249 }
250 else if (grub_strcmp (name, "theme_dir") == 0)
251 {
252 self->need_to_load_pixmaps = 1;
253 grub_free (self->theme_dir);
254 self->theme_dir = value ? grub_strdup (value) : 0;
255 }
256 else if (grub_strcmp (name, "visible") == 0)
257 {
258 self->visible = grub_strcmp (value, "false") != 0;
259 }
260 else if (grub_strcmp (name, "id") == 0)
261 {
262 grub_free (self->id);
263 if (value)
264 self->id = grub_strdup (value);
265 else
266 self->id = 0;
267 }
268 return grub_errno;
269 }
270
271 static struct grub_gui_component_ops circprog_ops =
272 {
273 .destroy = circprog_destroy,
274 .get_id = circprog_get_id,
275 .is_instance = circprog_is_instance,
276 .paint = circprog_paint,
277 .set_parent = circprog_set_parent,
278 .get_parent = circprog_get_parent,
279 .set_bounds = circprog_set_bounds,
280 .get_bounds = circprog_get_bounds,
281 .set_property = circprog_set_property
282 };
283
284 grub_gui_component_t
285 grub_gui_circular_progress_new (void)
286 {
287 circular_progress_t self;
288 self = grub_zalloc (sizeof (*self));
289 if (! self)
290 return 0;
291 self->comp.ops = &circprog_ops;
292 self->visible = 1;
293 self->num_ticks = 64;
294 self->start_angle = -64;
295
296 return (grub_gui_component_t) self;
297 }