From d2469b806c00b82a708cd14caec8c9e3d1286833 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Fri, 6 Oct 2006 13:42:59 +0000 Subject: Animated progress bar component. svn path=/trunk/netsurf/; revision=2983 --- riscos/gui/progress_bar.c | 477 ++++++++++++++++++++++++++++++++++++++++++++++ riscos/gui/progress_bar.h | 33 ++++ 2 files changed, 510 insertions(+) create mode 100644 riscos/gui/progress_bar.c create mode 100644 riscos/gui/progress_bar.h (limited to 'riscos') diff --git a/riscos/gui/progress_bar.c b/riscos/gui/progress_bar.c new file mode 100644 index 000000000..a343771a5 --- /dev/null +++ b/riscos/gui/progress_bar.c @@ -0,0 +1,477 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson + */ + +/** \file + * Progress bar (implementation). + */ + +#include +#include +#include +#include +#include "oslib/colourtrans.h" +#include "oslib/os.h" +#include "oslib/osspriteop.h" +#include "oslib/wimp.h" +#include "oslib/wimpspriteop.h" +#include "netsurf/desktop/plotters.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/utils.h" +#include "netsurf/riscos/gui.h" +#include "netsurf/riscos/tinct.h" +#include "netsurf/riscos/wimp_event.h" +#include "netsurf/riscos/gui/progress_bar.h" + +#define MARGIN 6 + +struct progress_bar { + wimp_w w; /**< progress bar window handle */ + unsigned int range; /**< progress bar range */ + unsigned int value; /**< progress bar value */ + char icon[13]; /**< current icon */ + int offset; /**< progress bar rotation */ + os_box visible; /**< progress bar position */ + int icon_x0; /**< icon x0 */ + int icon_y0; /**< icon y0 */ + osspriteop_header *icon_img; /**< icon image */ + bool animating; /**< progress bar is animating */ + bool recalculate; /**< recalculation required */ + int cur_width; /**< current calculated width */ + int cur_height; /**< current calculated height */ +}; + +struct wimp_window_base progress_bar_definition = { + {0, 0, 1, 1}, + 0, + 0, + wimp_TOP, + wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | wimp_WINDOW_NO_BOUNDS, + 0xff, + wimp_COLOUR_LIGHT_GREY, + wimp_COLOUR_LIGHT_GREY, + wimp_COLOUR_VERY_LIGHT_GREY, + wimp_COLOUR_DARK_GREY, + wimp_COLOUR_MID_LIGHT_GREY, + wimp_COLOUR_CREAM, + wimp_WINDOW_NEVER3D | 0x16u /* RISC OS 5.03+ */, + {0, 0, 65535, 65535}, + 0, + 0, + wimpspriteop_AREA, + 1, + 1, + {""}, + 0 +}; +static osspriteop_header *progress_icon; +static unsigned int progress_width; +static unsigned int progress_height; + + +static void ro_gui_progress_bar_update(struct progress_bar *pb); +static void ro_gui_progress_bar_calculate(struct progress_bar *pb, int width, + int height); +static void ro_gui_progress_bar_redraw(wimp_draw *redraw); +static void ro_gui_progress_bar_redraw_window(wimp_draw *redraw, + struct progress_bar *pb); +static void ro_gui_progress_bar_animate(void *p); + + +/** + * Initialise the progress bar + * + * \param icons the sprite area to use for icons + */ +void ro_gui_progress_bar_init(osspriteop_area *icons) { + os_error *error; + + progress_bar_definition.sprite_area = icons; + + progress_icon = NULL; + error = xosspriteop_select_sprite(osspriteop_USER_AREA, + progress_bar_definition.sprite_area, + (osspriteop_id)"progress", &progress_icon); + if (!error) { + xosspriteop_read_sprite_info(osspriteop_USER_AREA, + progress_bar_definition.sprite_area, + (osspriteop_id)"progress", + &progress_width, &progress_height, 0, 0); + } +} + + +/** + * Create a new progress bar + */ +struct progress_bar *ro_gui_progress_bar_create(void) { + struct progress_bar *pb; + os_error *error; + + pb = calloc(1, sizeof(*pb)); + if (!pb) + return NULL; + + error = xwimp_create_window((wimp_window *)&progress_bar_definition, + &pb->w); + if (error) { + LOG(("xwimp_create_window: 0x%x: %s", + error->errnum, error->errmess)); + free(pb); + return NULL; + } + + ro_gui_wimp_event_register_redraw_window(pb->w, + ro_gui_progress_bar_redraw); + ro_gui_wimp_event_set_user_data(pb->w, pb); + return pb; +} + + +/** + * Destroy a progress bar and free all associated resources + * + * \param pb the progress bar to destroy + */ +void ro_gui_progress_bar_destroy(struct progress_bar *pb) { + os_error *error; + assert(pb); + + if (pb->animating) + schedule_remove(ro_gui_progress_bar_animate, pb); + ro_gui_wimp_event_finalise(pb->w); + error = xwimp_delete_window(pb->w); + if (error) { + LOG(("xwimp_delete_window: 0x%x:%s", + error->errnum, error->errmess)); + } + + free(pb); +} + + +/** + * Get the handle of the window that represents a progress bar + * + * \param pb the progress bar to get the window handle of + * \return the progress bar's window handle + */ +wimp_w ro_gui_progress_bar_get_window(struct progress_bar *pb) { + assert(pb); + + return pb->w; +} + + +/** + * Set the icon for a progress bar + * + * \param pb the progress bar to set the icon for + * \param icon the icon to use, or NULL for no icon + */ +void ro_gui_progress_bar_set_icon(struct progress_bar *pb, const char *icon) { + assert(pb); + + if (!strcmp(icon, pb->icon)) + return; + if (!icon) + pb->icon[0] = '\0'; + else { + strncpy(pb->icon, icon, 12); + pb->icon[12] = '\0'; + } + pb->recalculate = true; + xwimp_force_redraw(pb->w, 0, 0, 32, 32); + ro_gui_progress_bar_update(pb); +} + + +/** + * Set the value of a progress bar + * + * \param pb the progress bar to set the value for + * \param value the value to use + */ +void ro_gui_progress_bar_set_value(struct progress_bar *pb, unsigned int value) { + assert(pb); + + pb->value = value; + if (pb->value > pb->range) + pb->range = pb->value; + ro_gui_progress_bar_update(pb); +} + + +/** + * Get the value of a progress bar + * + * \param pb the progress bar to get the value of + * \return the current value + */ +unsigned int ro_gui_progress_bar_get_value(struct progress_bar *pb) { + assert(pb); + + return pb->value; +} + + +/** + * Set the range of a progress bar + * + * \param pb the progress bar to set the range for + * \param range the range to use + */ +void ro_gui_progress_bar_set_range(struct progress_bar *pb, unsigned int range) { + assert(pb); + + pb->range = range; + if (pb->value > pb->range) + pb->value = pb->range; + ro_gui_progress_bar_update(pb); +} + + +/** + * Get the range of a progress bar + * + * \param pb the progress bar to get the range of + * \return the current range + */ +unsigned int ro_gui_progress_bar_get_range(struct progress_bar *pb) { + assert(pb); + + return pb->range; +} + + +/** + * Update the display to reflect new values + * + * \param pb the progress bar to update + */ +void ro_gui_progress_bar_update(struct progress_bar *pb) { + wimp_draw redraw; + os_error *error; + osbool more; + os_box cur; + + /* update the animation state */ + if ((pb->value == 0) || (pb->value == pb->range)) { + if (pb->animating) + schedule_remove(ro_gui_progress_bar_animate, pb); + pb->animating = false; + } else { + if (!pb->animating) + schedule(20, ro_gui_progress_bar_animate, pb); + pb->animating = true; + } + + /* get old and new positions */ + cur = pb->visible; + pb->recalculate = true; + ro_gui_progress_bar_calculate(pb, pb->cur_width, pb->cur_height); + + /* see if the progress bar hasn't moved. we don't need to consider + * the left edge moving as this is handled by the icon setting + * function */ + if (cur.x1 == pb->visible.x1) + return; + + /* if size has decreased then we must force a redraw */ + if (cur.x1 > pb->visible.x1) { + xwimp_force_redraw(pb->w, pb->visible.x1, pb->visible.y0, + cur.x1, pb->visible.y1); + return; + } + + /* perform a minimal redraw update */ + redraw.w = pb->w; + redraw.box = pb->visible; + redraw.box.x0 = cur.x1; + error = xwimp_update_window(&redraw, &more); + if (more) + ro_gui_progress_bar_redraw_window(&redraw, pb); +} + + +/** + * Process a WIMP redraw request + * + * \param redraw the redraw request to process + */ +void ro_gui_progress_bar_redraw(wimp_draw *redraw) { + + struct progress_bar *pb; + os_error *error; + osbool more; + + pb = (struct progress_bar *)ro_gui_wimp_event_get_user_data(redraw->w); + assert(pb); + + error = xwimp_redraw_window(redraw, &more); + if (error) { + LOG(("xwimp_redraw_window: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + if (more) + ro_gui_progress_bar_redraw_window(redraw, pb); +} + + +/** + * Animate the progress bar + * + * \param p the progress bar to animate + */ +void ro_gui_progress_bar_animate(void *p) { + wimp_draw redraw; + os_error *error; + osbool more; + struct progress_bar *pb = p; + + if (!progress_icon) + return; + pb->offset -= 6; + if (pb->offset < 0) + pb->offset += progress_width * 2; + + if (pb->animating) + schedule(20, ro_gui_progress_bar_animate, pb); + + redraw.w = pb->w; + redraw.box = pb->visible; + error = xwimp_update_window(&redraw, &more); + if (more) + ro_gui_progress_bar_redraw_window(&redraw, pb); +} + + +/** + * Calculate the position of the progress bar + * + * \param pb the progress bar to recalculate + * \param width the width of the progress bar + * \param height the height of the progress bar + * \return the address of the associated icon, or NULL + */ +void ro_gui_progress_bar_calculate(struct progress_bar *pb, int width, int height) { + os_error *error; + int icon_width, icon_height; + int icon_x0 = 0, icon_y0 = 0, progress_x0, progress_x1, progress_ymid = 0; + osspriteop_header *icon = NULL; + + /* try to use cached values */ + if ((!pb->recalculate) && (pb->cur_width == width) && + (pb->cur_height == height)) + return; + + /* update cache status */ + pb->recalculate = false; + pb->cur_width = width; + pb->cur_height = height; + + /* get the window dimensions */ + width -= MARGIN * 2; + icon_width = icon_height = 0; + progress_x0 = MARGIN; + + /* get the icon information */ + if (progress_bar_definition.sprite_area != wimpspriteop_AREA) { + progress_ymid = height / 2; + error = xosspriteop_read_sprite_info(osspriteop_USER_AREA, + progress_bar_definition.sprite_area, + (osspriteop_id)pb->icon, + &icon_width, &icon_height, 0, 0); + error = xosspriteop_select_sprite(osspriteop_USER_AREA, + progress_bar_definition.sprite_area, + (osspriteop_id)pb->icon, &icon); + if (!error) { + progress_x0 += 32; + width -= 32; + icon_x0 = 16 - icon_width; + icon_y0 = progress_ymid - icon_height; + } + } + progress_x1 = progress_x0; + if (pb->range > 0) + progress_x1 += (width * pb->value) / pb->range; + + pb->visible.x0 = progress_x0; + pb->visible.y0 = MARGIN; + pb->visible.x1 = progress_x1; + pb->visible.y1 = height - MARGIN; + pb->icon_x0 = icon_x0; + pb->icon_y0 = icon_y0; + pb->icon_img = icon; +} + + +/** + * Redraw a section of a progress bar window + * + * \param redraw the section of the window to redraw + * \param pb the progress bar to redraw + */ +void ro_gui_progress_bar_redraw_window(wimp_draw *redraw, struct progress_bar *pb) { + os_error *error; + osbool more = true; + int clip_x0 = 0, clip_y0 = 0, clip_x1 = 0, clip_y1 = 0; + int progress_ymid; + + /* initialise the plotters */ + plot = ro_plotters; + ro_plot_set_scale(1.0); + ro_plot_origin_x = 0; + ro_plot_origin_y = 0; + + /* recalculate the progress bar */ + ro_gui_progress_bar_calculate(pb, redraw->box.x1 - redraw->box.x0, + redraw->box.y1 - redraw->box.y0); + progress_ymid = redraw->box.y0 + pb->visible.y0 + + ((pb->visible.y1 - pb->visible.y0) >> 1); + + /* redraw the window */ + while (more) { + if (pb->icon) + _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7), + pb->icon_img, + redraw->box.x0 + pb->icon_x0, + redraw->box.y0 + pb->icon_y0, + tinct_ERROR_DIFFUSE); + if (progress_icon) { + clip_x0 = max(redraw->clip.x0, + redraw->box.x0 + pb->visible.x0) >> 1; + clip_y0 = -min(redraw->clip.y1, + redraw->box.y0 + pb->visible.y1) >> 1; + clip_x1 = min(redraw->clip.x1, + redraw->box.x0 + pb->visible.x1) >> 1; + clip_y1 = -max(redraw->clip.y0, + redraw->box.y0 + pb->visible.y0) >> 1; + if ((clip_x0 < clip_x1) && (clip_y0 < clip_y1)) { + plot.clip(clip_x0, clip_y0, + clip_x1, clip_y1); + _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7), + progress_icon, + redraw->box.x0 + pb->offset, + progress_ymid - progress_height, + tinct_FILL_HORIZONTALLY); + } + } else { + plot.fill(redraw->box.x0 + pb->visible.x0, + redraw->box.y0 + pb->visible.y0, + redraw->box.x0 + pb->visible.x1, + redraw->box.y0 + pb->visible.y1, + 0xff000000); + } + error = xwimp_get_rectangle(redraw, &more); + if (error) { + LOG(("xwimp_get_rectangle: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + } +} diff --git a/riscos/gui/progress_bar.h b/riscos/gui/progress_bar.h new file mode 100644 index 000000000..063326b82 --- /dev/null +++ b/riscos/gui/progress_bar.h @@ -0,0 +1,33 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson + */ + +/** \file + * Progress bar (interface). + */ + +#include +#include "oslib/osspriteop.h" +#include "oslib/wimp.h" + +#ifndef _NETSURF_RISCOS_PROGRESS_BAR_H_ +#define _NETSURF_RISCOS_PROGRESS_BAR_H_ + +struct progress_bar; + +void ro_gui_progress_bar_init(osspriteop_area *icons); + +struct progress_bar *ro_gui_progress_bar_create(void); +void ro_gui_progress_bar_destroy(struct progress_bar *pb); + +wimp_w ro_gui_progress_bar_get_window(struct progress_bar *pb); +void ro_gui_progress_bar_set_icon(struct progress_bar *pb, const char *icon); +void ro_gui_progress_bar_set_value(struct progress_bar *pb, unsigned int value); +unsigned int ro_gui_progress_bar_get_value(struct progress_bar *pb); +void ro_gui_progress_bar_set_range(struct progress_bar *pb, unsigned int range); +unsigned int ro_gui_progress_bar_get_range(struct progress_bar *pb); +void ro_gui_progress_bar_set_visible(struct progress_bar *pb, bool visible); +#endif -- cgit v1.2.3