From a6d038c543ba9ee197e844399bf5ffa582b1e7a8 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Wed, 11 Oct 2006 23:25:02 +0000 Subject: UTF-8 status bar component. svn path=/trunk/netsurf/; revision=2995 --- riscos/gui/status_bar.c | 608 ++++++++++++++++++++++++++++++++++++++++++++++++ riscos/gui/status_bar.h | 34 +++ 2 files changed, 642 insertions(+) create mode 100644 riscos/gui/status_bar.c create mode 100644 riscos/gui/status_bar.h (limited to 'riscos/gui') diff --git a/riscos/gui/status_bar.c b/riscos/gui/status_bar.c new file mode 100644 index 000000000..68971d161 --- /dev/null +++ b/riscos/gui/status_bar.c @@ -0,0 +1,608 @@ +/* + * 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 + * UTF8 status bar (implementation). + */ + +#include +#include +#include +#include +#include "oslib/colourtrans.h" +#include "oslib/os.h" +#include "oslib/wimp.h" +#include "oslib/wimpspriteop.h" +#include "netsurf/desktop/plotters.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/utf8.h" +#include "netsurf/utils/utils.h" +#include "netsurf/riscos/gui.h" +#include "netsurf/riscos/wimp.h" +#include "netsurf/riscos/wimp_event.h" +#include "netsurf/riscos/gui/progress_bar.h" +#include "netsurf/riscos/gui/status_bar.h" + +#define ICON_WIDGET 0 +#define WIDGET_WIDTH 12 +#define PROGRESS_WIDTH 160 + +struct status_bar { + wimp_w w; /**< status bar window handle */ + wimp_w parent; /**< parent window handle */ + char *text; /**< status bar text */ + char *local; /**< status bar text (local encoding) */ + struct progress_bar *pb; /**< progress bar */ + unsigned int scale; /**< current status bar scale */ + int width; /**< current status bar width */ + bool visible; /**< status bar is visible? */ +}; + +static char status_widget_text[] = "\0"; +static char status_widget_validation[] = "R5;Pptr_lr,8,6\0"; + +wimp_WINDOW(1) status_bar_definition = { + {0, 0, 1, 1}, + 0, + 0, + wimp_TOP, + wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | + wimp_WINDOW_FURNITURE_WINDOW | + wimp_WINDOW_IGNORE_XEXTENT, + wimp_COLOUR_BLACK, + 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, + {""}, + 1, + { + { + {0, 0, 1, 1}, + wimp_ICON_TEXT | wimp_ICON_INDIRECTED | + wimp_ICON_BORDER | wimp_ICON_FILLED | + (wimp_COLOUR_LIGHT_GREY << + wimp_ICON_BG_COLOUR_SHIFT) | + (wimp_BUTTON_CLICK_DRAG << + wimp_ICON_BUTTON_TYPE_SHIFT), + { + .indirected_text = { + status_widget_text, + status_widget_validation, + 1 + } + } + } + } +}; + +static void ro_gui_status_bar_open(wimp_open *open); +static bool ro_gui_status_bar_click(wimp_pointer *pointer); +static void ro_gui_status_bar_redraw(wimp_draw *redraw); +static void ro_gui_status_position_progress_bar(struct status_bar *sb); + + +/** + * Create a new status bar + * + * \param parent the window to contain the status bar + * \param width the proportional width to use (0...10,000) + */ +struct status_bar *ro_gui_status_bar_create(wimp_w parent, unsigned int width) { + struct status_bar *sb; + os_error *error; + + sb = calloc(1, sizeof(*sb)); + if (!sb) + return NULL; + + sb->pb = ro_gui_progress_bar_create(); + if (!sb->pb) + return NULL; + + error = xwimp_create_window((wimp_window *)&status_bar_definition, + &sb->w); + if (error) { + LOG(("xwimp_create_window: 0x%x: %s", + error->errnum, error->errmess)); + free(sb); + return NULL; + } + sb->parent = parent; + sb->scale = width; + sb->visible = true; + + ro_gui_wimp_event_set_user_data(sb->w, sb); + ro_gui_wimp_event_register_open_window(sb->w, + ro_gui_status_bar_open); + ro_gui_wimp_event_register_mouse_click(sb->w, + ro_gui_status_bar_click); + ro_gui_wimp_event_register_redraw_window(sb->w, + ro_gui_status_bar_redraw); + ro_gui_wimp_event_set_user_data(sb->w, sb); + ro_gui_wimp_event_set_help_prefix(sb->w, "HelpStatus"); + ro_gui_status_bar_resize(sb); + return sb; +} + + +/** + * Destroy a status bar and free all associated resources + * + * \param sb the status bar to destroy + */ +void ro_gui_status_bar_destroy(struct status_bar *sb) { + os_error *error; + assert(sb); + + ro_gui_wimp_event_finalise(sb->w); + error = xwimp_delete_window(sb->w); + if (error) { + LOG(("xwimp_delete_window: 0x%x:%s", + error->errnum, error->errmess)); + } + + free(sb); +} + + +/** + * Get the handle of the window that represents a status bar + * + * \param sb the status bar to get the window handle of + * \return the status bar's window handle + */ +wimp_w ro_gui_status_bar_get_window(struct status_bar *sb) { + assert(sb); + + return sb->w; +} + + +/** + * Get the proportional width the status bar is currently using + * + * \param sb the status bar to get the width of + * \return the status bar's width (0...10,000) + */ +unsigned int ro_gui_status_bar_get_width(struct status_bar *sb) { + assert(sb); + + return sb->scale; +} + + +/** + * Get the visibility status of the status bar + * + * \param sb the status bar to check the visiblity of + * \return whether the status bar is visible + */ +void ro_gui_status_bar_set_visible(struct status_bar *sb, bool visible) { + os_error *error; + + assert(sb); + + sb->visible = visible; + if (visible) { + ro_gui_status_bar_resize(sb); + } else { + error = xwimp_close_window(sb->w); + if (error) { + LOG(("xwimp_close_window: 0x%x:%s", + error->errnum, error->errmess)); + } + } +} + + +/** + * Get the visibility status of the status bar + * + * \param sb the status bar to check the visiblity of + * \return whether the status bar is visible + */ +bool ro_gui_status_bar_get_visible(struct status_bar *sb) { + assert(sb); + + return sb->visible; +} + + +/** + * Set the value of the progress bar + * + * \param pb the status bar to set the progress of + * \param value the value to use + */ +void ro_gui_status_bar_set_progress_value(struct status_bar *sb, + unsigned int value) { + + assert(sb); + + ro_gui_status_bar_set_progress_range(sb, + max(value, ro_gui_progress_bar_get_range(sb->pb))); + ro_gui_progress_bar_set_value(sb->pb, value); +} + + +/** + * Set the range of the progress bar + * + * \param pb the status bar to set the range of + * \param value the value to use, or 0 to turn off the progress bar + */ +void ro_gui_status_bar_set_progress_range(struct status_bar *sb, + unsigned int range) { + unsigned int old_range; + os_error *error; + + assert(sb); + + old_range = ro_gui_progress_bar_get_range(sb->pb); + ro_gui_progress_bar_set_range(sb->pb, range); + + LOG(("Ranges are %i vs %i", old_range, range)); + if ((old_range == 0) && (range != 0)) { + ro_gui_status_position_progress_bar(sb); + } else if ((old_range != 0) && (range == 0)) { + error = xwimp_close_window( + ro_gui_progress_bar_get_window(sb->pb)); + if (error) { + LOG(("xwimp_close_window: 0x%x:%s", + error->errnum, error->errmess)); + } + } +} + + +/** + * Set the icon for the progress bar + * + * \param pb the status bar to set the icon for + * \param icon the icon to use, or NULL for no icon + */ +void ro_gui_status_bar_set_progress_icon(struct status_bar *sb, + const char *icon) { + assert(sb); + + ro_gui_progress_bar_set_icon(sb->pb, icon); +} + + +/** + * Set the text to display in the status bar + * + * \param text the UTF8 text to display, or NULL for none + */ +void ro_gui_status_bar_set_text(struct status_bar *sb, const char *text) { + utf8_convert_ret ret; + + assert(sb); + + /* check for no change */ + if ((sb->text) && (!strcmp(text, sb->text))) + return; + + /* release the old text */ + if (sb->text) + free(sb->text); + sb->text = NULL; + if (sb->local) + free(sb->local); + sb->local = NULL; + + /* copy the text */ + sb->text = strdup(text); + if (!sb->text) + return; + + /* get local encoding */ + ret = utf8_to_local_encoding(text, 0, &(sb->local)); + if (ret != UTF8_CONVERT_OK) { + assert(ret != UTF8_CONVERT_BADENC); + LOG(("utf8_to_enc failed")); + free(sb->text); + sb->text = NULL; + return; + } + + /* redraw the window */ + xwimp_force_redraw(sb->w, 0, 0, sb->width - WIDGET_WIDTH, 65536); +} + + +/** + * Resize a status bar following a change in the dimensions of the + * parent window. + * + * \param sb the status bar to resize + */ +void ro_gui_status_bar_resize(struct status_bar *sb) { + int window_width, window_height; + int status_width, status_height; + int redraw_left, redraw_right; + wimp_window_state state; + os_error *error; + os_box extent; + + if (!sb) + return; + + /* get the window work area dimensions */ + state.w = sb->parent; + error = xwimp_get_window_state(&state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + window_width = state.visible.x1 - state.visible.x0; + window_height = state.visible.y1 - state.visible.y0; + + + /* recalculate the scaled width */ + status_width = (window_width * sb->scale) / 10000; + if (status_width < WIDGET_WIDTH) + status_width = WIDGET_WIDTH; + status_height = ro_get_hscroll_height(sb->parent); + + /* resize the status/resize icons */ + if (status_width != sb->width) { + /* update the window extent */ + extent.x0 = 0; + extent.y0 = 0; + extent.x1 = status_width; + extent.y1 = status_height - 4; + error = xwimp_set_extent(sb->w, &extent); + if (error) { + LOG(("xwimp_set_extent: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + + /* re-open the nested window */ + state.w = sb->w; + state.xscroll = 0; + state.yscroll = 0; + state.next = wimp_TOP; + state.visible.x0 = state.visible.x0; + state.visible.y1 = state.visible.y0 - 2; + state.visible.x1 = state.visible.x0 + status_width; + state.visible.y0 = state.visible.y1 - status_height + 4; + error = xwimp_open_window_nested((wimp_open *)&state, + sb->parent, + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_XORIGIN_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_YORIGIN_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_LS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_BS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_RS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_TS_EDGE_SHIFT); + if (error) { + LOG(("xwimp_open_window_nested: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + ro_gui_status_position_progress_bar(sb); + error = xwimp_resize_icon(sb->w, ICON_WIDGET, + status_width - WIDGET_WIDTH, 0, + status_width, status_height - 4); + if (error) { + LOG(("xwimp_resize_icon: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + + redraw_left = min(status_width, sb->width) - WIDGET_WIDTH - 2; + redraw_right = max(status_width, sb->width); + xwimp_force_redraw(sb->w, redraw_left, 0, + redraw_right, status_height); + sb->width = status_width; + } +} + + +/** + * Process a WIMP redraw request + * + * \param redraw the redraw request to process + */ +void ro_gui_status_bar_redraw(wimp_draw *redraw) { + + struct status_bar *sb; + os_error *error; + osbool more; + rufl_code code; + + sb = (struct status_bar *)ro_gui_wimp_event_get_user_data(redraw->w); + assert(sb); + + /* initialise the plotters */ + plot = ro_plotters; + ro_plot_set_scale(1.0); + ro_plot_origin_x = 0; + ro_plot_origin_y = 0; + + /* redraw the window */ + error = xwimp_redraw_window(redraw, &more); + if (error) { + LOG(("xwimp_redraw_window: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + while (more) { + /* redraw the status text */ + if (sb->local) { + error = xcolourtrans_set_font_colours(font_CURRENT, + 0xeeeeee00, 0x00000000, 14, 0, 0, 0); + if (error) { + LOG(("xcolourtrans_set_font_colours: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + code = rufl_paint(ro_gui_desktop_font_family, + ro_gui_desktop_font_style, + ro_gui_desktop_font_size, + sb->local, strlen(sb->local), + redraw->box.x0 + 6, redraw->box.y0 + 8, + rufl_BLEND_FONT); + if (code != rufl_OK) { + if (code == rufl_FONT_MANAGER_ERROR) + LOG(("rufl_FONT_MANAGER_ERROR: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess)); + else + LOG(("rufl_paint: 0x%x", code)); + } + } + + /* separate the widget from the text with a line */ + plot.fill((redraw->box.x0 + sb->width - WIDGET_WIDTH - 2) >> 1, + -redraw->box.y0 >> 1, + (redraw->box.x0 + sb->width - WIDGET_WIDTH) >> 1, + -redraw->box.y1 >> 1, + 0x00000000); + + error = xwimp_get_rectangle(redraw, &more); + if (error) { + LOG(("xwimp_get_rectangle: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + } +} + + +/** + * Process an mouse_click event for a status window. + * + * \param pointer details of the mouse click + */ +bool ro_gui_status_bar_click(wimp_pointer *pointer) { + wimp_drag drag; + os_error *error; + + switch (pointer->i) { + case ICON_WIDGET: + gui_current_drag_type = GUI_DRAG_STATUS_RESIZE; + drag.w = pointer->w; + drag.type = wimp_DRAG_SYSTEM_SIZE; + drag.initial.x0 = pointer->pos.x; + drag.initial.x1 = pointer->pos.x; + drag.initial.y0 = pointer->pos.y; + drag.initial.y1 = pointer->pos.y; + error = xwimp_drag_box(&drag); + if (error) { + LOG(("xwimp_drag_box: 0x%x: %s", + error->errnum, error->errmess)); + } + break; + } + return true; +} + + +/** + * Process an open_window request for a status window. + * + * \param open the request to process + */ +void ro_gui_status_bar_open(wimp_open *open) { + struct status_bar *sb; + int window_width, status_width; + wimp_window_state state; + os_error *error; + + /* get the parent width for scaling */ + sb = (struct status_bar *)ro_gui_wimp_event_get_user_data(open->w); + state.w = sb->parent; + error = xwimp_get_window_state(&state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + window_width = state.visible.x1 - state.visible.x0; + if (window_width == 0) + window_width = 1; + status_width = open->visible.x1 - open->visible.x0; + if (status_width <= 12) + status_width = 0; + + /* store the new size */ + sb->scale = (10000 * status_width) / window_width; + if (sb->scale > 10000) + sb->scale = 10000; + ro_gui_status_bar_resize(sb); +} + + +/** + * Reposition the progress component following a change in the + * dimension of the status window. + * + * \param sb the status bar to update + */ +void ro_gui_status_position_progress_bar(struct status_bar *sb) { + wimp_window_state state; + os_error *error; + + if (!sb) + return; + if (ro_gui_progress_bar_get_range(sb->pb) == 0) + return; + + /* get the window work area dimensions */ + state.w = sb->w; + error = xwimp_get_window_state(&state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess)); + return; + } + + /* re-open the nested window */ + state.w = ro_gui_progress_bar_get_window(sb->pb); + state.xscroll = 0; + state.yscroll = 0; + state.next = wimp_TOP; + state.visible.x0 = state.visible.x1 - PROGRESS_WIDTH; + state.visible.x1 -= WIDGET_WIDTH + 2; + error = xwimp_open_window_nested((wimp_open *)&state, + sb->w, + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_XORIGIN_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_YORIGIN_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_LS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_BS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_RS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT + << wimp_CHILD_TS_EDGE_SHIFT); + if (error) { + LOG(("xwimp_open_window: 0x%x: %s", + error->errnum, error->errmess)); + } +} diff --git a/riscos/gui/status_bar.h b/riscos/gui/status_bar.h new file mode 100644 index 000000000..b1c5baca4 --- /dev/null +++ b/riscos/gui/status_bar.h @@ -0,0 +1,34 @@ +/* + * 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 + * UTF8 status bar (interface). + */ + +#include + +#ifndef _NETSURF_RISCOS_STATUS_BAR_H_ +#define _NETSURF_RISCOS_STATUS_BAR_H_ + +struct status_bar; + +struct status_bar *ro_gui_status_bar_create(wimp_w parent, unsigned int width); +void ro_gui_status_bar_destroy(struct status_bar *sb); + +wimp_w ro_gui_status_bar_get_window(struct status_bar *sb); +unsigned int ro_gui_status_bar_get_width(struct status_bar *sb); +void ro_gui_status_bar_resize(struct status_bar *sb); +void ro_gui_status_bar_set_visible(struct status_bar *pb, bool visible); +bool ro_gui_status_bar_get_visible(struct status_bar *pb); +void ro_gui_status_bar_set_text(struct status_bar *pb, const char *text); +void ro_gui_status_bar_set_progress_value(struct status_bar *sb, + unsigned int value); +void ro_gui_status_bar_set_progress_range(struct status_bar *sb, + unsigned int range); +void ro_gui_status_bar_set_progress_icon(struct status_bar *sb, + const char *icon); +#endif -- cgit v1.2.3