aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gfx/menubar.c
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/gfx/menubar.c')
-rw-r--r--engines/sci/gfx/menubar.c536
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;
+ }
+
+}