NetSurf
progress_bar.c
Go to the documentation of this file.
1/*
2 * Copyright 2006 Richard Wilson <info@tinct.net>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf 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; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/** \file
20 * Progress bar (implementation).
21 */
22
23#include <assert.h>
24#include <stdbool.h>
25#include <string.h>
26#include "swis.h"
27#include "oslib/colourtrans.h"
28#include "oslib/os.h"
29#include "oslib/osspriteop.h"
30#include "oslib/wimp.h"
31#include "oslib/wimpspriteop.h"
32
33#include "utils/log.h"
34#include "utils/utils.h"
35#include "netsurf/plotters.h"
36
37#include "riscos/gui.h"
38#include "riscos/tinct.h"
39#include "riscos/wimp_event.h"
41
42#define MARGIN 6
43
45 wimp_w w; /**< progress bar window handle */
46 unsigned int range; /**< progress bar range */
47 unsigned int value; /**< progress bar value */
48 char icon[13]; /**< current icon */
49 int offset; /**< progress bar rotation */
50 os_box visible; /**< progress bar position */
51 int icon_x0; /**< icon x0 */
52 int icon_y0; /**< icon y0 */
53 osspriteop_header *icon_img; /**< icon image */
54 bool animating; /**< progress bar is animating */
55 bool recalculate; /**< recalculation required */
56 int cur_width; /**< current calculated width */
57 int cur_height; /**< current calculated height */
58 bool icon_obscured; /**< icon is partially obscured */
59};
60
61static char progress_animation_sprite[] = "progress";
62static osspriteop_header *progress_icon;
63static unsigned int progress_width;
64static unsigned int progress_height;
65
66struct wimp_window_base progress_bar_definition = {
67 {0, 0, 1, 1},
68 0,
69 0,
70 wimp_TOP,
71 wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | wimp_WINDOW_NO_BOUNDS,
72 0xff,
73 wimp_COLOUR_LIGHT_GREY,
74 wimp_COLOUR_LIGHT_GREY,
75 wimp_COLOUR_VERY_LIGHT_GREY,
76 wimp_COLOUR_DARK_GREY,
77 wimp_COLOUR_MID_LIGHT_GREY,
78 wimp_COLOUR_CREAM,
79 wimp_WINDOW_NEVER3D | 0x16u /* RISC OS 5.03+ */,
80 {0, 0, 65535, 65535},
81 0,
82 0,
83 wimpspriteop_AREA,
84 1,
85 1,
86 {""},
87 0
88};
89
90
91static void ro_gui_progress_bar_calculate(struct progress_bar *pb, int width,
92 int height);
93static void ro_gui_progress_bar_redraw(wimp_draw *redraw);
94static void ro_gui_progress_bar_redraw_window(wimp_draw *redraw,
95 struct progress_bar *pb);
96static void ro_gui_progress_bar_animate(void *p);
97
98
99/**
100 * Initialise the progress bar
101 *
102 * \param icons the sprite area to use for icons
103 */
104void ro_gui_progress_bar_init(osspriteop_area *icons)
105{
106 const char *name = progress_animation_sprite;
107 os_error *error;
108
109 progress_bar_definition.sprite_area = icons;
110
111 progress_icon = NULL;
112 error = xosspriteop_select_sprite(osspriteop_USER_AREA,
113 progress_bar_definition.sprite_area,
114 (osspriteop_id) name, &progress_icon);
115 if (!error) {
116 xosspriteop_read_sprite_info(osspriteop_USER_AREA,
117 progress_bar_definition.sprite_area,
118 (osspriteop_id) name,
119 (int *) &progress_width, (int *) &progress_height,
120 0, 0);
121 }
122}
123
124
125/**
126 * Create a new progress bar
127 */
129{
130 struct progress_bar *pb;
131 os_error *error;
132
133 pb = calloc(1, sizeof(*pb));
134 if (!pb)
135 return NULL;
136
137 error = xwimp_create_window((wimp_window *)&progress_bar_definition,
138 &pb->w);
139 if (error) {
140 NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
141 error->errnum, error->errmess);
142 free(pb);
143 return NULL;
144 }
145
149 return pb;
150}
151
152
153/**
154 * Destroy a progress bar and free all associated resources
155 *
156 * \param pb the progress bar to destroy
157 */
159{
160 os_error *error;
161 assert(pb);
162
163 if (pb->animating) {
165 }
167 error = xwimp_delete_window(pb->w);
168 if (error) {
169 NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
170 error->errnum, error->errmess);
171 }
172
173 free(pb);
174}
175
176
177/**
178 * Get the handle of the window that represents a progress bar
179 *
180 * \param pb the progress bar to get the window handle of
181 * \return the progress bar's window handle
182 */
184{
185 assert(pb);
186
187 return pb->w;
188}
189
190
191/**
192 * Set the icon for a progress bar
193 *
194 * \param pb the progress bar to set the icon for
195 * \param icon the icon to use, or NULL for no icon
196 */
197void ro_gui_progress_bar_set_icon(struct progress_bar *pb, const char *icon)
198{
199 assert(pb);
200
201 if (!strcmp(icon, pb->icon))
202 return;
203 if (!icon)
204 pb->icon[0] = '\0';
205 else {
206 strncpy(pb->icon, icon, 12);
207 pb->icon[12] = '\0';
208 }
209 pb->recalculate = true;
210 xwimp_force_redraw(pb->w, 0, 0, 32, 32);
212}
213
214
215/**
216 * Set the value of a progress bar
217 *
218 * \param pb the progress bar to set the value for
219 * \param value the value to use
220 */
222{
223 assert(pb);
224
225 pb->value = value;
226 if (pb->value > pb->range)
227 pb->range = pb->value;
229}
230
231
232/**
233 * Get the value of a progress bar
234 *
235 * \param pb the progress bar to get the value of
236 * \return the current value
237 */
239{
240 assert(pb);
241
242 return pb->value;
243}
244
245
246/**
247 * Set the range of a progress bar
248 *
249 * \param pb the progress bar to set the range for
250 * \param range the range to use
251 */
253{
254 assert(pb);
255
256 pb->range = range;
257 if (pb->value > pb->range)
258 pb->value = pb->range;
260}
261
262
263/**
264 * Get the range of a progress bar
265 *
266 * \param pb the progress bar to get the range of
267 * \return the current range
268 */
270{
271 assert(pb);
272
273 return pb->range;
274}
275
276
277/**
278 * Update the progress bar to a new dimension.
279 *
280 * \param pb the progress bar to update
281 * \param width the new progress bar width
282 * \param height the new progress bar height
283 */
285{
286 wimp_draw redraw;
287 os_error *error;
288 osbool more;
289 os_box cur;
290
291 /* don't allow negative dimensions */
292 width = max(width, 0);
293 height = max(height, 0);
294
295 /* update the animation state */
296 if ((pb->value == 0) || (pb->value == pb->range)) {
297 if (pb->animating) {
299 }
300 pb->animating = false;
301 } else {
302 if (!pb->animating) {
304 }
305 pb->animating = true;
306 }
307
308 /* get old and new positions */
309 cur = pb->visible;
310 pb->recalculate = true;
312
313 /* see if the progress bar hasn't moved. we don't need to consider
314 * the left edge moving as this is handled by the icon setting
315 * function */
316 if (cur.x1 == pb->visible.x1)
317 return;
318
319 /* if size has decreased then we must force a redraw */
320 if (cur.x1 > pb->visible.x1) {
321 xwimp_force_redraw(pb->w, pb->visible.x1, pb->visible.y0,
322 cur.x1, pb->visible.y1);
323 return;
324 }
325
326 /* perform a minimal redraw update */
327 redraw.w = pb->w;
328 redraw.box = pb->visible;
329 redraw.box.x0 = cur.x1;
330 error = xwimp_update_window(&redraw, &more);
331 if (error) {
332 NSLOG(netsurf, INFO, "Error getting update window: 0x%x: %s",
333 error->errnum, error->errmess);
334 return;
335 }
336 if (more)
338}
339
340
341/**
342 * Process a WIMP redraw request
343 *
344 * \param redraw the redraw request to process
345 */
346void ro_gui_progress_bar_redraw(wimp_draw *redraw)
347{
348 struct progress_bar *pb;
349 os_error *error;
350 osbool more;
351
352 pb = (struct progress_bar *)ro_gui_wimp_event_get_user_data(redraw->w);
353 assert(pb);
354
355 error = xwimp_redraw_window(redraw, &more);
356 if (error) {
357 NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
358 error->errnum, error->errmess);
359 return;
360 }
361 if (more)
363}
364
365
366/**
367 * Animate the progress bar
368 *
369 * \param p the progress bar to animate
370 */
372{
373 wimp_draw redraw;
374 os_error *error;
375 osbool more;
376 struct progress_bar *pb = p;
377
378 if (!progress_icon)
379 return;
380 pb->offset -= 6;
381 if (pb->offset < 0)
382 pb->offset += progress_width * 2;
383
384 if (pb->animating) {
386 }
387
388 redraw.w = pb->w;
389 redraw.box = pb->visible;
390 error = xwimp_update_window(&redraw, &more);
391 if (error != NULL) {
392 NSLOG(netsurf, INFO, "Error getting update window: '%s'",
393 error->errmess);
394 return;
395 }
396 if (more)
398}
399
400
401/**
402 * Calculate the position of the progress bar
403 *
404 * \param pb the progress bar to recalculate
405 * \param width the width of the progress bar
406 * \param height the height of the progress bar
407 * \return the address of the associated icon, or NULL
408 */
410 int height)
411{
412 int icon_width, icon_height;
413 int icon_x0 = 0, icon_y0 = 0, progress_x0, progress_x1;
414 osspriteop_header *icon = NULL;
415 bool icon_redraw = false;
416
417 /* try to use cached values */
418 if ((!pb->recalculate) && (pb->cur_width == width) &&
419 (pb->cur_height == height))
420 return;
421
422 /* update cache status */
423 pb->recalculate = false;
424 pb->cur_width = width;
425 pb->cur_height = height;
426
427 /* get the window dimensions */
428 width -= MARGIN * 2;
429 icon_width = icon_height = 0;
430 progress_x0 = MARGIN;
431
432 /* get the icon information */
433 if (progress_bar_definition.sprite_area != wimpspriteop_AREA) {
434 int progress_ymid = height / 2;
435 os_error *error;
436 error = xosspriteop_read_sprite_info(osspriteop_USER_AREA,
437 progress_bar_definition.sprite_area,
438 (osspriteop_id)pb->icon,
439 &icon_width, &icon_height, 0, 0);
440 if (!error) {
441 error = xosspriteop_select_sprite(osspriteop_USER_AREA,
442 progress_bar_definition.sprite_area,
443 (osspriteop_id)pb->icon, &icon);
444 }
445 if (!error) {
446 progress_x0 += 32 + MARGIN;
447 width -= 32 + MARGIN;
448 icon_x0 = MARGIN + 16 - icon_width;
449 icon_y0 = progress_ymid - icon_height;
450 if (width < -MARGIN) {
451 icon_x0 += width + MARGIN;
452 icon_redraw = true;
453 }
454 }
455 }
456
457 /* update the icon */
458 if ((pb->icon_obscured) || (icon_redraw)) {
459 if (icon_x0 != pb->icon_x0)
460 xwimp_force_redraw(pb->w, 0, 0, 32 + MARGIN, 65536);
461 }
462 pb->icon_obscured = icon_redraw;
463
464 progress_x1 = progress_x0;
465 if ((pb->range > 0) && (width > 0))
466 progress_x1 += (width * pb->value) / pb->range;
467
468 pb->visible.x0 = progress_x0;
469 pb->visible.y0 = MARGIN;
470 pb->visible.x1 = progress_x1;
471 pb->visible.y1 = height - MARGIN;
472 pb->icon_x0 = icon_x0;
473 pb->icon_y0 = icon_y0;
474 pb->icon_img = icon;
475}
476
477
478/**
479 * Redraw a section of a progress bar window
480 *
481 * \param redraw the section of the window to redraw
482 * \param pb the progress bar to redraw
483 */
485 struct progress_bar *pb)
486{
487 osbool more = true;
488 struct rect clip;
489 int progress_ymid;
490 struct redraw_context ctx = {
491 .interactive = true,
492 .background_images = true,
493 .plot = &ro_plotters
494 };
495
496 /* initialise the plotters */
499
500 /* recalculate the progress bar */
501 ro_gui_progress_bar_calculate(pb, redraw->box.x1 - redraw->box.x0,
502 redraw->box.y1 - redraw->box.y0);
503 progress_ymid = redraw->box.y0 + pb->visible.y0 +
504 ((pb->visible.y1 - pb->visible.y0) >> 1);
505
506 /* redraw the window */
507 while (more) {
508 os_error *error;
509 if (pb->icon)
510 _swix(Tinct_PlotAlpha, _IN(2) | _IN(3) | _IN(4) | _IN(7),
511 pb->icon_img,
512 redraw->box.x0 + pb->icon_x0,
513 redraw->box.y0 + pb->icon_y0,
515 if (!pb->icon_obscured) {
516 clip.x0 = max(redraw->clip.x0,
517 redraw->box.x0 + pb->visible.x0) >> 1;
518 clip.y0 = -min(redraw->clip.y1,
519 redraw->box.y0 + pb->visible.y1) >> 1;
520 clip.x1 = min(redraw->clip.x1,
521 redraw->box.x0 + pb->visible.x1) >> 1;
522 clip.y1 = -max(redraw->clip.y0,
523 redraw->box.y0 + pb->visible.y0) >> 1;
524 if ((clip.x0 < clip.x1) && (clip.y0 < clip.y1)) {
525 if (progress_icon) {
526 ctx.plot->clip(&ctx, &clip);
527 _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
529 redraw->box.x0 - pb->offset,
530 progress_ymid - progress_height,
532 } else {
533 ctx.plot->rectangle(&ctx,
535 &clip);
536 }
537 }
538 }
539 error = xwimp_get_rectangle(redraw, &more);
540 if (error) {
541 NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
542 error->errnum, error->errmess);
543 return;
544 }
545 }
546}
Target independent plotting interface.
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
plot_style_t * plot_style_fill_red
Definition: plot_style.c:44
static char progress_animation_sprite[]
Definition: progress_bar.c:61
void ro_gui_progress_bar_set_icon(struct progress_bar *pb, const char *icon)
Set the icon for a progress bar.
Definition: progress_bar.c:197
static unsigned int progress_height
Definition: progress_bar.c:64
struct wimp_window_base progress_bar_definition
Definition: progress_bar.c:66
static void ro_gui_progress_bar_calculate(struct progress_bar *pb, int width, int height)
Calculate the position of the progress bar.
Definition: progress_bar.c:409
unsigned int ro_gui_progress_bar_get_range(struct progress_bar *pb)
Get the range of a progress bar.
Definition: progress_bar.c:269
unsigned int ro_gui_progress_bar_get_value(struct progress_bar *pb)
Get the value of a progress bar.
Definition: progress_bar.c:238
void ro_gui_progress_bar_update(struct progress_bar *pb, int width, int height)
Update the progress bar to a new dimension.
Definition: progress_bar.c:284
void ro_gui_progress_bar_set_value(struct progress_bar *pb, unsigned int value)
Set the value of a progress bar.
Definition: progress_bar.c:221
static void ro_gui_progress_bar_animate(void *p)
Animate the progress bar.
Definition: progress_bar.c:371
void ro_gui_progress_bar_destroy(struct progress_bar *pb)
Destroy a progress bar and free all associated resources.
Definition: progress_bar.c:158
wimp_w ro_gui_progress_bar_get_window(struct progress_bar *pb)
Get the handle of the window that represents a progress bar.
Definition: progress_bar.c:183
struct progress_bar * ro_gui_progress_bar_create(void)
Create a new progress bar.
Definition: progress_bar.c:128
void ro_gui_progress_bar_set_range(struct progress_bar *pb, unsigned int range)
Set the range of a progress bar.
Definition: progress_bar.c:252
#define MARGIN
Definition: progress_bar.c:42
static void ro_gui_progress_bar_redraw(wimp_draw *redraw)
Process a WIMP redraw request.
Definition: progress_bar.c:346
void ro_gui_progress_bar_init(osspriteop_area *icons)
Initialise the progress bar.
Definition: progress_bar.c:104
static osspriteop_header * progress_icon
Definition: progress_bar.c:62
static unsigned int progress_width
Definition: progress_bar.c:63
static void ro_gui_progress_bar_redraw_window(wimp_draw *redraw, struct progress_bar *pb)
Redraw a section of a progress bar window.
Definition: progress_bar.c:484
Progress bar (interface).
int width
Definition: gui.c:160
int height
Definition: gui.c:161
int ro_plot_origin_x
Definition: plotters.c:40
nserror riscos_schedule(int t, void(*callback)(void *p), void *p)
Schedule a callback.
Definition: schedule.c:93
int ro_plot_origin_y
Definition: plotters.c:41
const struct plotter_table ro_plotters
RISC OS plotter operation table.
Definition: plotters.c:727
Interface to utility string handling.
nserror(* rectangle)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *rectangle)
Plots a rectangle.
Definition: plotters.h:188
nserror(* clip)(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plotters.h:111
bool icon_obscured
icon is partially obscured
Definition: progress_bar.c:58
int offset
progress bar rotation
Definition: progress_bar.c:49
char icon[13]
current icon
Definition: progress_bar.c:48
bool recalculate
recalculation required
Definition: progress_bar.c:55
int icon_x0
icon x0
Definition: progress_bar.c:51
int icon_y0
icon y0
Definition: progress_bar.c:52
bool animating
progress bar is animating
Definition: progress_bar.c:54
int cur_width
current calculated width
Definition: progress_bar.c:56
unsigned int value
progress bar value
Definition: progress_bar.c:47
wimp_w w
progress bar window handle
Definition: progress_bar.c:45
unsigned int range
progress bar range
Definition: progress_bar.c:46
osspriteop_header * icon_img
icon image
Definition: progress_bar.c:53
os_box visible
progress bar position
Definition: progress_bar.c:50
int cur_height
current calculated height
Definition: progress_bar.c:57
Rectangle coordinates.
Definition: types.h:40
Redraw context.
Definition: plotters.h:51
const struct plotter_table * plot
Current plot operation table.
Definition: plotters.h:73
bool interactive
Redraw to show interactive features.
Definition: plotters.h:59
Tinct SWI numbers and flags for version 0.11.
#define tinct_ERROR_DIFFUSE
Definition: tinct.h:136
#define tinct_FILL_HORIZONTALLY
Definition: tinct.h:138
#define Tinct_PlotAlpha
Plots an alpha-blended sprite at the specified coordinates.
Definition: tinct.h:39
#define Tinct_Plot
Plots a sprite at the specified coordinates with a constant 0xff value for the alpha channel,...
Definition: tinct.h:64
Interface to a number of general purpose functionality.
#define min(x, y)
Definition: utils.h:46
#define max(x, y)
Definition: utils.h:50
bool ro_gui_wimp_event_register_redraw_window(wimp_w w, void(*callback)(wimp_draw *redraw))
Register a function to be called for all window redraw operations.
Definition: wimp_event.c:1507
void ro_gui_wimp_event_finalise(wimp_w w)
Free any resources associated with a window.
Definition: wimp_event.c:296
void * ro_gui_wimp_event_get_user_data(wimp_w w)
Gets the user data associated with a window.
Definition: wimp_event.c:486
bool ro_gui_wimp_event_set_user_data(wimp_w w, void *user)
Sets the user data associated with a window.
Definition: wimp_event.c:467
Automated RISC OS WIMP event handling (interface).
static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plot.c:357