From e7da747f5f51a71254113552087e07d67efe0851 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Tue, 4 May 2004 22:23:44 +0000 Subject: [project @ 2004-05-04 22:21:37 by rjw] Revised GUI. svn path=/import/netsurf/; revision=823 --- riscos/toolbar.c | 696 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 696 insertions(+) create mode 100644 riscos/toolbar.c (limited to 'riscos/toolbar.c') diff --git a/riscos/toolbar.c b/riscos/toolbar.c new file mode 100644 index 000000000..b908c6c6d --- /dev/null +++ b/riscos/toolbar.c @@ -0,0 +1,696 @@ +/* + * 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 2004 Richard Wilson + */ + +/** \file + * Customisable toolbars (implementation). + */ + +#include +#include +#include +#include "oslib/os.h" +#include "oslib/osspriteop.h" +#include "oslib/wimp.h" +#include "oslib/wimpspriteop.h" +#include "netsurf/riscos/gui.h" +#include "netsurf/riscos/toolbar.h" +#include "netsurf/riscos/wimp.h" +#include "netsurf/utils/log.h" + +/* A basic window for the toolbar and status +*/ +static wimp_window empty_window = { + {0, 0, 16384, 16384}, + 0, + 0, + wimp_TOP, + wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE | wimp_WINDOW_AUTO_REDRAW | wimp_WINDOW_FURNITURE_WINDOW, + 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, + {0, 0, 16384, 16384}, + 0, + 0, + wimpspriteop_AREA, + 12, + 1, + {""}, + 0 +}; + +/* Holder for quick icon creation +*/ +static wimp_icon_create empty_icon; + +/* Shared URL validation +*/ +static char *url_validation = "Pptr_write\0"; +static char *resize_validation = "R1;Pptr_lr,8,6\0"; +static char *null_text_string = "\0"; + + +static struct toolbar *ro_toolbar_create_icons(struct toolbar *toolbar, osspriteop_area *sprite_area, + char *url_buffer, char *throbber_buffer); +static struct toolbar_icon *ro_toolbar_create_icon(osspriteop_area *sprite_area, char *sprite, unsigned int icon); +static struct toolbar_icon *ro_toolbar_create_separator(void); +static void ro_toolbar_destroy_icon(struct toolbar_icon *icon); +static void ro_toolbar_add_icon(struct toolbar *toolbar, struct toolbar_icon *icon); + +/** + * Creates a toolbar with a complete set of icons + * + * \param sprite_area the sprite area to read from + */ +struct toolbar *ro_toolbar_create(osspriteop_area *sprite_area, char *url_buffer, + char *status_buffer, char *throbber_buffer) { + struct toolbar *toolbar; + wimp_i icon_handle; + + /* Create a new toolbar + */ + toolbar = calloc(1, sizeof(struct toolbar)); + if (!toolbar) return NULL; + toolbar->update_pending = true; + toolbar->standard_buttons = true; + toolbar->url_bar = true; + toolbar->throbber = true; + toolbar->status_window = true; + toolbar->status_old_width = 0xffffffff; + + /* Load the toolbar icons + */ + if (sprite_area) { + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "back", ICON_TOOLBAR_BACK)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "forward", ICON_TOOLBAR_FORWARD)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "stop", ICON_TOOLBAR_STOP)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "reload", ICON_TOOLBAR_RELOAD)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_separator()); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "home", ICON_TOOLBAR_HOME)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "up", ICON_TOOLBAR_UP)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "search", ICON_TOOLBAR_SEARCH)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "history", ICON_TOOLBAR_HISTORY)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "scale", ICON_TOOLBAR_SCALE)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_separator()); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "mark", ICON_TOOLBAR_BOOKMARK)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "save", ICON_TOOLBAR_SAVE)); + ro_toolbar_add_icon(toolbar, ro_toolbar_create_icon(sprite_area, "print", ICON_TOOLBAR_PRINT)); + } + + /* Set the sprite area + */ + if (sprite_area) { + empty_window.sprite_area = sprite_area; + } else { + empty_window.sprite_area = 1; + } + + /* Create the basic windows + */ + empty_window.ymin = 36; + if (xwimp_create_window(&empty_window, &toolbar->status_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + + empty_window.ymin = 1; + if (xwimp_create_window(&empty_window, &toolbar->toolbar_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + + /* Create the status window icons. First the status text + */ + empty_icon.w = toolbar->status_handle; + empty_icon.icon.extent.x0 = 0; + empty_icon.icon.extent.y0 = 0; + empty_icon.icon.extent.x1 = 16384; + empty_icon.icon.extent.y1 = 36; + empty_icon.icon.flags = wimp_ICON_TEXT | (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | + wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED; + empty_icon.icon.data.indirected_text.text = status_buffer; + empty_icon.icon.data.indirected_text.validation = 0; + empty_icon.icon.data.indirected_text.size = 256; + if (xwimp_create_icon(&empty_icon, &icon_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + + /* And finally the status resize icon + */ + empty_icon.icon.flags = 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); + empty_icon.icon.extent.x1 = 0; + empty_icon.icon.data.indirected_text.text = null_text_string; + empty_icon.icon.data.indirected_text.validation = resize_validation; + empty_icon.icon.data.indirected_text.size = 1; + if (xwimp_create_icon(&empty_icon, &icon_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + + /* Create the icons + */ + toolbar = ro_toolbar_create_icons(toolbar, sprite_area, url_buffer, throbber_buffer); + + /* Return the toolbar + */ + return toolbar; +} + + +/** + * Creates a WIMP icons for the toolbar + * + * \param toolbar the toolbar to build from + * \param sprite_area the sprite area to plot sprites from + */ +static struct toolbar *ro_toolbar_create_icons(struct toolbar *toolbar, osspriteop_area *sprite_area, + char *url_buffer, char *throbber_buffer) { + int index; + struct toolbar_icon *cur_icon; + wimp_i icon_handle; + + /* Set the basic icon flags + */ + empty_icon.w = toolbar->toolbar_handle; + empty_icon.icon.extent.x0 = 0; + empty_icon.icon.extent.y0 = 0; + empty_icon.icon.extent.x1 = 0; + empty_icon.icon.extent.y1 = 0; + empty_icon.icon.data.indirected_text.text = null_text_string; + empty_icon.icon.data.indirected_text.size = 1; + empty_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE | wimp_ICON_INDIRECTED | + wimp_ICON_HCENTRED | wimp_ICON_VCENTRED | + (wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT); + + /* Create all the required icons + */ + for (index = 0; index < ICON_TOOLBAR_URL; index++) { + + /* Find an icon with the correct index and get the validation + */ + empty_icon.icon.data.indirected_text.validation = 0; + cur_icon = toolbar->icon; + while (cur_icon) { + if (cur_icon->icon_number == index) { + empty_icon.icon.data.indirected_text.validation = cur_icon->validation; + cur_icon = NULL; + } else { + cur_icon = cur_icon->next_icon; + } + } + + /* Create the icon and destroy the toolbar on failure + */ + if (xwimp_create_icon(&empty_icon, &icon_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + } + + /* Now the URL icon + */ + empty_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED | wimp_ICON_VCENTRED | + wimp_ICON_BORDER | wimp_ICON_FILLED | + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | + (wimp_BUTTON_WRITE_CLICK_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT); + empty_icon.icon.data.indirected_text.text = url_buffer; + empty_icon.icon.data.indirected_text.validation = url_validation; + empty_icon.icon.data.indirected_text.size = 256; + if (xwimp_create_icon(&empty_icon, &icon_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + + /* Now the throbber + */ + empty_icon.icon.flags = wimp_ICON_SPRITE | wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED | + wimp_ICON_VCENTRED; + empty_icon.icon.data.indirected_sprite.id = (osspriteop_id)throbber_buffer; + if (sprite_area) { + empty_icon.icon.data.indirected_sprite.area = sprite_area; + } else { + empty_icon.icon.data.indirected_sprite.area = 1; + } + empty_icon.icon.data.indirected_sprite.size = 12; + if (xwimp_create_icon(&empty_icon, &icon_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + + /* And finally the status resize icon + */ + empty_icon.w = toolbar->status_handle; + empty_icon.icon.flags = 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); + empty_icon.icon.data.indirected_text.text = null_text_string; + empty_icon.icon.data.indirected_text.validation = resize_validation; + empty_icon.icon.data.indirected_text.size = 1; + if (xwimp_create_icon(&empty_icon, &icon_handle)) { + ro_toolbar_destroy(toolbar); + return NULL; + } + + /* Success - return what we had + */ + return toolbar; + +} + + +/** + * Releases all icons and associated memory for a toolbar + * + * \param toolbar the toolbar to destroy + */ +void ro_toolbar_destroy(struct toolbar *toolbar) { + struct toolbar_icon *cur_icon; + struct toolbar_icon *next_icon; + + /* Paranoia + */ + if (toolbar == NULL) return; + + /* Free all our icons + */ + next_icon = toolbar->icon; + while((cur_icon = next_icon) != NULL) { + next_icon = cur_icon->next_icon; + ro_toolbar_destroy_icon(cur_icon); + } + + /* Destroy our windows + */ + if (toolbar->status_handle) xwimp_delete_window(toolbar->status_handle); + if (toolbar->toolbar_handle) xwimp_delete_window(toolbar->toolbar_handle); + + /* Destroy ourself + */ + free(toolbar); +} + + +/** + * Creates a toolbar icon + * + * \param sprite_area the sprite area to read from + * \param sprite the requested sprite + * \param icon the icon number + */ +static struct toolbar_icon *ro_toolbar_create_icon(osspriteop_area *sprite_area, char *sprite, unsigned int icon) { + struct toolbar_icon *current_icon; + int i; + int sprite_name_size = 0; + os_coord dimensions; + char name[16]; + osbool mask; + os_mode mode; + unsigned int validation_length; + + /* Check if the sprite exists + */ + for (i = 1; i <= sprite_area->sprite_count; i++) { + if (!xosspriteop_return_name(osspriteop_USER_AREA, + sprite_area, name, 16, i, &sprite_name_size)) { + name[sprite_name_size] = '\0'; + if (strncmp(name, sprite, sprite_name_size + 1) == 0) { + + /* Yes, a while loop would be better... + */ + goto ro_toolbar_create_icon_found; + } + } + } + + /* No icon found + */ + return NULL; +ro_toolbar_create_icon_found: + + /* Get the sprite details + */ + xosspriteop_read_sprite_info(osspriteop_USER_AREA, + sprite_area, (osspriteop_id)name, + &dimensions.x, &dimensions.y, &mask, &mode); + + /* Create an icon + */ + current_icon = (struct toolbar_icon *)calloc(1, sizeof(struct toolbar_icon)); + if (!current_icon) return NULL; + + /* Get the validation buffer for 'R5;S,p\0'. We always assume + there is a pushed variant as RISC OS happily ignores it if it doesn't + exist. + */ + validation_length = sprite_name_size * 2 + 8; + current_icon->validation = malloc(validation_length); + if (!current_icon->validation) { + free(current_icon); + return NULL; + } + sprintf(current_icon->validation, "R5;S%s,p%s", name, name); + + /* We want eig factors rather than pixels + */ + ro_convert_pixels_to_os_units(&dimensions, mode); + current_icon->width = dimensions.x; + current_icon->height = dimensions.y; + current_icon->icon_number = icon; + current_icon->available = true; + + /* Return our structure + */ + return current_icon; +} + + +/** + * Creates a toolbar separator icon + * + */ +static struct toolbar_icon *ro_toolbar_create_separator(void) { + struct toolbar_icon *current_icon; + + /* Create an icon + */ + current_icon = (struct toolbar_icon *)calloc(1, sizeof(struct toolbar_icon)); + if (!current_icon) return NULL; + + /* Set it as a 8 OS unit separator + */ + current_icon->icon_number = -1; + current_icon->available = true; + current_icon->width = 16; + + /* Return our structure + */ + return current_icon; +} + + +/** + * Removes all associated memory with a toolbar icon + * + * \param icon the icon to destroy + */ +static void ro_toolbar_destroy_icon(struct toolbar_icon *icon) { + if (!icon->icon_number >= 0) free(icon->validation); + free(icon); +} + + +/** + * Adds a toolbar icon to the toolbar + * + * \param toolbar the toolbar to add to + * \param icon the icon to add + */ +static void ro_toolbar_add_icon(struct toolbar *toolbar, struct toolbar_icon *icon) { + struct toolbar_icon *cur_icon; + + /* If we've been given a NULL due to a failure to create a toolbar + icon then we barf. + */ + if (icon == NULL) return; + + /* Traverse to the end of our linked list. + */ + cur_icon = toolbar->icon; + if (!cur_icon) { + + /* First icon cannot be a separator. Well, it can, but it's very unlikely + that this has arisen from anything other than the previous icons not + being present + */ + if (icon->icon_number < 0) return; + toolbar->icon = icon; + } else { + while (cur_icon->next_icon) cur_icon = cur_icon->next_icon; + + /* Two separators should not follow each other. + */ + if ((cur_icon->icon_number < 0) && (icon->icon_number < 0)) return; + cur_icon->next_icon = icon; + } + + /* Stop potential circular linking + */ + icon->next_icon = NULL; +} + + +/** + * Resizes the status bar height (toolsprites change) + * + * \param toolbar the toolbar to update + * \param height the new status bar height + */ +void ro_toolbar_resize_status(struct toolbar *toolbar, int height) { + os_box extent = { 0, 0, 0, 0 }; + + /* Paranoia + */ + if (toolbar == NULL) return; + + /* Check if we need to update + */ + if (toolbar->status_height != height) { + toolbar->status_height = height; + xwimp_resize_icon(toolbar->status_handle, ICON_STATUS_TEXT, + 0, 0, 16384, height - 2); + xwimp_force_redraw(toolbar->status_handle, 0, 0, 16384, height); + extent.x1 = 16384; + extent.y1 = height - 2; + xwimp_set_extent(toolbar->status_handle, &extent); + } +} + + +/** + * Reformat the contents of the toolbar/status window + * + * \param toolbar the toolbar to update + * \param width the new toolbar width + * \return non-zero if the toolbar height has changed + */ +int ro_toolbar_reformat(struct toolbar *toolbar, int width) { + wimp_caret caret; + unsigned int right_margin = 8; + int min_width = 0; + int status_width = 0; + int old_width; + + /* Paranoia + */ + if (toolbar == NULL) return 0; + + /* Check we aren't too small + */ + toolbar->width = width; + if (toolbar->throbber) min_width = toolbar->throbber_width + 8; + if (toolbar->standard_buttons) min_width += toolbar->icon_width; + if (toolbar->url_bar) min_width += 64; + if (width < min_width) width = min_width; + + /* Check if we need to update the icons + */ + if (toolbar->update_pending) { + toolbar->update_pending = 0; + toolbar->width_internal = 0xffffffff; + return ro_toolbar_update(toolbar); + } + + /* See if we need to move anything + */ + if (width != toolbar->width_internal) { + toolbar->width_internal = width; + + /* Move the throbber + */ + if ((toolbar->throbber) && (toolbar->throbber_width > 0)) { + xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_THROBBER, + width - toolbar->throbber_width - 8, + (toolbar->height - toolbar->throbber_height) / 2, + width - 8, + (toolbar->height + toolbar->throbber_height) / 2); + right_margin += toolbar->throbber_width + 8; + } + + /* Resize the URL bar + */ + if (toolbar->url_bar) { + xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_URL, + toolbar->icon_width, + (toolbar->height - 52) / 2, + width - right_margin, + (toolbar->height + 52) / 2); + + /* Handle the caret moving + */ + if (!xwimp_get_caret_position(&caret)) { + if ((caret.w == toolbar->toolbar_handle) && (caret.i == ICON_TOOLBAR_URL)) { + xwimp_set_caret_position(toolbar->toolbar_handle, ICON_TOOLBAR_URL, + caret.pos.x, caret.pos.y, -1, caret.index); + } + } + } + + /* Force a redraw + */ + xwimp_force_redraw(toolbar->toolbar_handle, toolbar->icon_width, 0, width, toolbar->height); + } + + /* Move the status resize icon + */ + if (toolbar->status_window) { + status_width = toolbar->width - toolbar->status_width; + if (status_width < 12) status_width = 12; + old_width = toolbar->status_old_width; + toolbar->status_old_width = status_width; + if (old_width != status_width) { + xwimp_resize_icon(toolbar->status_handle, ICON_STATUS_RESIZE, + status_width - 12, + 0, + status_width, + toolbar->status_height - 2); + xwimp_force_redraw(toolbar->status_handle, + status_width - 12, 0, status_width, toolbar->status_height - 2); + xwimp_force_redraw(toolbar->status_handle, + old_width - 12, 0, old_width, toolbar->status_height - 2); + } + } + + /* No change in height + */ + return 0; +} + + +/** + * Updates the icon states and positions. + * + * Any necessary redrawing is performed for the client. + * The client is responsible for resizing/opening/closing the window when necessary. + * + * \param toolbar the toolbar to update + * \return non-zero if the toolbar height has changed + */ +int ro_toolbar_update(struct toolbar *toolbar) { + wimp_caret caret; + struct toolbar_icon *cur_icon; + unsigned int toolbar_height = 0; + unsigned int icon_left = 4; + int return_status; + + /* Paranoia + */ + if (toolbar == NULL) return 0; + + /* Calculate the toolbar height (4 os unit border) + */ + if (toolbar->url_bar) toolbar_height = 52; + if ((toolbar->throbber) && (toolbar_height < (toolbar->throbber_height + 4))) { + toolbar_height = toolbar->throbber_height + 4; + } + + /* Calculate the maximum height of the icons + */ + if (toolbar->standard_buttons) { + cur_icon = toolbar->icon; + while (cur_icon) { + if ((cur_icon->available) && (toolbar_height < (cur_icon->height + 4))) { + toolbar_height = cur_icon->height + 4; + } + cur_icon = cur_icon->next_icon; + } + } + + /* Set our return status + */ + if (toolbar_height != 0) toolbar_height += 8; + return_status = (toolbar_height == toolbar->height); + toolbar->height = toolbar_height; + + /* Move our icons. Icons that are not avaiable are moved off the visible area. + */ + cur_icon = toolbar->icon; + while (cur_icon) { + if ((cur_icon->available) && (toolbar->standard_buttons)) { + if (cur_icon->icon_number >= 0) { + xwimp_resize_icon(toolbar->toolbar_handle, cur_icon->icon_number, + icon_left, + (toolbar_height - cur_icon->height) / 2, + icon_left + cur_icon->width, + (toolbar_height + cur_icon->height) / 2); + } + icon_left += cur_icon->width; + + } else { + if (cur_icon->icon_number >= 0) { + xwimp_resize_icon(toolbar->toolbar_handle, cur_icon->icon_number, + 0, + 1024 + toolbar_height, + cur_icon->width, + 1024 + toolbar_height + cur_icon->height); + } + } + cur_icon = cur_icon->next_icon; + } + + /* Make a 8 OS unit spacer between icons and URL bar + */ + if (icon_left != 4) icon_left += 8; + toolbar->icon_width = icon_left; + + /* Hide the URL bar if we should (and shade it to stop caret issues) + */ + if (!toolbar->url_bar) { + /* Handle losing the caret + */ + if (!xwimp_get_caret_position(&caret)) { + if ((caret.w == toolbar->toolbar_handle) && (caret.i == ICON_TOOLBAR_URL)) { + xwimp_set_caret_position(-1, 0, 0, 0, 0, 0); + } + } + xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_URL, + 0, + 1024 + toolbar_height, + 64, + 1024 + toolbar_height + 52); + ro_gui_set_icon_shaded_state(toolbar->toolbar_handle, ICON_TOOLBAR_URL, true); + } else { + ro_gui_set_icon_shaded_state(toolbar->toolbar_handle, ICON_TOOLBAR_URL, false); + } + + /* Hide the throbber if we should + */ + if (!toolbar->throbber) { + xwimp_resize_icon(toolbar->toolbar_handle, ICON_TOOLBAR_THROBBER, + 0, + 1024 + toolbar_height, + toolbar->throbber_width, + 1024 + toolbar_height + toolbar->throbber_height); + } + + /* Redraw the entire window + */ + ro_toolbar_reformat(toolbar, toolbar->width); + xwimp_force_redraw(toolbar->toolbar_handle, 0, 0, toolbar->width, toolbar_height); + + /* Update the toolbar height + */ + return return_status; +} -- cgit v1.2.3