aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/menu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/agi/menu.cpp')
-rw-r--r--engines/agi/menu.cpp503
1 files changed, 503 insertions, 0 deletions
diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp
new file mode 100644
index 0000000000..950b054cb3
--- /dev/null
+++ b/engines/agi/menu.cpp
@@ -0,0 +1,503 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * Copyright (C) 1999-2002 Sarien Team
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "agi/agi.h"
+#include "agi/sprite.h"
+#include "agi/graphics.h"
+#include "agi/keyboard.h"
+#include "agi/menu.h"
+#include "agi/text.h"
+#include "agi/list.h"
+
+namespace Agi {
+
+struct agi_menu {
+ struct list_head list; /**< list head for menubar list */
+ struct list_head down; /**< list head for menu options */
+ int index; /**< number of menu in menubar */
+ int width; /**< width of menu in characters */
+ int height; /**< height of menu in characters */
+ int col; /**< column of menubar entry */
+ int wincol; /**< column of menu window */
+ char *text; /**< menu name */
+};
+
+struct agi_menu_option {
+ struct list_head list; /**< list head for menu options */
+ int enabled; /**< option is enabled or disabled */
+ int event; /**< menu event */
+ int index; /**< number of option in this menu */
+ char *text; /**< text of menu option */
+};
+
+static LIST_HEAD(menubar);
+
+static int h_cur_menu;
+static int v_cur_menu;
+
+static struct agi_menu *get_menu(int i) {
+ struct list_head *h;
+ struct agi_menu *m;
+
+ list_for_each(h, &menubar, next) {
+ m = list_entry(h, struct agi_menu, list);
+ if (m->index == i)
+ return m;
+ }
+ return NULL;
+}
+
+static struct agi_menu_option *get_menu_option(int i, int j) {
+ struct list_head *h;
+ struct agi_menu *m;
+ struct agi_menu_option *d;
+
+ m = get_menu(i);
+
+ list_for_each(h, &m->down, next) {
+ d = list_entry(h, struct agi_menu_option, list);
+ if (d->index == j)
+ return d;
+ }
+
+ return NULL;
+}
+
+static void draw_menu_bar() {
+ struct list_head *h;
+ struct agi_menu *m;
+
+ clear_lines(0, 0, MENU_BG);
+ flush_lines(0, 0);
+
+ list_for_each(h, &menubar, next) {
+ m = list_entry(h, struct agi_menu, list);
+ print_text(m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG);
+ }
+
+}
+
+static void draw_menu_hilite(int cur_menu) {
+ struct agi_menu *m;
+
+ m = get_menu(cur_menu);
+ debugC(6, kDebugLevelMenu, "[%s]", m->text);
+ print_text(m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG);
+ flush_lines(0, 0);
+}
+
+/* draw box and pulldowns. */
+static void draw_menu_option(int h_menu) {
+ struct list_head *h;
+ struct agi_menu *m = NULL;
+ struct agi_menu_option *d = NULL;
+
+ /* find which vertical menu it is */
+ m = get_menu(h_menu);
+
+ draw_box(m->wincol * CHAR_COLS, 1 * CHAR_LINES, (m->wincol + m->width + 2) * CHAR_COLS,
+ (1 + m->height + 2) * CHAR_LINES, MENU_BG, MENU_LINE, 0);
+
+ list_for_each(h, &m->down, next) {
+ d = list_entry(h, struct agi_menu_option, list);
+ print_text(d->text, 0, m->wincol + 1, d->index + 2, m->width + 2,
+ d->enabled ? MENU_FG : MENU_DISABLED, MENU_BG);
+ }
+}
+
+static void draw_menu_option_hilite(int h_menu, int v_menu) {
+ struct agi_menu *m;
+ struct agi_menu_option *d;
+
+ m = get_menu(h_menu);
+ d = get_menu_option(h_menu, v_menu);
+
+ print_text(d->text, 0, m->wincol + 1, v_menu + 2, m->width + 2,
+ MENU_BG, d->enabled ? MENU_FG : MENU_DISABLED);
+}
+
+static void new_menu_selected(int i) {
+ show_pic();
+ draw_menu_bar();
+ draw_menu_hilite(i);
+ draw_menu_option(i);
+}
+
+#ifdef USE_MOUSE
+static int mouse_over_text(unsigned int line, unsigned int col, char *s) {
+ if (mouse.x < col * CHAR_COLS)
+ return false;
+
+ if (mouse.x > (col + strlen(s)) * CHAR_COLS)
+ return false;
+
+ if (mouse.y < line * CHAR_LINES)
+ return false;
+
+ if (mouse.y >= (line + 1) * CHAR_LINES)
+ return false;
+
+ return true;
+}
+#endif
+
+static int h_index;
+static int v_index;
+static int h_col;
+static int h_max_menu;
+static int v_max_menu[10];
+
+#if 0
+static void add_about_option() {
+ struct agi_menu *m;
+ struct agi_menu_option *d;
+ char text[] = "About AGI engine";
+
+ d = malloc(sizeof(struct agi_menu_option));
+ d->text = strdup(text);
+ d->enabled = true;
+ d->event = 255;
+ d->index = (v_max_menu[0] += 1);
+
+ m = list_entry(menubar.next, struct agi_menu, list);
+ list_add_tail(&d->list, &m->down);
+ m->height++;
+ if (m->width < strlen(text))
+ m->width = strlen(text);
+}
+#endif
+
+/*
+ * Public functions
+ */
+
+void menu_init() {
+ h_index = 0;
+ h_col = 1;
+ h_cur_menu = 0;
+ v_cur_menu = 0;
+}
+
+void menu_deinit() {
+ struct list_head *h, *h2, *v, *v2;
+ struct agi_menu *m = NULL;
+ struct agi_menu_option *d = NULL;
+
+ for (h = (&menubar)->prev; h != (&menubar); h = h2) {
+ m = list_entry(h, struct agi_menu, list);
+ h2 = h->prev;
+ debugC(3, kDebugLevelMenu, "deiniting hmenu %s", m->text);
+ for (v = (&m->down)->prev; v != (&m->down); v = v2) {
+ d = list_entry(v, struct agi_menu_option, list);
+ v2 = v->prev;
+ debugC(3, kDebugLevelMenu, " deiniting vmenu %s", d->text);
+ list_del(v);
+ free(d->text);
+ free(d);
+ }
+ list_del(h);
+ free(m->text);
+ free(m);
+ }
+}
+
+void menu_add(char *s) {
+ struct agi_menu *m;
+
+ m = (agi_menu *) malloc(sizeof(struct agi_menu));
+ m->text = strdup(s);
+ while (m->text[strlen(m->text) - 1] == ' ')
+ m->text[strlen(m->text) - 1] = 0;
+ m->down.next = &m->down;
+ m->down.prev = &m->down;
+ m->width = 0;
+ m->height = 0;
+ m->index = h_index++;
+ m->col = h_col;
+ m->wincol = h_col - 1;
+ v_index = 0;
+ v_max_menu[m->index] = 0;
+ h_col += strlen(m->text) + 1;
+ h_max_menu = m->index;
+
+ debugC(3, kDebugLevelMenu, "add menu: '%s' %02x", s, m->text[strlen(m->text)]);
+ list_add_tail(&m->list, &menubar);
+}
+
+void menu_add_item(char *s, int code) {
+ struct agi_menu *m;
+ struct agi_menu_option *d;
+ int l;
+
+ d = (agi_menu_option *) malloc(sizeof(struct agi_menu_option));
+ d->text = strdup(s);
+ d->enabled = true;
+ d->event = code;
+ d->index = v_index++;
+
+ m = list_entry(menubar.prev, struct agi_menu, list);
+ m->height++;
+
+ v_max_menu[m->index] = d->index;
+
+ l = strlen(d->text);
+ if (l > 40)
+ l = 38;
+ if (m->wincol + l > 38)
+ m->wincol = 38 - l;
+ if (l > m->width)
+ m->width = l;
+
+ debugC(3, kDebugLevelMenu, "Adding menu item: %s (size = %d)", s, m->height);
+ list_add_tail(&d->list, &m->down);
+}
+
+void menu_submit() {
+ struct list_head *h, *h2;
+ struct agi_menu *m = NULL;
+
+ debugC(3, kDebugLevelMenu, "Submitting menu");
+
+ /* add_about_option (); */
+
+ /* If a menu has no options, delete it */
+ for (h = (&menubar)->prev; h != (&menubar); h = h2) {
+ m = list_entry(h, struct agi_menu, list);
+ h2 = h->prev;
+ if ((&m->down)->prev == (&m->down)) {
+ list_del(h);
+ free(m->text);
+ free(m);
+ h_max_menu--;
+ }
+ }
+}
+
+int menu_keyhandler(int key) {
+ static int clock_val;
+ static int menu_active = false;
+ struct agi_menu_option *d;
+ struct list_head *h;
+ struct agi_menu *m;
+ static int button_used = 0;
+
+ if (!getflag(F_menus_work))
+ return false;
+
+ if (!menu_active) {
+ clock_val = game.clock_enabled;
+ game.clock_enabled = false;
+ draw_menu_bar();
+ }
+#ifdef USE_MOUSE
+ /*
+ * Mouse handling
+ */
+ if (mouse.button) {
+ int hmenu, vmenu;
+
+ button_used = 1; /* Button has been used at least once */
+ if (mouse.y <= CHAR_LINES) {
+ /* on the menubar */
+ hmenu = 0;
+
+ list_for_each(h, &menubar, next) {
+ m = list_entry(h, struct agi_menu, list);
+ if (mouse_over_text(0, m->col, m->text)) {
+ break;
+ } else {
+ hmenu++;
+ }
+ }
+
+ if (hmenu <= h_max_menu) {
+ if (h_cur_menu != hmenu) {
+ v_cur_menu = -1;
+ new_menu_selected(hmenu);
+ }
+ h_cur_menu = hmenu;
+ }
+ } else {
+ /* not in menubar */
+ struct agi_menu_option *do1;
+
+ vmenu = 0;
+
+ m = get_menu(h_cur_menu);
+ list_for_each(h, &m->down, next) {
+ do1 = list_entry(h, struct agi_menu_option, list);
+ if (mouse_over_text(2 + do1->index, m->wincol + 1, do1->text)) {
+ break;
+ } else {
+ vmenu++;
+ }
+ }
+
+ if (vmenu <= v_max_menu[h_cur_menu]) {
+ if (v_cur_menu != vmenu) {
+ draw_menu_option(h_cur_menu);
+ draw_menu_option_hilite(h_cur_menu, vmenu);
+ }
+ v_cur_menu = vmenu;
+ }
+ }
+ } else if (button_used) {
+ /* Button released */
+ button_used = 0;
+
+ debugC(6, kDebugLevelMenu | kDebugLevelInput, "button released!");
+
+ if (v_cur_menu < 0)
+ v_cur_menu = 0;
+
+ draw_menu_option_hilite(h_cur_menu, v_cur_menu);
+
+ if (mouse.y <= CHAR_LINES) {
+ /* on the menubar */
+ } else {
+ /* see which option we selected */
+ m = get_menu(h_cur_menu);
+ list_for_each(h, &m->down, next) {
+ d = list_entry(h, struct agi_menu_option, list);
+ if (mouse_over_text(2 + d->index,
+ m->wincol + 1, d->text)) {
+ /* activate that option */
+ if (d->enabled) {
+ debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
+ game.ev_keyp[d->event].occured = true;
+ game.ev_keyp[d->event].data = d->event;
+ goto exit_menu;
+ }
+ }
+ }
+ goto exit_menu;
+ }
+ }
+#endif /* USE_MOUSE */
+
+ if (!menu_active) {
+ if (h_cur_menu >= 0) {
+ draw_menu_hilite(h_cur_menu);
+ draw_menu_option(h_cur_menu);
+ if (!button_used && v_cur_menu >= 0)
+ draw_menu_option_hilite(h_cur_menu, v_cur_menu);
+ }
+ menu_active = true;
+ }
+
+ switch (key) {
+ case KEY_ESCAPE:
+ debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ESCAPE");
+ goto exit_menu;
+ case KEY_ENTER:
+ debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ENTER");
+ d = get_menu_option(h_cur_menu, v_cur_menu);
+ if (d->enabled) {
+ debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
+ game.ev_keyp[d->event].occured = true;
+ goto exit_menu;
+ }
+ break;
+ case KEY_DOWN:
+ case KEY_UP:
+ v_cur_menu += key == KEY_DOWN ? 1 : -1;
+
+ if (v_cur_menu < 0)
+ v_cur_menu = 0;
+ if (v_cur_menu > v_max_menu[h_cur_menu])
+ v_cur_menu = v_max_menu[h_cur_menu];
+
+ draw_menu_option(h_cur_menu);
+ draw_menu_option_hilite(h_cur_menu, v_cur_menu);
+ break;
+ case KEY_RIGHT:
+ case KEY_LEFT:
+ h_cur_menu += key == KEY_RIGHT ? 1 : -1;
+
+ if (h_cur_menu < 0)
+ h_cur_menu = h_max_menu;
+ if (h_cur_menu > h_max_menu)
+ h_cur_menu = 0;
+
+ v_cur_menu = 0;
+ new_menu_selected(h_cur_menu);
+ draw_menu_option_hilite(h_cur_menu, v_cur_menu);
+ break;
+ }
+
+ return true;
+
+exit_menu:
+ button_used = 0;
+ show_pic();
+ write_status();
+
+ setvar(V_key, 0);
+ game.keypress = 0;
+ game.clock_enabled = clock_val;
+ old_input_mode();
+ debugC(3, kDebugLevelMenu, "exit_menu: input mode reset to %d", game.input_mode);
+ menu_active = false;
+
+ return true;
+}
+
+void menu_set_item(int event, int state) {
+ struct list_head *h, *v;
+ struct agi_menu *m = NULL;
+ struct agi_menu_option *d = NULL;
+
+ /* scan all menus for event number # */
+
+ debugC(6, kDebugLevelMenu, "event = %d, state = %d", event, state);
+ list_for_each(h, &menubar, next) {
+ m = list_entry(h, struct agi_menu, list);
+ list_for_each(v, &m->down, next) {
+ d = list_entry(v, struct agi_menu_option, list);
+ if (d->event == event) {
+ d->enabled = state;
+ return;
+ }
+ }
+ }
+}
+
+void menu_enable_all() {
+ struct list_head *h, *v;
+ struct agi_menu *m = NULL;
+ struct agi_menu_option *d = NULL;
+
+ list_for_each(h, &menubar, next) {
+ m = list_entry(h, struct agi_menu, list);
+ list_for_each(v, &m->down, next) {
+ d = list_entry(v, struct agi_menu_option, list);
+ d->enabled = true;
+ }
+ }
+
+}
+
+} // End of namespace Agi