scummvm/engines/sci/engine/kmenu.cpp
2009-03-25 16:37:50 +00:00

339 lines
9.0 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 "sci/scicore/resource.h"
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
#include "sci/gfx/gfx_gui.h"
#include "sci/gfx/menubar.h"
#include "sci/gfx/gfx_state_internal.h" // required for gfxw_port_t, gfxw_visual_t
namespace Sci {
reg_t kAddMenu(EngineState *s, int funct_nr, int argc, reg_t *argv) {
char *name = kernel_dereference_char_pointer(s, argv[0], 0);
char *contents = kernel_dereference_char_pointer(s, argv[1], 0);
s->_menubar->addMenu(s->gfx_state, name,
contents, s->titlebar_port->font_nr, argv[1]);
return s->r_acc;
}
reg_t kSetMenu(EngineState *s, int funct_nr, int argc, reg_t *argv) {
int index = UKPV(0);
int i = 2;
while (i < argc) {
s->_menubar->setAttribute(s, (index >> 8) - 1, (index & 0xff) - 1, UKPV(i - 1), argv[i]);
i += 2;
}
return s->r_acc;
}
reg_t kGetMenu(EngineState *s, int funct_nr, int argc, reg_t *argv) {
int index = UKPV(0);
return s->_menubar->getAttribute((index >> 8) - 1, (index & 0xff) - 1, UKPV(1));
}
reg_t kDrawStatus(EngineState *s, int funct_nr, int argc, reg_t *argv) {
reg_t text = argv[0];
int fgcolor = SKPV_OR_ALT(1, s->status_bar_foreground);
int bgcolor = SKPV_OR_ALT(2, s->status_bar_background);
s->titlebar_port->color.visual = get_pic_color(s, fgcolor);
s->titlebar_port->color.mask = GFX_MASK_VISUAL;
s->titlebar_port->bgcolor.visual = get_pic_color(s, bgcolor);
s->titlebar_port->bgcolor.mask = GFX_MASK_VISUAL;
s->status_bar_foreground = fgcolor;
s->status_bar_background = bgcolor;
if (text.segment) {
const char *tmp = sci_strdup(kernel_dereference_char_pointer(s, text, 0));
s->_statusBarText = tmp ? tmp : "";
}
sciw_set_status_bar(s, s->titlebar_port, s->_statusBarText, fgcolor, bgcolor);
gfxop_update(s->gfx_state);
return s->r_acc;
}
reg_t kDrawMenuBar(EngineState *s, int funct_nr, int argc, reg_t *argv) {
if (SKPV(0))
sciw_set_menubar(s, s->titlebar_port, s->_menubar, -1);
else
sciw_set_status_bar(s, s->titlebar_port, "", 0, 0);
s->titlebar_port->draw(GFXW(s->titlebar_port), Common::Point(0, 0));
gfxop_update(s->gfx_state);
return s->r_acc;
}
static int _menu_go_down(Menubar *menubar, int menu_nr, int item_nr) {
int seeker;
const int max = menubar->_menus[menu_nr]._items.size();
seeker = item_nr + 1;
while ((seeker < max) && !menubar->itemValid(menu_nr, seeker))
++seeker;
if (seeker != max)
return seeker;
else
return item_nr;
}
#define FULL_REDRAW \
s->visual->draw(GFXW(s->visual), Common::Point(0, 0)); \
gfxop_update(s->gfx_state);
reg_t kMenuSelect(EngineState *s, int funct_nr, int argc, reg_t *argv) {
reg_t event = argv[0];
/*int pause_sound = UKPV_OR_ALT(1, 1);*/ /* FIXME: Do this eventually */
bool claimed = false;
int type = GET_SEL32V(event, type);
int message = GET_SEL32V(event, message);
int modifiers = GET_SEL32V(event, modifiers);
int menu_nr = -1, item_nr = 0;
MenuItem *item;
int menu_mode = 0; /* Menu is active */
int mouse_down = 0;
gfxop_set_clip_zone(s->gfx_state, gfx_rect_fullscreen);
/* Check whether we can claim the event directly as a keyboard or said event */
if (type & (SCI_EVT_KEYBOARD | SCI_EVT_SAID)) {
int menuc, itemc;
if ((type == SCI_EVT_KEYBOARD)
&& (message == SCI_K_ESC))
menu_mode = 1;
else if ((type == SCI_EVT_SAID) || message) { /* Don't claim 0 keyboard event */
SCIkdebug(SCIkMENU, "Menu: Got %s event: %04x/%04x\n",
((type == SCI_EVT_SAID) ? "SAID" : "KBD"), message, modifiers);
for (menuc = 0; menuc < (int)s->_menubar->_menus.size(); menuc++)
for (itemc = 0; itemc < (int)s->_menubar->_menus[menuc]._items.size(); itemc++) {
item = &s->_menubar->_menus[menuc]._items[itemc];
SCIkdebug(SCIkMENU, "Menu: Checking against %s: %04x/%04x (type %d, %s)\n",
!item->_text.empty() ? item->_text.c_str() : "--bar--", item->_key, item->_modifiers,
item->_type, item->_enabled ? "enabled" : "disabled");
if (((item->_type == MENU_TYPE_NORMAL)
&& (item->_enabled))
&& (((type == SCI_EVT_KEYBOARD) /* keyboard event */
&& item->matchKey(message, modifiers))
|| ((type == SCI_EVT_SAID) /* Said event */
&& (item->_flags & MENU_ATTRIBUTE_FLAGS_SAID)
&& (said(s, item->_said, (s->debug_mode & (1 << SCIkPARSER_NR))) != SAID_NO_MATCH)
)
)
) {
/* Claim the event */
SCIkdebug(SCIkMENU, "Menu: Event CLAIMED for %d/%d\n", menuc, itemc);
claimed = true;
menu_nr = menuc;
item_nr = itemc;
}
}
}
}
if ((type == SCI_EVT_MOUSE_PRESS) && (s->gfx_state->pointer_pos.y < 10)) {
menu_mode = 1;
mouse_down = 1;
}
if (menu_mode) {
int old_item;
int old_menu;
gfxw_port_t *port = NULL;
item_nr = -1;
/* Default to menu 0, unless the mouse was used to generate this effect */
if (mouse_down)
s->_menubar->mapPointer(s->gfx_state->pointer_pos, menu_nr, item_nr, port);
else
menu_nr = 0;
sciw_set_menubar(s, s->titlebar_port, s->_menubar, menu_nr);
FULL_REDRAW;
old_item = -1;
old_menu = -1;
while (menu_mode) {
sci_event_t ev = gfxop_get_event(s->gfx_state, SCI_EVT_ANY);
claimed = false;
switch (ev.type) {
case SCI_EVT_QUIT:
quit_vm();
return NULL_REG;
case SCI_EVT_KEYBOARD:
switch (ev.data) {
case '`':
if (ev.buckybits & SCI_EVM_CTRL)
s->visual->print(GFXW(s->visual), 0);
break;
case SCI_K_ESC:
menu_mode = 0;
break;
case SCI_K_ENTER:
menu_mode = 0;
if ((item_nr >= 0) && (menu_nr >= 0))
claimed = true;
break;
case SCI_K_LEFT:
if (menu_nr > 0)
--menu_nr;
else
menu_nr = s->_menubar->_menus.size() - 1;
item_nr = _menu_go_down(s->_menubar, menu_nr, -1);
break;
case SCI_K_RIGHT:
if (menu_nr < ((int)s->_menubar->_menus.size() - 1))
++menu_nr;
else
menu_nr = 0;
item_nr = _menu_go_down(s->_menubar, menu_nr, -1);
break;
case SCI_K_UP:
if (item_nr > -1) {
do { --item_nr; }
while ((item_nr > -1) && !s->_menubar->itemValid(menu_nr, item_nr));
}
break;
case SCI_K_DOWN: {
item_nr = _menu_go_down(s->_menubar, menu_nr, item_nr);
}
break;
}
break;
case SCI_EVT_MOUSE_RELEASE:
menu_mode = (s->gfx_state->pointer_pos.y < 10);
claimed = !menu_mode && !s->_menubar->mapPointer(s->gfx_state->pointer_pos, menu_nr, item_nr, port);
mouse_down = 0;
break;
case SCI_EVT_MOUSE_PRESS:
mouse_down = 1;
break;
case SCI_EVT_NONE:
gfxop_sleep(s->gfx_state, 2500 / 1000);
break;
}
if (mouse_down)
s->_menubar->mapPointer(s->gfx_state->pointer_pos, menu_nr, item_nr, port);
if ((item_nr > -1 && old_item == -1) || (menu_nr != old_menu)) { /* Update menu */
sciw_set_menubar(s, s->titlebar_port, s->_menubar, menu_nr);
if (port)
port->widfree(GFXW(port));
port = sciw_new_menu(s, s->titlebar_port, s->_menubar, menu_nr);
s->wm_port->add(GFXWC(s->wm_port), GFXW(port));
if (item_nr > -1)
old_item = -42; /* Enforce redraw in next step */
else {
FULL_REDRAW;
}
} /* ...if the menu changed. */
/* Remove the active menu item, if neccessary */
if (item_nr != old_item) {
port = sciw_toggle_item(port, &(s->_menubar->_menus[menu_nr]), old_item, false);
port = sciw_toggle_item(port, &(s->_menubar->_menus[menu_nr]), item_nr, true);
FULL_REDRAW;
}
old_item = item_nr;
old_menu = menu_nr;
} /* while (menu_mode) */
if (port) {
port->widfree(GFXW(port));
port = NULL;
sciw_set_status_bar(s, s->titlebar_port, s->_statusBarText, s->status_bar_foreground, s->status_bar_background);
gfxop_update(s->gfx_state);
}
FULL_REDRAW;
}
if (claimed) {
PUT_SEL32(event, claimed, make_reg(0, 1));
if (menu_nr > -1) {
s->r_acc = make_reg(0, ((menu_nr + 1) << 8) | (item_nr + 1));
} else
s->r_acc = NULL_REG;
SCIkdebug(SCIkMENU, "Menu: Claim -> %04x\n", s->r_acc.offset);
} else
s->r_acc = NULL_REG; /* Not claimed */
return s->r_acc;
}
} // End of namespace Sci