diff options
Diffstat (limited to 'frontends/riscos/wimp.c')
-rw-r--r-- | frontends/riscos/wimp.c | 1134 |
1 files changed, 1134 insertions, 0 deletions
diff --git a/frontends/riscos/wimp.c b/frontends/riscos/wimp.c new file mode 100644 index 000000000..2579c672e --- /dev/null +++ b/frontends/riscos/wimp.c @@ -0,0 +1,1134 @@ +/* + * Copyright 2004, 2005 Richard Wilson <info@tinct.net> + * Copyright 2008 John Tytgat <joty@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * General RISC OS WIMP/OS library functions (implementation). + */ + +#include <assert.h> +#include <locale.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "oslib/colourtrans.h" +#include "oslib/os.h" +#include "oslib/osfile.h" +#include "oslib/wimp.h" +#include "oslib/wimpextend.h" +#include "oslib/wimpspriteop.h" + +#include "utils/log.h" +#include "utils/utf8.h" + +#include "riscos/gui.h" +#include "riscos/oslib_pre7.h" +#include "riscos/wimp.h" +#include "riscos/ucstables.h" + + +static void ro_gui_wimp_cache_furniture_sizes(wimp_w w); +static size_t ro_gui_strlen(const char *str); +static int ro_gui_strncmp(const char *s1, const char *s2, size_t len); + +static wimpextend_furniture_sizes furniture_sizes; +static wimp_w furniture_window = NULL; + +/** + * Gets the horizontal scrollbar height + * + * \param w the window to read (or NULL to read a cached value) + */ +int ro_get_hscroll_height(wimp_w w) +{ + ro_gui_wimp_cache_furniture_sizes(w); + return furniture_sizes.border_widths.y0; +} + + +/** + * Gets the vertical scrollbar width + * + * \param w the window to read (or NULL to read a cached value) + */ +int ro_get_vscroll_width(wimp_w w) +{ + ro_gui_wimp_cache_furniture_sizes(w); + return furniture_sizes.border_widths.x1; +} + + +/** + * Gets the title bar height + * + * \param w the window to read (or NULL to read a cached value) + */ +int ro_get_title_height(wimp_w w) +{ + ro_gui_wimp_cache_furniture_sizes(w); + return furniture_sizes.border_widths.y1; +} + +/** + * Caches window furniture information + * + * \param w the window to cache information from + * \return true on success, false on error (default values cached) + */ +void ro_gui_wimp_cache_furniture_sizes(wimp_w w) +{ + os_error *error; + + if (furniture_window == w) + return; + furniture_window = w; + furniture_sizes.w = w; + furniture_sizes.border_widths.y0 = 40; + furniture_sizes.border_widths.x1 = 40; + error = xwimpextend_get_furniture_sizes(&furniture_sizes); + if (error) { + LOG("xwimpextend_get_furniture_sizes: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } +} + + +/** + * Reads a modes EIG factors. + * + * \param[in] mode mode to read EIG factors for, or -1 for current + * \param[out] xeig The x eig value + * \param[out] yeig The y eig value + * \return true on success else false. + */ +bool ro_gui_wimp_read_eig_factors(os_mode mode, int *xeig, int *yeig) +{ + os_error *error; + + error = xos_read_mode_variable(mode, os_MODEVAR_XEIG_FACTOR, xeig, 0); + if (error) { + LOG("xos_read_mode_variable: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + return false; + } + error = xos_read_mode_variable(mode, os_MODEVAR_YEIG_FACTOR, yeig, 0); + if (error) { + LOG("xos_read_mode_variable: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + return false; + } + return true; +} + + +/** + * Converts the supplied os_coord from OS units to pixels. + * + * \param os_units values to convert + * \param mode mode to use EIG factors for, or -1 for current + */ +void ro_convert_os_units_to_pixels(os_coord *os_units, os_mode mode) +{ + int xeig = 1, yeig = 1; + + ro_gui_wimp_read_eig_factors(mode, &xeig, &yeig); + os_units->x = ((os_units->x + (1 << xeig) - 1) >> xeig); + os_units->y = ((os_units->y + (1 << yeig) - 1) >> yeig); +} + + +/** + * Converts the supplied os_coord from pixels to OS units. + * + * \param pixels values to convert + * \param mode mode to use EIG factors for, or -1 for current + */ +void ro_convert_pixels_to_os_units(os_coord *pixels, os_mode mode) +{ + int xeig = 1, yeig = 1; + + ro_gui_wimp_read_eig_factors(mode, &xeig, &yeig); + pixels->x = (pixels->x << xeig); + pixels->y = (pixels->y << yeig); +} + + +/** + * Redraws an icon + * + * \param w window handle + * \param i icon handle + */ + +#define ro_gui_redraw_icon(w, i) xwimp_set_icon_state(w, i, 0, 0) + + +/** + * Forces an icon to be redrawn entirely (ie not just updated). + * + * \param w window handle + * \param i icon handle + */ +void ro_gui_force_redraw_icon(wimp_w w, wimp_i i) +{ + wimp_icon_state ic; + os_error *error; + + /* Get the icon data + */ + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + error = xwimp_force_redraw(w, ic.icon.extent.x0, ic.icon.extent.y0, + ic.icon.extent.x1, ic.icon.extent.y1); + if (error) { + LOG("xwimp_force_redraw: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } +} + + +/** + * Read the contents of a text or sprite icon. + * + * \param w window handle + * \param i icon handle + * \return NUL terminated string in icon + * + * If the icon contains direct text then the returned data will + * be invalidated by the next call to this function. Therefore, + * all client calls to this function must either copy the string or + * ensure that this function is not called again until they are + * finished with the string data returned. + * + * \todo this doesn't do local encoding -> UTF-8 to match what is done in + * ro_gui_set_icon_string. + */ +const char *ro_gui_get_icon_string(wimp_w w, wimp_i i) +{ + static wimp_icon_state ic; + os_error *error; + char *itext; + + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return NULL; + } + itext = (ic.icon.flags & wimp_ICON_INDIRECTED) + ? ic.icon.data.indirected_text.text : ic.icon.data.text; + /* Guarantee NUL termination. */ + itext[ro_gui_strlen(itext)] = '\0'; + + return itext; +} + + +/** + * Set the contents of a text or sprite icon to a string. + * + * \param w window handle + * \param i icon handle + * \param text NUL terminated string (copied) + * \param is_utf8 When true, the given string is UTF-8 encoded and will be + * converted to local encoding currently used by the Wimp. When false, the + * given string is assumed to be in local encoding in use by the Wimp. + */ +void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text, bool is_utf8) +{ + wimp_caret caret; + wimp_icon_state ic; + os_error *error; + size_t old_len, new_len; + char *local_text = NULL; + const char *text_for_icon; + char *dst_text; + size_t dst_max_len; + unsigned int button_type; + + if (is_utf8) { + nserror err; + /* convert text to local encoding */ + err = utf8_to_local_encoding(text, 0, &local_text); + if (err != NSERROR_OK) { + /* A bad encoding should never happen, so assert this */ + assert(err != NSERROR_BAD_ENCODING); + LOG("utf8_to_enc failed"); + /* Paranoia */ + local_text = NULL; + } + text_for_icon = local_text ? local_text : text; + } + else + text_for_icon = text; + new_len = strlen(text_for_icon); + + /* get the icon data */ + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + goto exit; + } + + if (ic.icon.flags & wimp_ICON_INDIRECTED) { + dst_text = ic.icon.data.indirected_text.text; + dst_max_len = ic.icon.data.indirected_text.size; + } + else { + dst_text = ic.icon.data.text; + dst_max_len = sizeof(ic.icon.data.text); + } + old_len = ro_gui_strlen(dst_text); + assert(old_len < dst_max_len); + + /* check that the existing text is not the same as the updated text + * to stop flicker */ + if (dst_max_len) { + if (!ro_gui_strncmp(dst_text, text_for_icon, dst_max_len)) + goto exit; + + /* copy the text across */ + strncpy(dst_text, text_for_icon, dst_max_len - 1); + dst_text[dst_max_len - 1] = '\0'; + + /* handle the caret being in the icon */ + button_type = (ic.icon.flags & wimp_ICON_BUTTON_TYPE) + >> wimp_ICON_BUTTON_TYPE_SHIFT; + if ((button_type == wimp_BUTTON_WRITABLE) || + (button_type == wimp_BUTTON_WRITE_CLICK_DRAG)) { + error = xwimp_get_caret_position(&caret); + if (error) { + LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + goto exit; + } + if ((caret.w == w) && (caret.i == i)) { + if ((size_t)caret.index > new_len + || (size_t)caret.index == old_len) + caret.index = new_len; + error = xwimp_set_caret_position(w, i, caret.pos.x, + caret.pos.y, -1, caret.index); + if (error) { + LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + } + } + ro_gui_redraw_icon(w, i); + } + +exit: + free(local_text); +} + + +/** + * Set the contents of an icon to a number. + * + * \param w window handle + * \param i icon handle + * \param value value + */ +void ro_gui_set_icon_integer(wimp_w w, wimp_i i, int value) +{ + char buffer[20]; // Big enough for 64-bit int + + setlocale(LC_NUMERIC, ""); + + sprintf(buffer, "%d", value); + + setlocale(LC_NUMERIC, "C"); + + ro_gui_set_icon_string(w, i, buffer, true); +} + + +/** + * Set the contents of an icon to a number. + * + * \param w window handle + * \param i icon handle + * \param value value to use in icon. + * \param decimal_places The number of decimal places to use. + */ +void ro_gui_set_icon_decimal(wimp_w w, wimp_i i, int value, int decimal_places) +{ + char buffer[20]; // Big enough for 64-bit int + + setlocale(LC_NUMERIC, ""); + + switch (decimal_places) { + case 0: + sprintf(buffer, "%d", value); + break; + case 1: + sprintf(buffer, "%.1f", (float)value / 10); + break; + case 2: + sprintf(buffer, "%.2f", (float)value / 100); + break; + default: + assert(!"Unsupported decimal format"); + break; + } + + setlocale(LC_NUMERIC, "C"); + + ro_gui_set_icon_string(w, i, buffer, true); +} + + +/** + * Get the contents of an icon as a number. + * + * \param w window handle + * \param i icon handle + * \param decimal_places number of places to show. + * \return value used. + */ +int ro_gui_get_icon_decimal(wimp_w w, wimp_i i, int decimal_places) +{ + double value; + int multiple = 1; + + for (; decimal_places > 0; decimal_places--) + multiple *= 10; + + setlocale(LC_NUMERIC, ""); + + value = atof(ro_gui_get_icon_string(w, i)) * multiple; + + setlocale(LC_NUMERIC, "C"); + + return (int)value; +} + + +/** + * Set the selected state of an icon. + * + * \param w window handle + * \param i icon handle + * \param state selected state + */ +void ro_gui_set_icon_selected_state(wimp_w w, wimp_i i, bool state) +{ + os_error *error; + if (ro_gui_get_icon_selected_state(w, i) == state) return; + error = xwimp_set_icon_state(w, i, + (state ? wimp_ICON_SELECTED : 0), wimp_ICON_SELECTED); + if (error) { + LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } +} + +/** + * Gets the selected state of an icon. + * + * \param w window handle + * \param i icon handle + */ +bool ro_gui_get_icon_selected_state(wimp_w w, wimp_i i) +{ + os_error *error; + wimp_icon_state ic; + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } + return ((ic.icon.flags & wimp_ICON_SELECTED) != 0); +} + + +/** + * Set the shaded state of an icon. + * + * \param w window handle + * \param i icon handle + * \param state shaded state + */ +void ro_gui_set_icon_shaded_state(wimp_w w, wimp_i i, bool state) +{ + wimp_caret caret; + os_error *error; + + /* update the state */ + if (ro_gui_get_icon_shaded_state(w, i) == state) + return; + error = xwimp_set_icon_state(w, i, + (state ? wimp_ICON_SHADED : 0), wimp_ICON_SHADED); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + if (!state) + return; + + /* ensure the caret is not in a shaded icon */ + error = xwimp_get_caret_position(&caret); + if (error) { + LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + if ((caret.w != w) || (caret.i != i)) + return; + /* move the caret to the first avaiable writable */ + if (ro_gui_set_caret_first(w)) + return; + /* lose the caret */ + error = xwimp_set_caret_position((wimp_w)-1, (wimp_i)-1, -1, -1, -1, -1); + if (error) { + LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } +} + + +/** + * Gets the shaded state of an icon. + * + * \param w window handle + * \param i icon handle + */ +bool ro_gui_get_icon_shaded_state(wimp_w w, wimp_i i) +{ + wimp_icon_state ic; + ic.w = w; + ic.i = i; + xwimp_get_icon_state(&ic); + return (ic.icon.flags & wimp_ICON_SHADED) != 0; +} + + +/** + * Set the deleted state of an icon. + * + * \param w window handle + * \param i icon handle + * \param state shaded state + */ +void ro_gui_set_icon_deleted_state(wimp_w w, wimp_i i, bool state) +{ + wimp_caret caret; + os_error *error; + + /* update the state */ + if (ro_gui_get_icon_deleted_state(w, i) == state) + return; + error = xwimp_set_icon_state(w, i, + (state ? wimp_ICON_DELETED : 0), wimp_ICON_DELETED); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + if (!state) + return; + + /* ensure the caret is not in a shaded icon */ + error = xwimp_get_caret_position(&caret); + if (error) { + LOG("xwimp_get_caret_position: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + if ((caret.w != w) || (caret.i != i)) + return; + /* move the caret to the first avaiable writable */ + if (ro_gui_set_caret_first(w)) + return; + /* lose the caret */ + error = xwimp_set_caret_position((wimp_w)-1, (wimp_i)-1, -1, -1, -1, -1); + if (error) { + LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } +} + + +/** + * Gets the deleted state of an icon. + * + * \param w window handle + * \param i icon handle + */ +bool ro_gui_get_icon_deleted_state(wimp_w w, wimp_i i) +{ + wimp_icon_state ic; + ic.w = w; + ic.i = i; + xwimp_get_icon_state(&ic); + return (ic.icon.flags & wimp_ICON_DELETED) != 0; +} + + +/** + * Set the button type of an icon. + * + * \param w window handle + * \param i icon handle + * \param type button type + */ +void ro_gui_set_icon_button_type(wimp_w w, wimp_i i, int type) +{ + os_error *error; + error = xwimp_set_icon_state(w, i, wimp_ICON_BUTTON_TYPE, + (type << wimp_ICON_BUTTON_TYPE_SHIFT)); + if (error) { + LOG("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } +} + + +/** + * Set an icon's sprite + * + * \param w window handle + * \param i icon handle + * \param area sprite area containing sprite + * \param name name of sprite in area (in local encoding) + */ +void ro_gui_set_icon_sprite(wimp_w w, wimp_i i, osspriteop_area *area, + const char *name) +{ + wimp_icon_state ic; + os_error *error; + + /* get the icon data */ + ic.w = w; + ic.i = i; + error = xwimp_get_icon_state(&ic); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + + /* copy the name across */ + if (ic.icon.data.indirected_text.size) { + strncpy(ic.icon.data.indirected_text.text, name, + (unsigned int)ic.icon.data.indirected_text.size - 1); + ic.icon.data.indirected_text.text[ + ic.icon.data.indirected_text.size - 1] = '\0'; + } + + ic.icon.data.indirected_sprite.area = area; + + ro_gui_redraw_icon(w, i); +} + + +/** + * Set a window title + * + * \param w window handle + * \param text new title (copied) + */ +void ro_gui_set_window_title(wimp_w w, const char *text) +{ + wimp_window_info_base window; + os_error *error; + char *title_local_enc; + nserror err; + + /* Get the window details + */ + window.w = w; + error = xwimp_get_window_info_header_only((wimp_window_info *)&window); + if (error) { + LOG("xwimp_get_window_info: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + + /* convert text to local encoding */ + err = utf8_to_local_encoding(text, 0, &title_local_enc); + if (err != NSERROR_OK) { + /* A bad encoding should never happen, + * so assert this */ + assert(err != NSERROR_BAD_ENCODING); + LOG("utf8_to_enc failed"); + return; + } + + /* Set the title string + */ + strncpy(window.title_data.indirected_text.text, title_local_enc, + (unsigned int)window.title_data.indirected_text.size + - 1); + window.title_data.indirected_text.text[ + window.title_data.indirected_text.size - 1] = '\0'; + + /* Redraw accordingly + */ + error = xwimp_force_redraw_title(w); + if (error) { + LOG("xwimp_force_redraw_title: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + + free(title_local_enc); +} + + +/** + * Places the caret in the first available icon + * + * \param w the window to place the caret in + * \return true if the caret was placed, false otherwise + */ +bool ro_gui_set_caret_first(wimp_w w) +{ + int icon, b; + wimp_window_state win_state; + wimp_window_info_base window; + wimp_icon_state state; + os_error *error; + + /* check the window is open */ + win_state.w = w; + error = xwimp_get_window_state(&win_state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } + if (!(win_state.flags & wimp_WINDOW_OPEN)) + return false; + + /* get the window details for the icon count */ + window.w = w; + error = xwimp_get_window_info_header_only((wimp_window_info *)&window); + if (error) { + LOG("xwimp_get_window_info: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } + + /* work through all the icons */ + state.w = w; + for (icon = 0; icon < window.icon_count; icon++) { + state.i = icon; + error = xwimp_get_icon_state(&state); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } + + /* ignore if it's shaded or not writable */ + if (state.icon.flags & wimp_ICON_SHADED) + continue; + b = (state.icon.flags >> wimp_ICON_BUTTON_TYPE_SHIFT) & 0xf; + if ((b != wimp_BUTTON_WRITE_CLICK_DRAG) && + (b != wimp_BUTTON_WRITABLE)) + continue; + + /* move the caret */ + error = xwimp_set_caret_position(w, icon, 0, 0, -1, + strlen(state.icon.data.indirected_text.text)); + if (error) { + LOG("xwimp_set_caret_position: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + } + return true; + } + return false; +} + + +/** + * Load a sprite file into memory. + * + * \param pathname file to load + * \return sprite area, or 0 on memory exhaustion or error and error reported + */ + +osspriteop_area *ro_gui_load_sprite_file(const char *pathname) +{ + int len; + fileswitch_object_type obj_type; + osspriteop_area *area; + os_error *error; + + error = xosfile_read_stamped_no_path(pathname, + &obj_type, 0, 0, &len, 0, 0); + if (error) { + LOG("xosfile_read_stamped_no_path: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + return 0; + } + if (obj_type != fileswitch_IS_FILE) { + ro_warn_user("FileError", pathname); + return 0; + } + + area = malloc(len + 4); + if (!area) { + ro_warn_user("NoMemory", 0); + return 0; + } + + area->size = len + 4; + area->sprite_count = 0; + area->first = 16; + area->used = 16; + + error = xosspriteop_load_sprite_file(osspriteop_USER_AREA, + area, pathname); + if (error) { + LOG("xosspriteop_load_sprite_file: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + free(area); + return 0; + } + + return area; +} + + +/** + * Check if a sprite is present in the Wimp sprite pool. + * + * \param sprite name of sprite + * \return true if the sprite is present + */ + +bool ro_gui_wimp_sprite_exists(const char *sprite) +{ + static char last_sprite_found[16]; + os_error *error; + + /* make repeated calls fast */ + if (!strncmp(sprite, last_sprite_found, sizeof(last_sprite_found))) + return true; + + /* fallback if not known to exist */ + error = xwimpspriteop_select_sprite(sprite, 0); + if (error) { + if (error->errnum != error_SPRITE_OP_DOESNT_EXIST) { + LOG("xwimpspriteop_select_sprite: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + } + return false; + } + snprintf(last_sprite_found, sizeof(last_sprite_found), sprite); + return true; +} + + +/** + * Locate a sprite in the Wimp sprite pool, returning a pointer to it. + * + * \param name sprite name + * \param sprite receives pointer to sprite if found + * \return error ptr iff not found + */ + +os_error *ro_gui_wimp_get_sprite(const char *name, osspriteop_header **sprite) +{ + osspriteop_area *rom_base, *ram_base; + os_error *error; + + error = xwimp_base_of_sprites(&rom_base, &ram_base); + if (error) return error; + + error = xosspriteop_select_sprite(osspriteop_USER_AREA, + ram_base, (osspriteop_id)name, sprite); + + if (error && error->errnum == error_SPRITE_OP_DOESNT_EXIST) + error = xosspriteop_select_sprite(osspriteop_USER_AREA, + rom_base, (osspriteop_id)name, sprite); + + return error; +} + + +/** + * Get the dimensions of a sprite + * + * \param *area The sprite area to use. + * \param *sprite Pointer to the sprite name. + * \param *width Return the sprite width. + * \param *height Return the sprite height. + * \return true if successful; else false. + */ + +bool ro_gui_wimp_get_sprite_dimensions(osspriteop_area *area, char *sprite, + int *width, int *height) +{ + os_error *error = NULL; + os_mode mode; + os_coord dimensions; + + dimensions.x = 0; + dimensions.y = 0; + + if (area != (osspriteop_area *) -1) + error = xosspriteop_read_sprite_info(osspriteop_USER_AREA, + area, (osspriteop_id) sprite, + &dimensions.x, &dimensions.y, 0, &mode); + + if (error != NULL || area == (osspriteop_area *) -1) + error = xwimpspriteop_read_sprite_info(sprite, + &dimensions.x, &dimensions.y, 0, &mode); + + if (error == NULL) { + ro_convert_pixels_to_os_units(&dimensions, mode); + if (width != NULL) + *width = dimensions.x; + if (height != NULL) + *height = dimensions.y; + } else if (error->errnum != error_SPRITE_OP_DOESNT_EXIST) { + LOG("xosspriteop_read_sprite_info: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + return false; + } + + return true; +} + + +/** + * Performs simple user redraw for a window. + * + * \param redraw wimp draw + * \param user_fill whether to fill the redraw area + * \param user_colour the colour to use when filling + */ + +void ro_gui_user_redraw(wimp_draw *redraw, bool user_fill, + os_colour user_colour) +{ + os_error *error; + osbool more; + + error = xwimp_redraw_window(redraw, &more); + if (error) { + LOG("xwimp_redraw_window: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + while (more) { + if (user_fill) { + error = xcolourtrans_set_gcol(user_colour, + colourtrans_SET_BG_GCOL, + os_ACTION_OVERWRITE, 0, 0); + if (error) { + LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MiscError", error->errmess); + } + os_clg(); + } + error = xwimp_get_rectangle(redraw, &more); + if (error) { + LOG("xwimp_get_rectangle: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + } +} + + +/** + * Sets whether a piece of window furniture is present for a window. + * + * \param w the window to modify + * \param bic_mask the furniture flags to clear + * \param xor_mask the furniture flags to toggle + */ +void ro_gui_wimp_update_window_furniture(wimp_w w, wimp_window_flags bic_mask, + wimp_window_flags xor_mask) +{ + wimp_window_state state; + wimp_w parent; + bits linkage; + os_error *error; + bool open; + + state.w = w; + error = xwimp_get_window_state_and_nesting(&state, &parent, &linkage); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + + open = state.flags & wimp_WINDOW_OPEN; + state.flags &= ~(63 << 16); /* clear bits 16-21 */ + state.flags &= ~bic_mask; + state.flags ^= xor_mask; + if (!open) + state.next = wimp_HIDDEN; + error = xwimp_open_window_nested_with_flags(&state, parent, linkage); + if (error) { + LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + + if (!open) { + error = xwimp_close_window(w); + if (error) { + LOG("xwimp_close_window: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return; + } + } +} + + +/** + * Checks whether a piece of window furniture is present for a window. + * + * \param w the window to modify + * \param mask the furniture flags to check + */ +bool ro_gui_wimp_check_window_furniture(wimp_w w, wimp_window_flags mask) +{ + wimp_window_state state; + os_error *error; + + state.w = w; + error = xwimp_get_window_state(&state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + return false; + } + return state.flags & mask; +} + +/** + * RO GUI-specific strlen, for control character terminated strings + * + * \param str The string to measure the length of + * \return The length of the string + */ +size_t ro_gui_strlen(const char *str) +{ + const char *str_begin; + + if (str == NULL) + return 0; + + for (str_begin = str; *str++ >= ' '; /* */) + /* */; + + return str - str_begin - 1; +} + +/** + * RO GUI-specific strncmp, for control character terminated strings + * + * \param s1 The first string for comparison + * \param s2 The second string for comparison + * \param len Maximum number of bytes to be checked + * \return 0 for equal strings up to len bytes; pos for s1 being bigger than + * s2; neg for s1 being smaller than s2. + */ +int ro_gui_strncmp(const char *s1, const char *s2, size_t len) +{ + while (len--) { + char c1 = *s1++; + char c2 = *s2++; + if (c1 < ' ' || c2 < ' ') + return (c1 < ' ' ? 0 : c1) - (c2 < ' ' ? 0 : c2); + int diff = c1 - c2; + if (diff) + return diff; + } + return 0; +} + + +/** + * Generic window scroll event handler. + * + * \param *scroll Pointer to Scroll Event block. + */ + +void ro_gui_scroll(wimp_scroll *scroll) +{ + os_error *error; + int x = scroll->visible.x1 - scroll->visible.x0 - 32; + int y = scroll->visible.y1 - scroll->visible.y0 - 32; + + switch (scroll->xmin) { + case wimp_SCROLL_PAGE_LEFT: + scroll->xscroll -= x; + break; + case wimp_SCROLL_COLUMN_LEFT: + scroll->xscroll -= 100; + break; + case wimp_SCROLL_COLUMN_RIGHT: + scroll->xscroll += 100; + break; + case wimp_SCROLL_PAGE_RIGHT: + scroll->xscroll += x; + break; + default: + scroll->xscroll += (x * (scroll->xmin>>2)) >> 2; + break; + } + + switch (scroll->ymin) { + case wimp_SCROLL_PAGE_UP: + scroll->yscroll += y; + break; + case wimp_SCROLL_LINE_UP: + scroll->yscroll += 100; + break; + case wimp_SCROLL_LINE_DOWN: + scroll->yscroll -= 100; + break; + case wimp_SCROLL_PAGE_DOWN: + scroll->yscroll -= y; + break; + default: + scroll->yscroll += (y * (scroll->ymin>>2)) >> 2; + break; + } + + error = xwimp_open_window((wimp_open *) scroll); + if (error) { + LOG("xwimp_open_window: 0x%x: %s", error->errnum, error->errmess); + } +} + |