]> git.proxmox.com Git - grub2.git/blob - gfxmenu/gui_circular_progress.c
Merge mainline into bidi
[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_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 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;
142 int tick_begin;
143 int tick_end;
144 if (self->end == self->start)
145 nticks = 0;
146 else
147 nticks = (self->num_ticks
148 * (self->value - self->start)
149 / (self->end - self->start));
150 /* Do ticks appear or disappear as the value approached the end? */
151 if (self->ticks_disappear)
152 {
153 tick_begin = nticks;
154 tick_end = self->num_ticks - 1;
155 }
156 else
157 {
158 tick_begin = 0;
159 tick_end = nticks - 1;
160 }
161
162 int i;
163 for (i = tick_begin; i < tick_end; i++)
164 {
165 int x;
166 int y;
167 int angle;
168
169 /* Calculate the location of the tick. */
170 angle = self->start_angle + i * GRUB_TRIG_ANGLE_MAX / self->num_ticks;
171 x = width / 2 + (grub_cos (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
172 y = height / 2 + (grub_sin (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
173
174 /* Adjust (x,y) so the tick is centered. */
175 x -= tick_width / 2;
176 y -= tick_height / 2;
177
178 /* Draw the tick. */
179 grub_video_blit_bitmap (self->tick_bitmap, GRUB_VIDEO_BLIT_BLEND,
180 x, y, 0, 0, tick_width, tick_height);
181 }
182
183 grub_gui_restore_viewport (&vpsave);
184 }
185
186 static void
187 circprog_set_parent (void *vself, grub_gui_container_t parent)
188 {
189 circular_progress_t self = vself;
190 self->parent = parent;
191 }
192
193 static grub_gui_container_t
194 circprog_get_parent (void *vself)
195 {
196 circular_progress_t self = vself;
197 return self->parent;
198 }
199
200 static void
201 circprog_set_bounds (void *vself, const grub_video_rect_t *bounds)
202 {
203 circular_progress_t self = vself;
204 self->bounds = *bounds;
205 }
206
207 static void
208 circprog_get_bounds (void *vself, grub_video_rect_t *bounds)
209 {
210 circular_progress_t self = vself;
211 *bounds = self->bounds;
212 }
213
214 static grub_err_t
215 circprog_set_property (void *vself, const char *name, const char *value)
216 {
217 circular_progress_t self = vself;
218 if (grub_strcmp (name, "num_ticks") == 0)
219 {
220 self->num_ticks = grub_strtol (value, 0, 10);
221 }
222 else if (grub_strcmp (name, "start_angle") == 0)
223 {
224 self->start_angle = grub_strtol (value, 0, 10);
225 }
226 else if (grub_strcmp (name, "ticks_disappear") == 0)
227 {
228 self->ticks_disappear = grub_strcmp (value, "false") != 0;
229 }
230 else if (grub_strcmp (name, "center_bitmap") == 0)
231 {
232 self->need_to_load_pixmaps = 1;
233 grub_free (self->center_file);
234 self->center_file = value ? grub_strdup (value) : 0;
235 }
236 else if (grub_strcmp (name, "tick_bitmap") == 0)
237 {
238 self->need_to_load_pixmaps = 1;
239 grub_free (self->tick_file);
240 self->tick_file = value ? grub_strdup (value) : 0;
241 }
242 else if (grub_strcmp (name, "theme_dir") == 0)
243 {
244 self->need_to_load_pixmaps = 1;
245 grub_free (self->theme_dir);
246 self->theme_dir = value ? grub_strdup (value) : 0;
247 }
248 else if (grub_strcmp (name, "id") == 0)
249 {
250 grub_free (self->id);
251 if (value)
252 self->id = grub_strdup (value);
253 else
254 self->id = 0;
255 }
256 return grub_errno;
257 }
258
259 static void
260 circprog_set_state (void *vself, int visible, int start,
261 int current, int end)
262 {
263 circular_progress_t self = vself;
264 self->visible = visible;
265 self->start = start;
266 self->value = current;
267 self->end = end;
268 }
269
270 static struct grub_gui_component_ops circprog_ops =
271 {
272 .destroy = circprog_destroy,
273 .get_id = circprog_get_id,
274 .is_instance = circprog_is_instance,
275 .paint = circprog_paint,
276 .set_parent = circprog_set_parent,
277 .get_parent = circprog_get_parent,
278 .set_bounds = circprog_set_bounds,
279 .get_bounds = circprog_get_bounds,
280 .set_property = circprog_set_property
281 };
282
283 static struct grub_gui_progress_ops circprog_prog_ops =
284 {
285 .set_state = circprog_set_state
286 };
287
288 grub_gui_component_t
289 grub_gui_circular_progress_new (void)
290 {
291 circular_progress_t self;
292 self = grub_zalloc (sizeof (*self));
293 if (! self)
294 return 0;
295 self->progress.ops = &circprog_prog_ops;
296 self->progress.component.ops = &circprog_ops;
297 self->visible = 1;
298 self->num_ticks = 64;
299 self->start_angle = -64;
300
301 return (grub_gui_component_t) self;
302 }