From d21447d096a320a08b3efb2b8768fad0dcdcfd64 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 5 May 2016 22:28:51 +0100 Subject: move frontends into sub directory --- frontends/riscos/menus.c | 958 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 958 insertions(+) create mode 100644 frontends/riscos/menus.c (limited to 'frontends/riscos/menus.c') diff --git a/frontends/riscos/menus.c b/frontends/riscos/menus.c new file mode 100644 index 000000000..37285c9d1 --- /dev/null +++ b/frontends/riscos/menus.c @@ -0,0 +1,958 @@ +/* + * Copyright 2003 Phil Mellor + * Copyright 2005 James Bursa + * Copyright 2003 John M Bell + * Copyright 2005 Richard Wilson + * + * 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 . + */ + +/** + * \file + * Menu creation and handling implementation. + */ + +#include +#include +#include +#include "oslib/os.h" +#include "oslib/osbyte.h" +#include "oslib/osgbpb.h" +#include "oslib/territory.h" +#include "oslib/wimp.h" + +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/utf8.h" +#include "content/content.h" +#include "content/hlcache.h" +#include "content/urldb.h" +#include "desktop/cookie_manager.h" +#include "desktop/browser.h" +#include "desktop/textinput.h" + +#include "riscos/dialog.h" +#include "riscos/configure.h" +#include "riscos/cookies.h" +#include "riscos/gui.h" +#include "riscos/global_history.h" +#include "riscos/help.h" +#include "riscos/hotlist.h" +#include "riscos/menus.h" +#include "utils/nsoption.h" +#include "riscos/save.h" +#include "riscos/tinct.h" +#include "riscos/toolbar.h" +#include "riscos/treeview.h" +#include "riscos/url_suggest.h" +#include "riscos/wimp.h" +#include "riscos/wimp_event.h" +#include "riscos/ucstables.h" + +struct menu_definition_entry { + menu_action action; /**< menu action */ + wimp_menu_entry *menu_entry; /**< corresponding menu entry */ + const char *entry_key; /**< Messages key for entry text */ + struct menu_definition_entry *next; /**< next menu entry */ +}; + +struct menu_definition { + wimp_menu *menu; /**< corresponding menu */ + const char *title_key; /**< Messages key for title text */ + int current_encoding; /**< Identifier for current text encoding of menu text (as per OS_Byte,71,127) */ + struct menu_definition_entry *entries; /**< menu entries */ + struct menu_definition *next; /**< next menu */ +}; + +static void ro_gui_menu_closed(void); +static void ro_gui_menu_define_menu_add(struct menu_definition *definition, + const struct ns_menu *menu, int depth, + wimp_menu_entry *parent_entry, + int first, int last, const char *prefix, int prefix_length); +static struct menu_definition *ro_gui_menu_find_menu(wimp_menu *menu); +static struct menu_definition_entry *ro_gui_menu_find_entry(wimp_menu *menu, + menu_action action); +static menu_action ro_gui_menu_find_action(wimp_menu *menu, + wimp_menu_entry *menu_entry); +static int ro_gui_menu_get_checksum(void); +static bool ro_gui_menu_translate(struct menu_definition *menu); + + +/* default menu item flags */ +#define DEFAULT_FLAGS (wimp_ICON_TEXT | wimp_ICON_FILLED | \ + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | \ + (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT)) + +/** The currently defined menus to perform actions for */ +static struct menu_definition *ro_gui_menu_definitions; +/** The current menu being worked with (may not be open) */ +wimp_menu *current_menu; +/** Whether a menu is currently open */ +bool current_menu_open = false; +/** Window that owns the current menu */ +wimp_w current_menu_window; +/** Icon that owns the current menu (only valid for popup menus) */ +static wimp_i current_menu_icon; +/** The available menus */ +wimp_menu *image_quality_menu, *proxy_type_menu, *languages_menu; + +/* the values given in PRM 3-157 for how to check menus/windows are + * incorrect so we use a hack of checking if the sub-menu has bit 0 + * set which is undocumented but true of window handles on + * all target OS versions */ +#define IS_MENU(menu) !((int)(menu) & 1) + +/** + * Create menu structures. + */ + +void ro_gui_menu_init(void) +{ + /* image quality menu */ + static const struct ns_menu images_definition = { + "Display", { + { "ImgStyle0", NO_ACTION, 0 }, + { "ImgStyle1", NO_ACTION, 0 }, + { "ImgStyle2", NO_ACTION, 0 }, + { "ImgStyle3", NO_ACTION, 0 }, + {NULL, 0, 0} + } + }; + image_quality_menu = ro_gui_menu_define_menu(&images_definition); + + /* proxy menu */ + static const struct ns_menu proxy_type_definition = { + "ProxyType", { + { "ProxyNone", NO_ACTION, 0 }, + { "ProxyNoAuth", NO_ACTION, 0 }, + { "ProxyBasic", NO_ACTION, 0 }, + { "ProxyNTLM", NO_ACTION, 0 }, + {NULL, 0, 0} + } + }; + proxy_type_menu = ro_gui_menu_define_menu(&proxy_type_definition); + + /* special case menus */ + ro_gui_url_suggest_init(); + + /* Note: This table *must* be kept in sync with the LangNames file */ + static const struct ns_menu lang_definition = { + "Languages", { + { "lang_af", NO_ACTION, 0 }, + { "lang_bm", NO_ACTION, 0 }, + { "lang_ca", NO_ACTION, 0 }, + { "lang_cs", NO_ACTION, 0 }, + { "lang_cy", NO_ACTION, 0 }, + { "lang_da", NO_ACTION, 0 }, + { "lang_de", NO_ACTION, 0 }, + { "lang_en", NO_ACTION, 0 }, + { "lang_es", NO_ACTION, 0 }, + { "lang_et", NO_ACTION, 0 }, + { "lang_eu", NO_ACTION, 0 }, + { "lang_ff", NO_ACTION, 0 }, + { "lang_fi", NO_ACTION, 0 }, + { "lang_fr", NO_ACTION, 0 }, + { "lang_ga", NO_ACTION, 0 }, + { "lang_gl", NO_ACTION, 0 }, + { "lang_ha", NO_ACTION, 0 }, + { "lang_hr", NO_ACTION, 0 }, + { "lang_hu", NO_ACTION, 0 }, + { "lang_id", NO_ACTION, 0 }, + { "lang_is", NO_ACTION, 0 }, + { "lang_it", NO_ACTION, 0 }, + { "lang_lt", NO_ACTION, 0 }, + { "lang_lv", NO_ACTION, 0 }, + { "lang_ms", NO_ACTION, 0 }, + { "lang_mt", NO_ACTION, 0 }, + { "lang_nl", NO_ACTION, 0 }, + { "lang_no", NO_ACTION, 0 }, + { "lang_pl", NO_ACTION, 0 }, + { "lang_pt", NO_ACTION, 0 }, + { "lang_rn", NO_ACTION, 0 }, + { "lang_ro", NO_ACTION, 0 }, + { "lang_rw", NO_ACTION, 0 }, + { "lang_sk", NO_ACTION, 0 }, + { "lang_sl", NO_ACTION, 0 }, + { "lang_so", NO_ACTION, 0 }, + { "lang_sq", NO_ACTION, 0 }, + { "lang_sr", NO_ACTION, 0 }, + { "lang_sv", NO_ACTION, 0 }, + { "lang_sw", NO_ACTION, 0 }, + { "lang_tr", NO_ACTION, 0 }, + { "lang_uz", NO_ACTION, 0 }, + { "lang_vi", NO_ACTION, 0 }, + { "lang_wo", NO_ACTION, 0 }, + { "lang_xs", NO_ACTION, 0 }, + { "lang_yo", NO_ACTION, 0 }, + { "lang_zu", NO_ACTION, 0 }, + { NULL, 0, 0 } + } + }; + languages_menu = ro_gui_menu_define_menu(&lang_definition); +} + + +/** + * Display a menu. + * + * \param *menu Pointer to the menu to be displayed. + * \param x The x position. + * \param y The y position. + * \param w The window that the menu belongs to. + */ + +void ro_gui_menu_create(wimp_menu *menu, int x, int y, wimp_w w) +{ + os_error *error; + struct menu_definition *definition; + + /* translate menu, if necessary (this returns quickly + * if there's nothing to be done) */ + definition = ro_gui_menu_find_menu(menu); + if (definition) { + if (!ro_gui_menu_translate(definition)) { + ro_warn_user("NoMemory", 0); + return; + } + } + + /* store the menu characteristics */ + current_menu = menu; + current_menu_window = w; + current_menu_icon = wimp_ICON_WINDOW; + + /* create the menu */ + current_menu_open = true; + error = xwimp_create_menu(menu, x - 64, y); + if (error) { + LOG("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MenuError", error->errmess); + ro_gui_menu_closed(); + } +} + + +/** + * Display a pop-up menu next to the specified icon. + * + * \param menu menu to open + * \param w window handle + * \param i icon handle + */ + +void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i) +{ + wimp_window_state state; + wimp_icon_state icon_state; + os_error *error; + + state.w = w; + icon_state.w = w; + icon_state.i = i; + error = xwimp_get_window_state(&state); + if (error) { + LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MenuError", error->errmess); + return; + } + + error = xwimp_get_icon_state(&icon_state); + if (error) { + LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MenuError", error->errmess); + return; + } + + ro_gui_menu_create(menu, + state.visible.x0 + icon_state.icon.extent.x1 + 64, + state.visible.y1 + icon_state.icon.extent.y1 - + state.yscroll, w); + current_menu_icon = i; +} + + +/** + * Forcibly close any menu or transient dialogue box that is currently open. + */ + +void ro_gui_menu_destroy(void) +{ + os_error *error; + + if (current_menu == NULL) + return; + + error = xwimp_create_menu(wimp_CLOSE_MENU, 0, 0); + if (error) { + LOG("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MenuError", error->errmess); + } + + ro_gui_menu_closed(); +} + + +/** + * Allow the current menu window to change, if the window is deleted and + * recreated while a menu is active on an Adjust-click. + * + * \param from The original window handle. + * \param to The new replacement window handle. + */ + +void ro_gui_menu_window_changed(wimp_w from, wimp_w to) +{ + + if (from == current_menu_window) + current_menu_window = to; +} + + +/** + * Handle menu selection. + */ + +void ro_gui_menu_selection(wimp_selection *selection) +{ + int i; //, j; + wimp_menu_entry *menu_entry; + menu_action action; + wimp_pointer pointer; + os_error *error; + int previous_menu_icon = current_menu_icon; + + /* if we are using gui_multitask then menu selection events + * may be delivered after the menu has been closed. As such, + * we simply ignore these events. */ + if (!current_menu) + return; + + assert(current_menu_window); + + /* get the menu entry and associated action and definition */ + menu_entry = ¤t_menu->entries[selection->items[0]]; + for (i = 1; selection->items[i] != -1; i++) + menu_entry = &menu_entry->sub_menu-> + entries[selection->items[i]]; + action = ro_gui_menu_find_action(current_menu, menu_entry); + + /* Deal with the menu action. If this manages to re-prepare the + * menu for re-opening, we test for and act on Adjust clicks. + */ + + if (!ro_gui_wimp_event_menu_selection(current_menu_window, + current_menu_icon, current_menu, selection, action)) + return; + + /* re-open the menu for Adjust clicks */ + error = xwimp_get_pointer_info(&pointer); + if (error) { + LOG("xwimp_get_pointer_info: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("WimpError", error->errmess); + ro_gui_menu_closed(); + return; + } + + if (pointer.buttons != wimp_CLICK_ADJUST) { + ro_gui_menu_closed(); + return; + } + + ro_gui_menu_create(current_menu, 0, 0, current_menu_window); + current_menu_icon = previous_menu_icon; +} + + +/** + * Handle Message_MenuWarning. + */ +void ro_gui_menu_warning(wimp_message_menu_warning *warning) +{ + int i; + menu_action action; + wimp_menu_entry *menu_entry; + os_error *error; + + assert(current_menu); + assert(current_menu_window); + + /* get the sub-menu of the warning */ + if (warning->selection.items[0] == -1) + return; + menu_entry = ¤t_menu->entries[warning->selection.items[0]]; + for (i = 1; warning->selection.items[i] != -1; i++) + menu_entry = &menu_entry->sub_menu-> + entries[warning->selection.items[i]]; + action = ro_gui_menu_find_action(current_menu, menu_entry); + + /* Process the warning via Wimp_Event, then register the resulting + * submenu with the module. + */ + + ro_gui_wimp_event_submenu_warning(current_menu_window, + current_menu_icon, current_menu, &(warning->selection), + action); + + if (IS_MENU(menu_entry->sub_menu)) { + ro_gui_wimp_event_register_submenu((wimp_w) 0); + } else { + ro_gui_wimp_event_register_submenu((wimp_w) + menu_entry->sub_menu); + + /* If this is a dialogue box, remove the close and back icons. + */ + + ro_gui_wimp_update_window_furniture((wimp_w) + menu_entry->sub_menu, + wimp_WINDOW_CLOSE_ICON | wimp_WINDOW_BACK_ICON, + 0); + } + + /* open the sub-menu */ + + error = xwimp_create_sub_menu(menu_entry->sub_menu, + warning->pos.x, warning->pos.y); + if (error) { + LOG("xwimp_create_sub_menu: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MenuError", error->errmess); + } +} + + +/** + * Handle Message_MenusDeleted, removing our current record of an open menu + * if it matches the deleted menu handle. + * + * \param *deleted The message block. + */ + +void ro_gui_menu_message_deleted(wimp_message_menus_deleted *deleted) +{ + if (deleted != NULL && deleted->menu == current_menu) + ro_gui_menu_closed(); +} + + +/** + * Clean up after a menu has been closed, or forcibly close an open menu. + */ + +static void ro_gui_menu_closed(void) +{ + if (current_menu != NULL) + ro_gui_wimp_event_menus_closed(current_menu_window, + current_menu_icon, current_menu); + + current_menu = NULL; + current_menu_window = NULL; + current_menu_icon = 0; + current_menu_open = false; +} + + +/** + * Update the current menu by sending it a Menu Prepare event through wimp_event + * and then reopening it if the contents has changed. + * + * \param *menu The menu to refresh: if 0, the current menu will be + * refreshed regardless, otherwise it will be refreshed + * only if it matches the supplied handle. + */ + +void ro_gui_menu_refresh(wimp_menu *menu) +{ + int checksum = 0; + + if (!current_menu_open) + return; + + checksum = ro_gui_menu_get_checksum(); + + if (!ro_gui_wimp_event_prepare_menu(current_menu_window, + current_menu_icon, current_menu)) + return; + + /* \TODO -- Call the menu's event handler here. */ + + if (checksum != ro_gui_menu_get_checksum()) { + os_error *error; + error = xwimp_create_menu(current_menu, 0, 0); + if (error) { + LOG("xwimp_create_menu: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MenuError", error->errmess); + } + } +} + + + + +/** + * Creates a wimp_menu and adds it to the list to handle actions for. + * + * \param menu The data to create the menu with + * \return The menu created, or NULL on failure + */ +wimp_menu *ro_gui_menu_define_menu(const struct ns_menu *menu) +{ + struct menu_definition *definition; + int entry; + + definition = calloc(sizeof(struct menu_definition), 1); + if (!definition) { + die("No memory to create menu definition."); + return NULL; /* For the benefit of scan-build */ + } + + /* link in the menu to our list */ + definition->next = ro_gui_menu_definitions; + ro_gui_menu_definitions = definition; + + /* count number of menu entries */ + for (entry = 0; menu->entries[entry].text; entry++) + /* do nothing */; + + /* create our definitions */ + ro_gui_menu_define_menu_add(definition, menu, 0, NULL, + 0, entry, NULL, 0); + + /* and translate menu into current encoding */ + if (!ro_gui_menu_translate(definition)) + die("No memory to translate menu."); + + return definition->menu; +} + +/** + * Create a wimp menu tree from ns_menu data. + * This function does *not* deal with the menu textual content - it simply + * creates and populates the appropriate structures. Textual content is + * generated by ro_gui_menu_translate_menu() + * + * \param definition Top level menu definition + * \param menu Menu declaration data + * \param depth Depth of menu we're currently building + * \param parent_entry Entry in parent menu, or NULL if root menu + * \param first First index in declaration data that is used by this menu + * \param last Last index in declaration data that is used by this menu + * \param prefix Prefix pf menu declaration string already seen + * \param prefix_length Length of prefix + */ +void ro_gui_menu_define_menu_add(struct menu_definition *definition, + const struct ns_menu *menu, int depth, + wimp_menu_entry *parent_entry, int first, int last, + const char *prefix, int prefix_length) +{ + int entry; + int entries = 0; + int matches[last - first + 1]; + const char *text, *menu_text; + wimp_menu *new_menu; + struct menu_definition_entry *definition_entry; + + /* step 1: store the matches for depth and subset string */ + for (entry = first; entry < last; entry++) { + const char *match; + int cur_depth = 0; + match = menu->entries[entry].text; + + /* skip specials at start of string */ + while (!isalnum(*match)) + match++; + + /* attempt prefix match */ + if ((prefix) && (strncmp(match, prefix, prefix_length))) + continue; + + /* Find depth of this entry */ + while (*match) + if (*match++ == '.') + cur_depth++; + + if (depth == cur_depth) + matches[entries++] = entry; + } + matches[entries] = last; + + /* no entries, so exit */ + if (entries == 0) + return; + + /* step 2: build and link the menu. we must use realloc to stop + * our memory fragmenting so we can test for sub-menus easily */ + new_menu = (wimp_menu *)malloc(wimp_SIZEOF_MENU(entries)); + if (!new_menu) + die("No memory to create menu."); + + if (parent_entry) { + /* Fix up sub menu pointer */ + parent_entry->sub_menu = new_menu; + } else { + /* Root menu => fill in definition struct */ + definition->title_key = menu->title; + definition->current_encoding = 0; + definition->menu = new_menu; + } + + /* this is fixed up in ro_gui_menu_translate() */ + new_menu->title_data.indirected_text.text = NULL; + + /* fill in menu flags */ + ro_gui_menu_init_structure(new_menu, entries); + + /* and then create the entries */ + for (entry = 0; entry < entries; entry++) { + /* add the entry */ + int id = matches[entry]; + + text = menu->entries[id].text; + + /* fill in menu flags from specials at start of string */ + new_menu->entries[entry].menu_flags = 0; + while (!isalnum(*text)) { + if (*text == '_') + new_menu->entries[entry].menu_flags |= + wimp_MENU_SEPARATE; + text++; + } + + /* get messages key for menu entry */ + menu_text = strrchr(text, '.'); + if (!menu_text) + /* no '.' => top-level entry */ + menu_text = text; + else + menu_text++; /* and move past the '.' */ + + /* fill in submenu data */ + if (menu->entries[id].sub_window) + new_menu->entries[entry].sub_menu = + (wimp_menu *) (*menu->entries[id].sub_window); + + /* this is fixed up in ro_gui_menu_translate() */ + new_menu->entries[entry].data.indirected_text.text = NULL; + + /* create definition entry */ + definition_entry = + malloc(sizeof(struct menu_definition_entry)); + if (!definition_entry) + die("Unable to create menu definition entry"); + definition_entry->action = menu->entries[id].action; + definition_entry->menu_entry = &new_menu->entries[entry]; + definition_entry->entry_key = menu_text; + definition_entry->next = definition->entries; + definition->entries = definition_entry; + + /* recurse */ + if (new_menu->entries[entry].sub_menu == wimp_NO_SUB_MENU) { + ro_gui_menu_define_menu_add(definition, menu, + depth + 1, &new_menu->entries[entry], + matches[entry], matches[entry + 1], + text, strlen(text)); + } + + /* give menu warnings */ + if (new_menu->entries[entry].sub_menu != wimp_NO_SUB_MENU) + new_menu->entries[entry].menu_flags |= + wimp_MENU_GIVE_WARNING; + } + new_menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; + new_menu->entries[entries - 1].menu_flags |= wimp_MENU_LAST; +} + + +/** + * Initialise the basic state of a menu structure so all entries are + * indirected text with no flags, no submenu. + */ +void ro_gui_menu_init_structure(wimp_menu *menu, int entries) +{ + int i; + + menu->title_fg = wimp_COLOUR_BLACK; + menu->title_bg = wimp_COLOUR_LIGHT_GREY; + menu->work_fg = wimp_COLOUR_BLACK; + menu->work_bg = wimp_COLOUR_WHITE; + menu->width = 200; + menu->height = wimp_MENU_ITEM_HEIGHT; + menu->gap = wimp_MENU_ITEM_GAP; + + for (i = 0; i < entries; i++) { + menu->entries[i].menu_flags = 0; + menu->entries[i].sub_menu = wimp_NO_SUB_MENU; + menu->entries[i].icon_flags = + DEFAULT_FLAGS | wimp_ICON_INDIRECTED; + menu->entries[i].data.indirected_text.validation = + (char *)-1; + } + menu->entries[0].menu_flags |= wimp_MENU_TITLE_INDIRECTED; + menu->entries[i - 1].menu_flags |= wimp_MENU_LAST; +} + + +/** + * Finds the menu_definition corresponding to a wimp_menu. + * + * \param menu the menu to find the definition for + * \return the associated definition, or NULL if one could not be found + */ +struct menu_definition *ro_gui_menu_find_menu(wimp_menu *menu) +{ + struct menu_definition *definition; + + if (!menu) + return NULL; + + for (definition = ro_gui_menu_definitions; definition; + definition = definition->next) + if (definition->menu == menu) + return definition; + return NULL; +} + + +/** + * Finds the key associated with a menu entry translation. + * + * \param menu the menu to search + * \param translated the translated text + * \return the original message key, or NULL if one could not be found + */ +const char *ro_gui_menu_find_menu_entry_key(wimp_menu *menu, + const char *translated) +{ + struct menu_definition_entry *entry; + struct menu_definition *definition = ro_gui_menu_find_menu(menu); + + if (!definition) + return NULL; + + for (entry = definition->entries; entry; entry = entry->next) + if (!strcmp(entry->menu_entry->data.indirected_text.text, translated)) + return entry->entry_key; + return NULL; +} + + +/** + * Finds the menu_definition_entry corresponding to an action for a wimp_menu. + * + * \param menu the menu to search for an action within + * \param action the action to find + * \return the associated menu entry, or NULL if one could not be found + */ +struct menu_definition_entry *ro_gui_menu_find_entry(wimp_menu *menu, + menu_action action) +{ + struct menu_definition_entry *entry; + struct menu_definition *definition = ro_gui_menu_find_menu(menu); + + if (!definition) + return NULL; + + for (entry = definition->entries; entry; entry = entry->next) + if (entry->action == action) + return entry; + return NULL; +} + + +/** + * Finds the action corresponding to a wimp_menu_entry for a wimp_menu. + * + * \param menu the menu to search for an action within + * \param menu_entry the menu_entry to find + * \return the associated action, or 0 if one could not be found + */ +menu_action ro_gui_menu_find_action(wimp_menu *menu, wimp_menu_entry *menu_entry) +{ + struct menu_definition_entry *entry; + struct menu_definition *definition = ro_gui_menu_find_menu(menu); + + if (!definition) + return NO_ACTION; + + for (entry = definition->entries; entry; entry = entry->next) { + if (entry->menu_entry == menu_entry) + return entry->action; + } + return NO_ACTION; +} + + +/** + * Sets an action within a menu as having a specific ticked status. + * + * \param menu the menu containing the action + * \param action the action to tick/untick + * \param shaded whether to set the item as shaded + */ +void ro_gui_menu_set_entry_shaded(wimp_menu *menu, menu_action action, + bool shaded) +{ + struct menu_definition_entry *entry; + struct menu_definition *definition = ro_gui_menu_find_menu(menu); + + if (!definition) + return; + + /* we can't use find_entry as multiple actions may appear in one menu */ + for (entry = definition->entries; entry; entry = entry->next) + if (entry->action == action) { + if (shaded) + entry->menu_entry->icon_flags |= wimp_ICON_SHADED; + else + entry->menu_entry->icon_flags &= ~wimp_ICON_SHADED; + } +} + + +/** + * Sets an action within a menu as having a specific ticked status. + * + * \param menu the menu containing the action + * \param action the action to tick/untick + * \param ticked whether to set the item as ticked + */ +void ro_gui_menu_set_entry_ticked(wimp_menu *menu, menu_action action, + bool ticked) +{ + struct menu_definition_entry *entry = + ro_gui_menu_find_entry(menu, action); + if (entry) { + if (ticked) + entry->menu_entry->menu_flags |= wimp_MENU_TICKED; + else + entry->menu_entry->menu_flags &= ~wimp_MENU_TICKED; + } +} + + +/** + * Calculates a simple checksum for the current menu state + */ +int ro_gui_menu_get_checksum(void) +{ + wimp_selection menu_tree; + int i = 0, j, checksum = 0; + os_error *error; + wimp_menu *menu; + + if (!current_menu_open) + return 0; + + error = xwimp_get_menu_state((wimp_menu_state_flags)0, + &menu_tree, 0, 0); + if (error) { + LOG("xwimp_get_menu_state: 0x%x: %s", error->errnum, error->errmess); + ro_warn_user("MenuError", error->errmess); + return 0; + } + + menu = current_menu; + do { + j = 0; + do { + if (menu->entries[j].icon_flags & wimp_ICON_SHADED) + checksum ^= (1 << (i + j * 2)); + if (menu->entries[j].menu_flags & wimp_MENU_TICKED) + checksum ^= (2 << (i + j * 2)); + } while (!(menu->entries[j++].menu_flags & wimp_MENU_LAST)); + + j = menu_tree.items[i++]; + if (j != -1) { + menu = menu->entries[j].sub_menu; + if ((!menu) || (menu == wimp_NO_SUB_MENU) || (!IS_MENU(menu))) + break; + } + } while (j != -1); + + return checksum; +} + +/** + * Translate a menu's textual content into the system local encoding + * + * \param menu The menu to translate + * \return false if out of memory, true otherwise + */ +bool ro_gui_menu_translate(struct menu_definition *menu) +{ + os_error *error; + int alphabet; + struct menu_definition_entry *entry; + char *translated; + nserror err; + + /* read current alphabet */ + error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &alphabet); + if (error) { + LOG("failed reading alphabet: 0x%x: %s", error->errnum, error->errmess); + /* assume Latin1 */ + alphabet = territory_ALPHABET_LATIN1; + } + + if (menu->current_encoding == alphabet) + /* menu text is already in the correct encoding */ + return true; + + /* translate root menu title text */ + free(menu->menu->title_data.indirected_text.text); + err = utf8_to_local_encoding(messages_get(menu->title_key), + 0, &translated); + if (err != NSERROR_OK) { + assert(err != NSERROR_BAD_ENCODING); + LOG("utf8_to_enc failed"); + return false; + } + + /* and fill in WIMP menu field */ + menu->menu->title_data.indirected_text.text = translated; + + /* now the menu entries */ + for (entry = menu->entries; entry; entry = entry->next) { + wimp_menu *submenu = entry->menu_entry->sub_menu; + + /* tranlate menu entry text */ + free(entry->menu_entry->data.indirected_text.text); + err = utf8_to_local_encoding(messages_get(entry->entry_key), + 0, &translated); + if (err != NSERROR_OK) { + assert(err != NSERROR_BAD_ENCODING); + LOG("utf8_to_enc failed"); + return false; + } + + /* fill in WIMP menu fields */ + entry->menu_entry->data.indirected_text.text = translated; + entry->menu_entry->data.indirected_text.validation = + (char *) -1; + entry->menu_entry->data.indirected_text.size = + strlen(translated); + + /* child menu title - this is the same as the text of + * the parent menu entry, so just copy the pointer */ + if (submenu != wimp_NO_SUB_MENU && IS_MENU(submenu)) { + submenu->title_data.indirected_text.text = + translated; + } + } + + /* finally, set the current encoding of the menu */ + menu->current_encoding = alphabet; + + return true; +} + -- cgit v1.2.3