Logo Search packages:      
Sourcecode: scummvm version File versions

menu.cpp

/* 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: https://svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-9-1/engines/agi/menu.cpp $
 * $Id: menu.cpp 23011 2006-06-10 13:20:29Z ender $
 *
 */

#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 "common/list.h"

namespace Agi {

Menu* menu;

// TODO: add constructor/destructor for agi_menu, agi_menu_option

struct agi_menu_option {
      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 */
};

struct agi_menu {
      MenuOptionList 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 */
};

agi_menu *Menu::get_menu(int i) {
      MenuList::iterator iter;
      for (iter = menubar.begin(); iter != menubar.end(); ++iter) {
            agi_menu *m = *iter;
            if (m->index == i)
                  return m;
      }
      return NULL;
}

agi_menu_option *Menu::get_menu_option(int i, int j) {
      agi_menu *m = get_menu(i);
      MenuOptionList::iterator iter;
      for (iter = m->down.begin(); iter != m->down.end(); ++iter) {     
            agi_menu_option* d = *iter;
            if (d->index == j)
                  return d;
      }

      return NULL;
}

void Menu::draw_menu_bar() {
      _text->clear_lines(0, 0, MENU_BG);
      _text->flush_lines(0, 0);

      MenuList::iterator iter;
      for (iter = menubar.begin(); iter != menubar.end(); ++iter) {     
            agi_menu *m = *iter;
            _text->print_text(m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG);
      }

}

void Menu::draw_menu_hilite(int cur_menu) {
      agi_menu *m = get_menu(cur_menu);
      debugC(6, kDebugLevelMenu, "[%s]", m->text);
      _text->print_text(m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG);
      _text->flush_lines(0, 0);
}

/* draw box and pulldowns. */
void Menu::draw_menu_option(int h_menu) {
      /* find which vertical menu it is */
      agi_menu *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);

      MenuOptionList::iterator iter;
      for (iter = m->down.begin(); iter != m->down.end(); ++iter) {     
            agi_menu_option* d = *iter;
            _text->print_text(d->text, 0, m->wincol + 1, d->index + 2, m->width + 2,
                        d->enabled ? MENU_FG : MENU_DISABLED, MENU_BG);
      }
}

void Menu::draw_menu_option_hilite(int h_menu, int v_menu) {
      agi_menu *m = get_menu(h_menu);
      agi_menu_option *d = get_menu_option(h_menu, v_menu);

      _text->print_text(d->text, 0, m->wincol + 1, v_menu + 2, m->width + 2,
                  MENU_BG, d->enabled ? MENU_FG : MENU_DISABLED);
}

void Menu::new_menu_selected(int i) {
      show_pic();
      draw_menu_bar();
      draw_menu_hilite(i);
      draw_menu_option(i);
}

bool Menu::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;
}

#if 0
static void add_about_option() {
      const char *text = "About AGI engine";

      agi_menu_option *d = new agi_menu_option;
      d->text = strdup(text);
      d->enabled = true;
      d->event = 255;
      d->index = (v_max_menu[0] += 1);

      agi_menu *m = *menubar.begin();
      m->down.push_back(d);
      m->height++;
      if (m->width < (int)strlen(text))
            m->width = strlen(text);
}
#endif

/*
 * Public functions
 */

Menu::Menu() {
      h_index = 0;
      h_col = 1;
      h_cur_menu = 0;
      v_cur_menu = 0;
}

Menu::~Menu() {
      MenuList::iterator iterh;
      for (iterh = menubar.reverse_begin(); iterh != menubar.end(); ) {
            agi_menu *m = *iterh;
            debugC(3, kDebugLevelMenu, "deiniting hmenu %s", m->text);
            MenuOptionList::iterator iterv;
            for (iterv = m->down.reverse_begin(); iterv != m->down.end(); ) {
                  agi_menu_option *d = *iterv;
                  debugC(3, kDebugLevelMenu, "  deiniting vmenu %s", d->text);
                  free(d->text);
                  delete d;
                  iterv = m->down.reverse_erase(iterv);
            }
            free(m->text);
            delete m;
            iterh = menubar.reverse_erase(iterh);
      }
}

void Menu::add(const char *s) {
      agi_menu *m = new agi_menu;
      m->text = strdup(s);
      while (m->text[strlen(m->text) - 1] == ' ')
            m->text[strlen(m->text) - 1] = 0;
      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)]);
      menubar.push_back(m);
}

void Menu::add_item(const char *s, int code) {
      int l;

      agi_menu_option* d = new agi_menu_option;
      d->text = strdup(s);
      d->enabled = true;
      d->event = code;
      d->index = v_index++;

      // add to last menu in list
      assert(menubar.reverse_begin() != menubar.end());
      agi_menu *m = *menubar.reverse_begin();
      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);
      m->down.push_back(d);
}

void Menu::submit() {
      debugC(3, kDebugLevelMenu, "Submitting menu");

      /* add_about_option (); */

      /* If a menu has no options, delete it */
      MenuList::iterator iter;
      for (iter = menubar.reverse_begin(); iter != menubar.end(); ) {
            agi_menu *m = *iter;
            if (m->down.empty()) {
                  free(m->text);
                  delete m;
                  h_max_menu--;
                  iter = menubar.reverse_erase(iter);
            } else {
                  --iter;
            }
      }
}

bool Menu::keyhandler(int key) {
      static int clock_val;
      static int menu_active = false;
      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();
      }
      /*
       * 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;

                  MenuList::iterator iterh;
                  for (iterh = menubar.begin(); iterh != menubar.end(); ++iterh) {
                        agi_menu *m = *iterh;
                        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 */
                  vmenu = 0;

                  agi_menu *m = get_menu(h_cur_menu);
                  MenuOptionList::iterator iterv;
                  for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                        agi_menu_option *do1 = *iterv;
                        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 */
                  agi_menu *m = get_menu(h_cur_menu);
                  MenuOptionList::iterator iterv;
                  for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                        agi_menu_option *d = *iterv;
                        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;
            }
      }

      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");
            agi_menu_option* 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();
      _text->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) {
      /* scan all menus for event number # */

      debugC(6, kDebugLevelMenu, "event = %d, state = %d", event, state);
      MenuList::iterator iterh;
      for (iterh = menubar.begin(); iterh != menubar.end(); ++iterh) {
            agi_menu *m = *iterh;
            MenuOptionList::iterator iterv;
            for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                  agi_menu_option *d = *iterv;
                  if (d->event == event) {
                        d->enabled = state;
                        return;
                  }
            }
      }
}

void Menu::enable_all() {
      MenuList::iterator iterh;
      for (iterh = menubar.begin(); iterh != menubar.end(); ++iterh) {
            agi_menu *m = *iterh;
            MenuOptionList::iterator iterv;
            for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                  agi_menu_option *d = *iterv;
                  d->enabled = true;
            }
      }
}

}                             // End of namespace Agi

Generated by  Doxygen 1.6.0   Back to index