diff options
Diffstat (limited to 'engines/sci/gfx/menubar.c')
-rw-r--r-- | engines/sci/gfx/menubar.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/engines/sci/gfx/menubar.c b/engines/sci/gfx/menubar.c new file mode 100644 index 0000000000..ff4cb4a11e --- /dev/null +++ b/engines/sci/gfx/menubar.c @@ -0,0 +1,536 @@ +/*************************************************************************** + menubar.c Copyright (C) 1999,2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CJR) [jameson@linuxgames.com] + +***************************************************************************/ +/* Management and drawing operations for the SCI0 menu bar */ +/* I currently assume that the hotkey information used in the menu bar is NOT +** used for any actual actions on behalf of the interpreter. +*/ + +#include <sci_memory.h> +#include <engine.h> +#include <menubar.h> + +#define SIZE_INF 32767 + +/* +static int __active = 0; + +inline void* +__my_malloc(long size, char *function, int line) +{ + void *retval = sci_malloc(size); + __active++; + fprintf(stderr,"[%d] line %d, %s: malloc(%d) -> %p\n", __active, line, function, size, retval); + return retval; +} + +inline void* +__my_realloc(void *origin, long size, char *function, int line) +{ + void *retval = sci_realloc(origin, size); + fprintf(stderr,"line %d, %s: realloc(%p, %d) -> %p\n", line, function, origin, size, retval); + return retval; +} + +inline void +__my_free(void *origin, char *function, int line) +{ + free(origin); + fprintf(stderr,"[%d] line %d, %s: free(%p)\n", __active, line, function, origin); + __active--; +} + +#define malloc(x) __my_malloc(x, __PRETTY_FUNCTION__, __LINE__) +#define realloc(x,y) __my_realloc(x,y, __PRETTY_FUNCTION__, __LINE__) +#define free(x) __my_free(x, __PRETTY_FUNCTION__, __LINE__) +*/ + +menubar_t * +menubar_new() +{ + menubar_t *tmp = (menubar_t*)sci_malloc(sizeof(menubar_t)); + tmp->menus_nr = 0; + + return tmp; +} + +void +menubar_free(menubar_t *menubar) +{ + int i; + + for (i = 0; i < menubar->menus_nr; i++) { + menu_t *menu = &(menubar->menus[i]); + int j; + + for (j = 0; j < menu->items_nr; j++) { + if (menu->items[j].keytext) + free (menu->items[j].keytext); + if (menu->items[j].text) + free (menu->items[j].text); + } + + free(menu->items); + free(menu->title); + } + + if (menubar->menus_nr) + free (menubar->menus); + + free(menubar); +} + + +int +_menubar_add_menu_item(gfx_state_t *state, menu_t *menu, int type, char *left, char *right, + int font, int key, int modifiers, int tag, reg_t text_pos) +/* Returns the total text size, plus MENU_BOX_CENTER_PADDING if (right != NULL) */ +{ + menu_item_t *item; + int total_left_size = 0; + int width, height; + + if (menu->items_nr == 0) { + menu->items = (menu_item_t *) sci_malloc(sizeof(menu_item_t)); + menu->items_nr = 1; + } else menu->items = (menu_item_t *) sci_realloc(menu->items, sizeof(menu_item_t) * ++(menu->items_nr)); + + item = &(menu->items[menu->items_nr - 1]); + + memset(item, 0, sizeof(menu_item_t)); + + if ((item->type = type) == MENU_TYPE_HBAR) + return 0; + + /* else assume MENU_TYPE_NORMAL */ + item->text = left; + if (right) { + int end = strlen(right); + item->keytext = right; + while (end && isspace(right[end])) + right[end--] = 0; /* Remove trailing whitespace */ + item->flags = MENU_ATTRIBUTE_FLAGS_KEY; + item->key = key; + item->modifiers = modifiers; + } else { + item->keytext=NULL; + item->flags = 0; + } + + if (right) { + gfxop_get_text_params(state, font, right, SIZE_INF, &width, &height, 0, + NULL, NULL, NULL); + total_left_size = MENU_BOX_CENTER_PADDING + (item->keytext_size = width); + } + + item->enabled = 1; + item->tag = tag; + item->text_pos = text_pos; + gfxop_get_text_params(state, font, left, SIZE_INF, &width, &height, 0, + NULL, NULL, NULL); + + return total_left_size + width; +} + +void +menubar_add_menu(gfx_state_t *state, menubar_t *menubar, char *title, char *entries, int font, + reg_t entries_base) +{ + int i, add_freesci = 0; + menu_t *menu; + char tracker; + char *left = NULL, *right; + reg_t left_origin; + int string_len = 0; + int tag = 0, c_width, max_width = 0; + int height; + + if (menubar->menus_nr == 0) { +#ifdef MENU_FREESCI_BLATANT_PLUG + add_freesci = 1; +#endif + menubar->menus = (menu_t*)sci_malloc(sizeof(menu_t)); + menubar->menus_nr = 1; + } else menubar->menus = (menu_t*)sci_realloc(menubar->menus, ++(menubar->menus_nr) * sizeof (menu_t)); + + menu = &(menubar->menus[menubar->menus_nr-1]); + memset(menu, 0, sizeof(menu_t)); + menu->items_nr = 0; + menu->title = sci_strdup(title); + + gfxop_get_text_params(state, font, menu->title, SIZE_INF, &(menu->title_width), &height, 0, + NULL, NULL, NULL); + + do { + tracker = *entries++; + entries_base.offset++; + + if (!left) { /* Left string not finished? */ + + if (tracker == '=') { /* Hit early-SCI tag assignment? */ + + left = sci_strndup(entries - string_len - 1, string_len); + tag = atoi(entries++); + tracker = *entries++; + } + if ((tracker == 0 && string_len > 0) || (tracker == '=') || (tracker == ':')) { /* End of entry */ + int entrytype = MENU_TYPE_NORMAL; + char *inleft; + reg_t beginning; + + if (!left) + left = sci_strndup(entries - string_len - 1, string_len); + + inleft = left; + while (isspace(*inleft)) + inleft++; /* Seek beginning of actual string */ + + if (!strncmp(inleft, MENU_HBAR_STRING_1, strlen(MENU_HBAR_STRING_1)) + || !strncmp(inleft, MENU_HBAR_STRING_2, strlen(MENU_HBAR_STRING_2)) + || !strncmp(inleft, MENU_HBAR_STRING_3, strlen(MENU_HBAR_STRING_3))) + { + entrytype = MENU_TYPE_HBAR; /* Horizontal bar */ + free(left); + left = NULL; + } + + beginning = entries_base; beginning.offset -= string_len + 1; + c_width = _menubar_add_menu_item(state, menu, entrytype, left, NULL, font, 0, 0, tag, + beginning); + if (c_width > max_width) + max_width = c_width; + + string_len = 0; + left = NULL; /* Start over */ + + } else if (tracker == '`') { /* Start of right string */ + + if (!left) + { + left_origin = entries_base; left_origin.offset -= string_len + 1; + left = sci_strndup(entries - string_len -1, string_len); + } + string_len = 0; /* Continue with the right string */ + + } + else string_len++; /* Nothing special */ + + } else { /* Left string finished => working on right string */ + if ((tracker == ':') || (tracker == 0)) { /* End of entry */ + int key, modifiers = 0; + + right = sci_strndup(entries - string_len - 1, string_len); + + if (right[0] == '#') { + right[0] = SCI_SPECIAL_CHAR_FUNCTION; /* Function key */ + + key = SCI_K_F1 + ((right[1] - '1') << 8); + + if (right[1] == '0') + key = SCI_K_F10; /* F10 */ + + if (right[2]=='=') { + tag = atoi(right + 3); + right[2] = 0; + }; + } + else if (right[0] == '@') { /* Alt key */ + right[0] = SCI_SPECIAL_CHAR_ALT; /* ALT */ + key = right[1]; + modifiers = SCI_EVM_ALT; + + if ((key >= 'a') && (key <= 'z')) + right[1] = key - 'a' + 'A'; + + if (right[2]=='=') { + tag = atoi(right+3); + right[2] = 0; + }; + + } + else { + + if (right[0] == '^') { + right[0] = SCI_SPECIAL_CHAR_CTRL; /* Control key - there must be a replacement... */ + key = right[1]; + modifiers = SCI_EVM_CTRL; + + if ((key >= 'a') && (key <= 'z')) + right[1] = key - 'a' + 'A'; + + if (right[2]=='=') { + tag = atoi(right+3); + right[2] = 0; + } + + } + else { + key = right[0]; + if ((key >= 'a') && (key <= 'z')) + right[0] = key - 'a' + 'A'; + + if (right[1]=='=') { + tag=atoi(right+2); + right[1] = 0; + } + } + + if ((key >= 'A') && (key <= 'Z')) + key = key - 'A' + 'a'; /* Lowercase the key */ + } + + + i = strlen(right); + + while (i>0 && right[--i] == ' ') + right[i] = 0; /* Cut off chars to the right */ + + c_width = _menubar_add_menu_item(state, menu, MENU_TYPE_NORMAL, left, right, font, key, + modifiers, tag, left_origin); + tag = 0; + if (c_width > max_width) + max_width = c_width; + + string_len = 0; + left = NULL; /* Start over */ + + } else string_len++; /* continuing entry */ + } /* right string finished */ + + } while (tracker); + +#ifdef MENU_FREESCI_BLATANT_PLUG + if (add_freesci) { + + char *freesci_text = sci_strdup ("About FreeSCI"); + c_width = _menubar_add_menu_item(state, menu, MENU_TYPE_NORMAL, freesci_text, NULL, font, 0, 0, 0, NULL_REG); + if (c_width > max_width) + max_width = c_width; + + menu->items[menu->items_nr-1].flags = MENU_FREESCI_BLATANT_PLUG; + } +#endif /* MENU_FREESCI_BLATANT_PLUG */ + menu->width = max_width; +} + +int +menubar_match_key(menu_item_t *item, int message, int modifiers) +{ + if ((item->key == message) + && ((modifiers & (SCI_EVM_CTRL | SCI_EVM_ALT)) == item->modifiers)) + return 1; + + if (message == '\t' + && item->key == 'i' + && ((modifiers & (SCI_EVM_CTRL | SCI_EVM_ALT)) == 0) + && item->modifiers == SCI_EVM_CTRL) + return 1; /* Match TAB to ^I */ + + return 0; +} + +int +menubar_set_attribute(state_t *s, int menu_nr, int item_nr, int attribute, reg_t value) +{ + menubar_t *menubar = s->menubar; + menu_item_t *item; + + if ((menu_nr < 0) || (item_nr < 0)) + return 1; + + if ((menu_nr >= menubar->menus_nr) || (item_nr >= menubar->menus[menu_nr].items_nr)) + return 1; + + item = menubar->menus[menu_nr].items + item_nr; + + switch (attribute) { + + case MENU_ATTRIBUTE_SAID: + if (value.segment) { + item->said_pos = value; + memcpy(item->said, kernel_dereference_bulk_pointer(s, value, 0), MENU_SAID_SPEC_SIZE); /* Copy Said spec */ + item->flags |= MENU_ATTRIBUTE_FLAGS_SAID; + + } else + item->flags &= ~MENU_ATTRIBUTE_FLAGS_SAID; + + break; + + case MENU_ATTRIBUTE_TEXT: + free(item->text); + assert(value.segment); + item->text = sci_strdup(kernel_dereference_char_pointer(s, value, 0)); + item->text_pos = value; + break; + + case MENU_ATTRIBUTE_KEY: + if (item->keytext) + free(item->keytext); + + if (value.segment) { + + /* FIXME: What happens here if <value> is an extended key? Potential bug. LS */ + item->key = value.offset; + item->modifiers = 0; + item->keytext = (char*)sci_malloc(2); + item->keytext[0] = value.offset; + item->keytext[1] = 0; + item->flags |= MENU_ATTRIBUTE_FLAGS_KEY; + if ((item->key >= 'A') && (item->key <= 'Z')) + item->key = item->key - 'A' + 'a'; /* Lowercase the key */ + + + } else { + + item->keytext = NULL; + item->flags &= ~MENU_ATTRIBUTE_FLAGS_KEY; + + } + break; + + case MENU_ATTRIBUTE_ENABLED: + item->enabled = value.offset; + break; + + case MENU_ATTRIBUTE_TAG: + item->tag = value.offset; + break; + + default: + sciprintf("Attempt to set invalid attribute of menu %d, item %d: 0x%04x\n", + menu_nr, item_nr, attribute); + return 1; + } + + return 0; +} + +reg_t +menubar_get_attribute(state_t *s, int menu_nr, int item_nr, int attribute) +{ + menubar_t *menubar = s->menubar; + menu_item_t *item; + + if ((menu_nr < 0) || (item_nr < 0)) + return make_reg(0, -1); + + if ((menu_nr >= menubar->menus_nr) || (item_nr >= menubar->menus[menu_nr].items_nr)) + return make_reg(0, -1); + + item = menubar->menus[menu_nr].items + item_nr; + + switch (attribute) { + case MENU_ATTRIBUTE_SAID: + return item->said_pos; + + case MENU_ATTRIBUTE_TEXT: + return item->text_pos; + + case MENU_ATTRIBUTE_KEY: + return make_reg(0, item->key); + + case MENU_ATTRIBUTE_ENABLED: + return make_reg(0, item->enabled); + + case MENU_ATTRIBUTE_TAG: + return make_reg(0, item->tag); + + default: + sciprintf("Attempt to read invalid attribute from menu %d, item %d: 0x%04x\n", + menu_nr, item_nr, attribute); + return make_reg(0, -1); + } +} + +int +menubar_item_valid(state_t *s, int menu_nr, int item_nr) +{ + menubar_t *menubar = s->menubar; + menu_item_t *item; + + if ((menu_nr < 0) || (item_nr < 0)) + return 0; + + if ((menu_nr >= menubar->menus_nr) || (item_nr >= menubar->menus[menu_nr].items_nr)) + return 0; + + item = menubar->menus[menu_nr].items + item_nr; + + if ((item->type == MENU_TYPE_NORMAL) + && item->enabled) + return 1; + + return 0; /* May not be selected */ +} + + +int +menubar_map_pointer(state_t *s, int *menu_nr, int *item_nr, gfxw_port_t *port) +{ + menubar_t *menubar = s->menubar; + menu_t *menu; + + if (s->gfx_state->pointer_pos.y <= 10) { /* Re-evaulate menu */ + int x = MENU_LEFT_BORDER; + int i; + + for (i = 0; i < menubar->menus_nr; i++) { + int newx = x + MENU_BORDER_SIZE * 2 + menubar->menus[i].title_width; + + if (s->gfx_state->pointer_pos.x < x) + return 0; + + if (s->gfx_state->pointer_pos.x < newx) { + *menu_nr = i; + *item_nr = -1; + } + + x = newx; + } + + return 0; + + } else { + int row = (s->gfx_state->pointer_pos.y / 10) - 1; + + if ((*menu_nr < 0) || (*menu_nr >= menubar->menus_nr)) + return 1; /* No menu */ + else + menu = menubar->menus + *menu_nr; /* Menu is valid, assume that it's popped up */ + + if (menu->items_nr <= row) + return 1; + + if ((s->gfx_state->pointer_pos.x < port->bounds.x) || (s->gfx_state->pointer_pos.x > port->bounds.x + port->bounds.xl)) + return 1; + + if (menubar_item_valid(s, *menu_nr, row)) + *item_nr = row; /* Only modify if we'll be hitting a valid element */ + + return 0; + } + +} |