Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

menu.cpp

/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-1-0/engines/agi/menu.cpp $
 * $Id: menu.cpp 46942 2010-01-03 20:15:44Z sev $
 *
 */

#include "agi/agi.h"
#include "agi/graphics.h"
#include "agi/keyboard.h"
#include "agi/menu.h"

namespace Agi {

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

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

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

AgiMenuOption *Menu::getMenuOption(int i, int j) {
      AgiMenu *m = getMenu(i);
      MenuOptionList::iterator iter;

      for (iter = m->down.begin(); iter != m->down.end(); ++iter) {
            AgiMenuOption* d = *iter;
            if (d->index == j)
                  return d;
      }

      return NULL;
}

void Menu::drawMenuBar() {
      _vm->clearLines(0, 0, MENU_BG);
      _vm->flushLines(0, 0);

      MenuList::iterator iter;
      for (iter = _menubar.begin(); iter != _menubar.end(); ++iter) {
            AgiMenu *m = *iter;

            _vm->printText(m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG);
      }

}

void Menu::drawMenuHilite(int curMenu) {
      AgiMenu *m = getMenu(curMenu);

      debugC(6, kDebugLevelMenu, "[%s]", m->text);

      _vm->printText(m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG);
      _vm->flushLines(0, 0);
}

// draw box and pulldowns.
void Menu::drawMenuOption(int hMenu) {
      // find which vertical menu it is
      AgiMenu *m = getMenu(hMenu);

      _gfx->drawBox(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) {
            AgiMenuOption* d = *iter;

            _vm->printText(d->text, 0, m->wincol + 1, d->index + 2, m->width + 2,
                        MENU_FG, MENU_BG, !d->enabled);
      }
}

void Menu::drawMenuOptionHilite(int hMenu, int vMenu) {
      AgiMenu *m = getMenu(hMenu);
      AgiMenuOption *d = getMenuOption(hMenu, vMenu);

      // Disabled menu items are "greyed out" with a checkerboard effect,
      // rather than having a different colour. -- dsymonds
      _vm->printText(d->text, 0, m->wincol + 1, vMenu + 2, m->width + 2,
                  MENU_BG, MENU_FG, !d->enabled);
}

void Menu::newMenuSelected(int i) {
      _picture->showPic();
      drawMenuBar();
      drawMenuHilite(i);
      drawMenuOption(i);
}

bool Menu::mouseOverText(int line, int col, char *s) {
      if (_vm->_mouse.x < col * CHAR_COLS)
            return false;

      if (_vm->_mouse.x > (int)(col + strlen(s)) * CHAR_COLS)
            return false;

      if (_vm->_mouse.y < line * CHAR_LINES)
            return false;

      if (_vm->_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(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture) {
      _vm = vm;
      _gfx = gfx;
      _picture = picture;
      _hIndex = 0;
      _hCol = 1;
      _hMaxMenu = 0;
      _hCurMenu = 0;
      _vCurMenu = 0;
}

Menu::~Menu() {
      MenuList::iterator iterh;
      for (iterh = _menubar.reverse_begin(); iterh != _menubar.end(); ) {
            AgiMenu *m = *iterh;

            debugC(3, kDebugLevelMenu, "deiniting hmenu %s", m->text);

            MenuOptionList::iterator iterv;

            for (iterv = m->down.reverse_begin(); iterv != m->down.end(); ) {
                  AgiMenuOption *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) {
      AgiMenu *m = new AgiMenu;
      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 = _hIndex++;
      m->col = _hCol;
      m->wincol = _hCol - 1;
      _vIndex = 0;
      _vMaxMenu[m->index] = 0;
      _hCol += strlen(m->text) + 1;
      _hMaxMenu = m->index;

      debugC(3, kDebugLevelMenu, "add menu: '%s' %02x", s, m->text[strlen(m->text)]);
      _menubar.push_back(m);
}

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

      AgiMenuOption* d = new AgiMenuOption;

      d->text = strdup(s);
      d->enabled = true;
      d->event = code;
      d->index = _vIndex++;

      // add to last menu in list
      assert(_menubar.reverse_begin() != _menubar.end());
      AgiMenu *m = *_menubar.reverse_begin();
      m->height++;

      _vMaxMenu[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(); ) {
            AgiMenu *m = *iter;

            if (m->down.empty()) {
                  free(m->text);
                  delete m;

                  _hMaxMenu--;

                  iter = _menubar.reverse_erase(iter);
            } else {
                  --iter;
            }
      }
}

bool Menu::keyhandler(int key) {
      static int clockVal;
      static int menuActive = false;
      static int buttonUsed = 0;

      if (!_vm->getflag(fMenusWork) && !(_vm->getFeatures() & GF_MENUS))
            return false;

      if (!menuActive) {
            clockVal = _vm->_game.clockEnabled;
            _vm->_game.clockEnabled = false;
            drawMenuBar();
      }
      //
      // Mouse handling
      //
      if (_vm->_mouse.button) {
            int hmenu, vmenu;

            buttonUsed = 1;   // Button has been used at least once

            if (_vm->_mouse.y <= CHAR_LINES) {
                  // on the menubar
                  hmenu = 0;

                  MenuList::iterator iterh;

                  for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
                        AgiMenu *m = *iterh;

                        if (mouseOverText(0, m->col, m->text)) {
                              break;
                        } else {
                              hmenu++;
                        }
                  }

                  if (hmenu <= _hMaxMenu) {
                        if (_hCurMenu != hmenu) {
                              _vCurMenu = -1;
                              newMenuSelected(hmenu);
                        }
                        _hCurMenu = hmenu;
                  }
            } else {
                  // not in menubar
                  vmenu = 0;

                  AgiMenu *m = getMenu(_hCurMenu);

                  MenuOptionList::iterator iterv;

                  for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                        AgiMenuOption *do1 = *iterv;

                        if (mouseOverText(2 + do1->index, m->wincol + 1, do1->text)) {
                              break;
                        } else {
                              vmenu++;
                        }
                  }

                  if (vmenu <= _vMaxMenu[_hCurMenu]) {
                        if (_vCurMenu != vmenu) {
                              drawMenuOption(_hCurMenu);
                              drawMenuOptionHilite(_hCurMenu, vmenu);
                        }
                        _vCurMenu = vmenu;
                  }
            }
      } else if (buttonUsed) {
            // Button released
            buttonUsed = 0;

            debugC(6, kDebugLevelMenu | kDebugLevelInput, "button released!");

            if (_vCurMenu < 0)
                  _vCurMenu = 0;

            drawMenuOptionHilite(_hCurMenu, _vCurMenu);

            if (_vm->_mouse.y <= CHAR_LINES) {
                  // on the menubar
            } else {
                  // see which option we selected
                  AgiMenu *m = getMenu(_hCurMenu);
                  MenuOptionList::iterator iterv;

                  for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                        AgiMenuOption *d = *iterv;

                        if (mouseOverText(2 + d->index, m->wincol + 1, d->text)) {
                              // activate that option
                              if (d->enabled) {
                                    debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
                                    _vm->_game.controllerOccured[d->event] = true;
                                    _vm->_menuSelected = true;

                                    goto exit_menu;
                              }
                        }
                  }
                  goto exit_menu;
            }
      }

      if (!menuActive) {
            if (_hCurMenu >= 0) {
                  drawMenuHilite(_hCurMenu);
                  drawMenuOption(_hCurMenu);
                  if (!buttonUsed && _vCurMenu >= 0)
                        drawMenuOptionHilite(_hCurMenu, _vCurMenu);
            }
            menuActive = true;
      }

      switch (key) {
      case KEY_ESCAPE:
            debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ESCAPE");
            goto exit_menu;
      case KEY_ENTER:
      {
            debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ENTER");
            AgiMenuOption* d = getMenuOption(_hCurMenu, _vCurMenu);

            if (d->enabled) {
                  debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
                  _vm->_game.controllerOccured[d->event] = true;
                  _vm->_menuSelected = true;
                  goto exit_menu;
            }
            break;
      }
      case KEY_DOWN:
      case KEY_UP:
            _vCurMenu += key == KEY_DOWN ? 1 : -1;

            if (_vCurMenu < 0)
                  _vCurMenu = _vMaxMenu[_hCurMenu];
            if (_vCurMenu > _vMaxMenu[_hCurMenu])
                  _vCurMenu = 0;

            drawMenuOption(_hCurMenu);
            drawMenuOptionHilite(_hCurMenu, _vCurMenu);
            break;
      case KEY_RIGHT:
      case KEY_LEFT:
            _hCurMenu += key == KEY_RIGHT ? 1 : -1;

            if (_hCurMenu < 0)
                  _hCurMenu = _hMaxMenu;
            if (_hCurMenu > _hMaxMenu)
                  _hCurMenu = 0;

            _vCurMenu = 0;
            newMenuSelected(_hCurMenu);
            drawMenuOptionHilite(_hCurMenu, _vCurMenu);
            break;
      }

      return true;

exit_menu:
      buttonUsed = 0;
      _picture->showPic();
      _vm->writeStatus();

      _vm->setvar(vKey, 0);
      _vm->_game.keypress = 0;
      _vm->_game.clockEnabled = clockVal;
      _vm->oldInputMode();

      debugC(3, kDebugLevelMenu, "exit_menu: input mode reset to %d", _vm->_game.inputMode);
      menuActive = false;

      return true;
}

void Menu::setItem(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) {
            AgiMenu *m = *iterh;
            MenuOptionList::iterator iterv;

            for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                  AgiMenuOption *d = *iterv;

                  if (d->event == event) {
                        d->enabled = state;
                        // keep going; we need to set the state of every menu item
                        // with this event code. -- dsymonds
                  }
            }
      }
}

void Menu::enableAll() {
      MenuList::iterator iterh;
      for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
            AgiMenu *m = *iterh;
            MenuOptionList::iterator iterv;

            for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
                  AgiMenuOption *d = *iterv;

                  d->enabled = true;
            }
      }
}


00496 AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const {
      if (_amigaStyle) {
            if (positive) {
                  if (pressed) { // Positive pressed Amiga-style button
                        if (_olderAgi) {
                              return AgiTextColor(amigaBlack, amigaOrange);
                        } else {
                              return AgiTextColor(amigaBlack, amigaPurple);
                        }
                  } else { // Positive unpressed Amiga-style button
                        return AgiTextColor(amigaWhite, amigaGreen);
                  }
            } else { // _amigaStyle && !positive
                  if (pressed) { // Negative pressed Amiga-style button
                        return AgiTextColor(amigaBlack, amigaCyan);
                  } else { // Negative unpressed Amiga-style button
                        return AgiTextColor(amigaWhite, amigaRed);
                  }
            }
      } else { // PC-style button
            if (hasFocus || pressed) { // A pressed or in focus PC-style button
                  return AgiTextColor(pcWhite, pcBlack);
            } else { // An unpressed PC-style button without focus
                  return AgiTextColor(pcBlack, pcWhite);
            }
      }
}

00524 AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const {
      return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor));
}

00528 AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const {
      if (hasFocus || pressed)
            return baseColor.swap();
      else
            return baseColor;
}

00535 int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const {
      return (pressed && !_amigaStyle) ? 1 : 0;
}

00539 bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const {
      return _amigaStyle && !_authenticAmiga && (hasFocus || pressed);
}

00543 void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) {
      _amigaStyle       = amigaStyle;
      _olderAgi         = olderAgi;
      _authenticAmiga   = authenticAmiga;
}

00549 void AgiButtonStyle::setPcStyle(bool pcStyle) {
      setAmigaStyle(!pcStyle);
}

00553 AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) {
      setAmigaStyle(renderMode == Common::kRenderAmiga);
}

} // End of namespace Agi

Generated by  Doxygen 1.6.0   Back to index