/* 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-1/engines/m4/m4_menus.cpp $
 * $Id: m4_menus.cpp 47732 2010-01-31 00:42:47Z dreammaster $
 *
 */

#include "common/algorithm.h"		// for find()
#include "gui/dialog.h"
#include "gui/message.h"

#include "m4/m4_menus.h"
#include "m4/m4_views.h"
#include "m4/woodscript.h"
#include "m4/midi.h"

namespace M4 {

const char *EmptySaveString = "<empty>";

//--------------------------------------------------------------------------
// Callback methods
//
// Following is a set of callback methods used to handle the execution
// of buttons in the various dialogs
//--------------------------------------------------------------------------

// General function which simply closes the active menu

void OrionCallbacks::closeMenuFn(DialogView *view, MenuObject *item) {
	view->close();
}

void OrionCallbacks::closeMenuFn(OrionMenuView *view) {
	closeMenuFn(view, NULL);
}

/* Game menu functions */

void OrionCallbacks::gameOptionsMenuFn(DialogView *view, MenuObject *item) {
	view->vm()->loadMenu(OPTIONS_MENU);
	view->close();
}

void OrionCallbacks::gameSaveGameFn(DialogView *view, MenuObject *item) {
	view->vm()->loadMenu(SAVE_MENU);
	view->close();
}

void OrionCallbacks::gameLoadGameFn(DialogView *view, MenuObject *item) {
	view->vm()->loadMenu(LOAD_MENU);
	view->close();
}

void OrionCallbacks::gameExitFn(DialogView *view, MenuObject *item) {
	view->vm()->_events->quitFlag = true;
	view->close();
}

/* Options menu */

void OrionCallbacks::optionsDigiSliderFn(DialogView *view, MenuObject *item) {
	// Digi volume slider changed
	int percent = ((MenuHorizSlider *) item)->percent();

	view->vm()->_sound->setVolume(percent * 255 / 100);
}

void OrionCallbacks::optionsMidiSliderFn(DialogView *view, MenuObject *item) {
	// Midi volume slider changed
	int percent = ((MenuHorizSlider *) item)->percent();

	view->vm()->midi()->setVolume(percent * 255 / 100);
}

void OrionCallbacks::optionsScrollingFn(DialogView *view, MenuObject *item) {
	// TODO: Change current Digi volume settings here
}

void OrionCallbacks::optionsCancelFn(DialogView *view, MenuObject *item) {
	// TODO: Reset original option settings here
	OrionMenuView *vw = (OrionMenuView *) view;

	vw->vm()->midi()->setVolume(vw->_originalMidiVolume);

	vw->vm()->loadMenu(GAME_MENU);
	vw->close();
}

void OrionCallbacks::optionsDoneFn(DialogView *view, MenuObject *item) {
	view->vm()->loadMenu(GAME_MENU);
	view->close();
}

void OrionCallbacks::optionsReturnFn(OrionMenuView *view) {
	optionsDoneFn(view, NULL);
}

void OrionCallbacks::optionsEscapeFn(OrionMenuView *view) {
	optionsCancelFn(view, NULL);
}

/* Save/Load dialog functions */

// Save the current game

void OrionCallbacks::saveLoadSaveFn(DialogView *view, MenuObject *item) {
	if (view->_selectedSlot == -1)
		return;

	MenuTextField *textItem = (MenuTextField *) view->getItem(SLTAG_TEXTFIELD);
	if (!textItem)
		return;

	textItem->setState(OS_NORMAL);

	// Save the game
	bool succeeded = view->vm()->_saveLoad->save(view->_selectedSlot + 1, textItem->getText());

	if (!succeeded) {
		GUI::MessageDialog dialog("Save game failed!");
		dialog.runModal();
	}

	// Close the menu
	closeMenuFn(view, item);
}

void OrionCallbacks::saveLoadLoadFn(DialogView *view, MenuObject *item) {
	// TODO: load the selected save game
	closeMenuFn(view, item);
}

void OrionCallbacks::saveLoadSlotFn(DialogView *view, MenuObject *item) {
	OrionMenuView *vw = (OrionMenuView *) view;
	MenuSaveLoadText *button = (MenuSaveLoadText *) item;

	view->_selectedSlot = button->getIndex();
	view->_deleteSaveDesc = true;

	// Disable all the slots except the selected one
	for (int index = 0; index < SL_NUM_VISIBLE_SLOTS; ++index) {
		MenuSaveLoadText *currentItem = (MenuSaveLoadText *) view->getItem(SLTAG_SLOTS_START + index);
		if (currentItem->getIndex() != button->getIndex()) {
			currentItem->setState(OS_GREYED);
		}
	}

	// Get a copy of the slot bounds
	Common::Rect slotBounds = button->getBounds();

	if (view->getMenuType() == SAVE_MENU) {
		// Add in a text field for entry of the savegame name
		vw->items().push_back(new MenuTextField(view, SLTAG_TEXTFIELD,
			slotBounds.left, slotBounds.top, slotBounds.width(), slotBounds.height(), false,
			saveLoadSaveFn, (button->getText() == EmptySaveString) ? NULL : button->getText(),
			button->getIndex() + 1));

	} else {
		vw->items().push_back(new MenuTextField(view, SLTAG_TEXTFIELD,
			slotBounds.left, slotBounds.top, slotBounds.width(), slotBounds.height(), true,
			saveLoadLoadFn, button->getText(), button->getIndex() + 1));
	}

	// Hide the existing slot
	button->setVisible(false);

	// Disable the slider

	MenuVertSlider *slider = (MenuVertSlider *) view->getItem(SLTAG_VSLIDER);
	slider->setState(OS_GREYED);

	// Enable the save/load button
	MenuButton *btn = (MenuButton *) view->getItem(SLTAG_SAVELOAD);
	btn->setState(OS_NORMAL);
}

void OrionCallbacks::saveLoadCancelFn(DialogView *view, MenuObject *item) {
	OrionMenuView *vw = (OrionMenuView *) view;

	if (view->_selectedSlot != -1) {
		// Pressed cancel with a save selected, so revert back to no selection

		// Re-enable all the other slots

		for (int index = 0; index < SL_NUM_VISIBLE_SLOTS; ++index) {
			if (index != view->_selectedSlot) {
				MenuSaveLoadText *currentItem = (MenuSaveLoadText *) view->getItem(SLTAG_SLOTS_START + index);
				currentItem->setState(OS_NORMAL);
			}
		}

		// Show the previously hidden slot again
		MenuSaveLoadText *slot = (MenuSaveLoadText *) view->getItem(SLTAG_SLOTS_START + view->_selectedSlot);
		slot->setVisible(true);
		slot->setState(OS_NORMAL);

		// Remove the text selection
		MenuTextField *textField = (MenuTextField *) view->getItem(SLTAG_TEXTFIELD);
		delete textField;
		vw->items().remove(textField);

		// Set button enablement
		MenuButton *btn = (MenuButton *) view->getItem(SLTAG_SAVELOAD);
		btn->setState(OS_GREYED);
		btn = (MenuButton *) view->getItem(SLTAG_CANCEL);
		btn->setState(OS_NORMAL);

		// Re-enable the slider

		MenuVertSlider *slider = (MenuVertSlider *) view->getItem(SLTAG_VSLIDER);
		slider->setState(OS_NORMAL);

		view->_selectedSlot = -1;

	} else {
		// Close the dialog
		if (vw->_loadSaveFromHotkey)
			// Since dialog was called from hotkey, return directly to the game
			closeMenuFn(view, item);
		else {
			// Return to the game menu
			view->vm()->loadMenu(GAME_MENU);
			view->close();
		}
	}
}

void OrionCallbacks::saveLoadSliderFn(DialogView *view, MenuObject *item) {
	OrionMenuView *vw = (OrionMenuView *) view;
	MenuVertSlider *slider = (MenuVertSlider *) item;

	if (slider->sliderState() == VSLIDER_THUMBNAIL) {
		// Callback generated by slider thumb, so set top slot using slider percentage
		vw->setTopSaveSlot(slider->percent() * 89 / 100);

	} else {
		int newIndex = view->_topSaveSlotIndex;

		switch (slider->sliderState()) {
		case VSLIDER_UP:
			if (newIndex > 0)
				--newIndex;
			break;

		case VSLIDER_PAGE_UP:
			if (newIndex > 0)
				newIndex = MAX(newIndex - 10, 0);
			break;

		case VSLIDER_PAGE_DOWN:
			if (newIndex < 89)
				newIndex = MIN(newIndex + 10, 89);
			break;

		case VSLIDER_DOWN:
			if (newIndex < 89)
				++newIndex;
			break;

		default:
			break;
		}

		if (newIndex != view->_topSaveSlotIndex) {
			// Set the new top slot
			vw->setTopSaveSlot(newIndex);

			// Set the new slider position
			slider->setPercentage(newIndex * 100 / 89);
		}
	}
}

void OrionCallbacks::saveLoadEscapeFn(OrionMenuView *view) {
	saveLoadCancelFn(view, NULL);
}

void OrionCallbacks::saveLoadReturnFn(OrionMenuView *view) {
	MenuTextField *textItem = (MenuTextField *) view->getItem(SLTAG_TEXTFIELD);
	if (textItem) {
		if (view->getMenuType() == SAVE_MENU)
			saveLoadSaveFn(view, NULL);
		else
			saveLoadLoadFn(view, NULL);
	}
}

//--------------------------------------------------------------------------

OrionMenuView::OrionMenuView(MadsM4Engine *Vm, int x, int y, MenuType menuType, bool calledFromMainMenu,
		bool loadSaveFromHotkey): DialogView(Vm, x, y, true) {
	_menuType = menuType;
	_screenType = VIEWID_MENU;
	_screenFlags.layer = LAYER_MENU;
	_screenFlags.get = SCREVENT_ALL;
	_screenFlags.blocks = SCREVENT_ALL;
	_screenFlags.immovable = true;
	//_screenFlags.immovable = false;	// uncomment to make menu movable
	_coords.left = x;
	_coords.top = y;
	_currentItem = NULL;
	_escapeHandler = &OrionCallbacks::closeMenuFn;
	_returnHandler = NULL;
	_saveNames = NULL;
	_savegameThumbnail = NULL;
	_deleteSaveDesc = false;
	_closeFlag = false;

	_calledFromMainMenu = calledFromMainMenu;
	_loadSaveFromHotkey = loadSaveFromHotkey;

	_interfaceWasVisible = _m4Vm->scene()->getInterface()->isVisible();
	if (_interfaceWasVisible)
		_m4Vm->scene()->getInterface()->hide();

	_vm->_mouse->setCursorNum(CURSOR_ARROW);

	switch (menuType) {
	case GAME_MENU:
		loadSprites(MENU_GAME);

		// Add menu contents
		_menuObjects.push_back(new MenuButton(this, BTNID_MAIN, 45, 53, 24, 24, &OrionCallbacks::closeMenuFn));
		_menuObjects.push_back(new MenuButton(this, BTNID_OPTIONS, 45, 94, 24, 24, &OrionCallbacks::gameOptionsMenuFn));
		_menuObjects.push_back(new MenuButton(this, BTNID_RESUME, 45, 135, 24, 24, &OrionCallbacks::closeMenuFn));
		_menuObjects.push_back(new MenuButton(this, BTNID_QUIT, 141, 135, 24, 24, &OrionCallbacks::gameExitFn));
		_menuObjects.push_back(new MenuButton(this, BTNID_SAVE, 141, 53, 24, 24, &OrionCallbacks::gameSaveGameFn, _calledFromMainMenu));
		_menuObjects.push_back(new MenuButton(this, BTNID_LOAD, 141, 94, 24, 24, &OrionCallbacks::gameLoadGameFn,
			!_vm->_saveLoad->hasSaves()));

		_escapeHandler = &OrionCallbacks::closeMenuFn;
		_returnHandler = &OrionCallbacks::closeMenuFn;
		break;

	case OPTIONS_MENU:
		loadSprites(MENU_OPTIONS);

		// Store the original settings in case user aborts dialog
		_originalMidiVolume = _vm->midi()->getVolume();

		// Add menu contents
		// TODO: Currently the Digi slider isn't hooked up to anything
		_menuObjects.push_back(new MenuButton(this, OPTIONID_CANCEL, 93, 141, 74, 43,
			&OrionCallbacks::optionsCancelFn, false, false, OBJTYPE_OM_CANCEL));
		_menuObjects.push_back(new MenuButton(this, OPTIONID_DONE, 168, 141, 74, 43,
			&OrionCallbacks::optionsDoneFn, false, false, OBJTYPE_OM_DONE));
		_menuObjects.push_back(new MenuHorizSlider(this, OPTIONID_HSLIDER_MIDI, 47, 64, 212, 24,
			_originalMidiVolume * 100 / 255, &OrionCallbacks::optionsMidiSliderFn, true));
		_menuObjects.push_back(new MenuHorizSlider(this, OPTIONID_HSLIDER_DIGI, 47, 104, 212, 24,
			0, &OrionCallbacks::optionsDigiSliderFn, true));

		_escapeHandler = &OrionCallbacks::optionsEscapeFn;
		_returnHandler = &OrionCallbacks::optionsReturnFn;
		break;

	case SAVE_MENU:
	case LOAD_MENU:
		loadSprites(MENU_SAVELOAD);

		// Set up the defaults for the window
		_topSaveSlotIndex = 0;
		_selectedSlot = -1;
		_highlightedSlot = -1;
		_saveNames = _vm->_saveLoad->getSaves();

		// Set up menu elements
		_menuObjects.push_back(new MenuMessage(this, SLTAG_SAVELOAD_LABEL, 50, 241, 70, 16));
		_menuObjects.push_back(new MenuButton(this, SLTAG_SAVELOAD, 214, 384, 72, 41,
			(menuType == SAVE_MENU) ? &OrionCallbacks::saveLoadSaveFn : &OrionCallbacks::saveLoadLoadFn,
			true, true, (menuType == SAVE_MENU) ? OBJTYPE_SL_SAVE : OBJTYPE_SL_LOAD));
		_menuObjects.push_back(new MenuButton(this, SLTAG_CANCEL, 139, 384, 74, 43,
			&OrionCallbacks::saveLoadCancelFn, false, false, OBJTYPE_SL_CANCEL));
		_menuObjects.push_back(new MenuVertSlider(this, SLTAG_VSLIDER, 291, 255, 23, 127, 0,
			&OrionCallbacks::saveLoadSliderFn));

		if (_menuType == SAVE_MENU)
			_savegameThumbnail = createThumbnail();

		_menuObjects.push_back(new MenuImage(this, SLTAG_THUMBNAIL, 66, 28, 215, 162,
			(_savegameThumbnail == NULL) ? _sprites->getFrame(SL_EMPTY_THUMBNAIL) : _savegameThumbnail));


		{
			SaveGameIterator slot = _saveNames->begin();
			for (uint slotIndex = 0; slotIndex < SL_NUM_VISIBLE_SLOTS; ++slotIndex, ++slot) {
				// Get save slot
				bool isEmpty = (slotIndex >= _saveNames->size()) || (*slot).empty();

				_menuObjects.push_back(new MenuSaveLoadText(this, SLTAG_SLOTS_START + slotIndex,
					50, 256 + slotIndex * 15, 238, 15, &OrionCallbacks::saveLoadSlotFn,
					(menuType == LOAD_MENU) && isEmpty, true, (menuType == LOAD_MENU),
					isEmpty ? EmptySaveString : slot->c_str(), slotIndex + 1));
			}
		}

		_escapeHandler = &OrionCallbacks::saveLoadEscapeFn;
		_returnHandler = &OrionCallbacks::saveLoadReturnFn;
		break;

	default:
		error("Unknown menu type");
		break;
	}

	// Draw all the items onto the background surface
	for (MenuObjectsIterator i = _menuObjects.begin(); i != _menuObjects.end(); ++i)
		(*i)->onRefresh();
}

OrionMenuView::~OrionMenuView() {
	delete _sprites;

	for (MenuObjectList::iterator i = _menuObjects.begin(); i != _menuObjects.end(); ++i)
		delete *i;
	_menuObjects.clear();

	delete _saveNames;
	delete _savegameThumbnail;
}

bool OrionMenuView::loadSprites(const char *seriesName) {
	Common::SeekableReadStream *data = _vm->res()->get(seriesName);
	RGB8 *palette;

	_sprites = new SpriteAsset(_vm, data, data->size(), seriesName);
	palette = _sprites->getPalette();
	_vm->_palette->setPalette(palette, 0, _sprites->getColorCount());

	_vm->res()->toss(seriesName);

	// Update the palette
	//_vm->setPalette((byte *) _menuPalette, 59, 197);

	// The first sprite is the menu background

	M4Sprite *bg = _sprites->getFrame(0);
	this->setSize(bg->width(), bg->height());
	_coords.setWidth(bg->width());
	_coords.setHeight(bg->height());
	bg->copyTo(this);

	return true;
}

// Creates a thumbnail based on the current background screen

M4Surface *OrionMenuView::createThumbnail() {
	M4Surface srcSurface(_vm->_screen->width(), _vm->_screen->height());
	M4Surface *result = new M4Surface(_vm->_screen->width() / 3, _vm->_screen->height() / 3);

	// Translate the scene data

	_vm->_scene->onRefresh(NULL, &srcSurface);
	byte *srcP = srcSurface.getBasePtr(0, 0);
	byte *destP = result->getBasePtr(0, 0);

	for (int yCtr = 0; yCtr < _vm->_scene->height() / 3; ++yCtr, srcP += g_system->getWidth() * 3) {
		byte *src0P = srcP;
		byte *src1P = srcP + _vm->_screen->width();
		byte *src2P = src1P + _vm->_screen->width();

		for (int xCtr = 0; xCtr < result->width(); ++xCtr) {
			*destP = (byte)((uint32)((
				*src0P + *(src0P + 1) + *(src0P + 2) +
				*src1P + *(src1P + 1) + *(src1P + 2) +
				*src2P + *(src2P + 1) + *(src2P + 2)) / 9));
			if (*destP == 0)
				*destP = 21;

			++destP;
			src0P += 3;
			src1P += 3;
			src2P += 3;
		}
	}

	// Translate the game interface view - since it's using standard colors that can't be
	// averaged, simply take the top left pixel of every 3x3 pixel block

	_m4Vm->scene()->getInterface()->onRefresh(NULL, &srcSurface);
	destP = result->getBasePtr(0, 0) + (_vm->_screen->width() / 3) * (_m4Vm->scene()->getInterface()->bounds().top / 3);

	int yStart = _m4Vm->scene()->getInterface()->bounds().top;
	int yEnd = MIN(_vm->_screen->height() - 1, (int) _m4Vm->scene()->getInterface()->bounds().bottom - 1);
	for (int yCtr = yStart; yCtr <= yEnd; yCtr += 3) {
		srcP = (byte *)srcSurface.getBasePtr(0, yCtr) + (yCtr * _vm->_screen->width());

		for (int xCtr = 0; xCtr < result->width(); ++xCtr, srcP += 3)
			*destP++ = *srcP;
	}

	return result;
}

void OrionMenuView::destroyView() {
	MadsM4Engine *engine = _vm;
	bool interfaceVisible = _interfaceWasVisible;
	engine->_viewManager->deleteView(this);

	// Fade the game back in if no menu views are active (such as if a button was pressed in one menu
	// to activate another menu dialog)
	bool fadeIn = engine->_viewManager->getView(VIEWID_MENU) == NULL;

	if (fadeIn) {
		bool fadeToBlack = engine->_events->quitFlag;
		engine->_ws->update();
		engine->_palette->fadeFromGreen(M4_DIALOG_FADE_STEPS, M4_DIALOG_FADE_DELAY, fadeToBlack);

		if (interfaceVisible)
			engine->scene()->showInterface();
	}
}

bool OrionMenuView::onEvent(M4EventType eventType, int32 param, int x, int y, bool &captureEvents) {
	static Common::Point movingPos(0, 0);
	static bool movingFlag = false;

	bool handledFlag = false;
	int localX, localY;
	MenuObjectsIterator i;

	if (!_screenFlags.visible)
		return false;

	if (!movingFlag)
		captureEvents = false;

	// If the escape key is pressed, then pass onto the Escape handler

	if (eventType == KEVENT_KEY) {
		if ((param == Common::KEYCODE_ESCAPE) && (_escapeHandler != NULL)) {
			// Execute the Escape handler function
			_currentItem = NULL;
			captureEvents = false;
			_escapeHandler(this);
			destroyView();
			return true;
		}

		if (((param == Common::KEYCODE_RETURN) || (param == Common::KEYCODE_KP_ENTER)) &&
			(_returnHandler != NULL)) {
			// Execute the Return handler function
			_currentItem = NULL;
			captureEvents = false;
			_returnHandler(this);
			return true;
		}

		MenuTextField *textItem = (MenuTextField *) getItem(SLTAG_TEXTFIELD);
		if (textItem && textItem->onEvent(KEVENT_KEY, param, x, y, _currentItem))
			return true;
	}

	// Convert the screen position to a relative position within the menu surface
	localX = x - _coords.left;
	localY = y - _coords.top;

	// If there is an active object handling events, pass it on until it releases control

	if (_currentItem) {
		handledFlag = _currentItem->onEvent(eventType, param, localX, localY, _currentItem);

		if (_closeFlag) {
			// Dialog has been flagged to be closed
			captureEvents = false;
			destroyView();
			return true;
		}

		if (_currentItem) {
			captureEvents =
				(Common::find(_menuObjects.begin(), _menuObjects.end(), _currentItem) != _menuObjects.end());
			if (!captureEvents)
				// The menu object is no longer active, so reset current item
				_currentItem = NULL;
		} else {
			captureEvents = false;
		}

		if (handledFlag)
			return true;
	}

	if (eventType == KEVENT_KEY) {
		// Handle keypresses by looping through the item list to see if any of them want it

		for (i = _menuObjects.begin(); (i != _menuObjects.end()) && !handledFlag; ++i) {
			MenuObject *menuObj = *i;
			MenuObject *dummyItem;
			handledFlag = menuObj->onEvent(eventType, param, localX, localY, dummyItem);
		}

		return handledFlag;

	} else {
		// Handle mouse events by scanning the item list to see if the cursor is within any

		for (i = _menuObjects.begin(); (i != _menuObjects.end()) && !handledFlag; ++i) {
			MenuObject *menuObj = *i;

			if (menuObj->isInside(localX, localY)) {
				// Found an item, so pass it the event
				menuObj->onEvent(eventType, param, localX, localY, _currentItem);

				if (_closeFlag) {
					// Dialog has been flagged to be closed
					captureEvents = false;
					destroyView();
					return true;
				}

				if (_currentItem) {
					captureEvents =
						(Common::find(_menuObjects.begin(), _menuObjects.end(), _currentItem) != _menuObjects.end());
					if (!captureEvents)
						// The menu object is no longer active, so reset current item
						_currentItem = NULL;
				} else {
					captureEvents = false;
				}

				return true;
			}
		}
	}

	// None of the items have handled the event, so fall back on menu-wide event handling

	switch (eventType) {
	case MEVENT_LEFT_CLICK:
	case MEVENT_DOUBLECLICK:
		if (!_screenFlags.immovable) {
			// Move the entire dialog
			captureEvents = true;
			movingFlag = true;
			movingPos.x = x;
			movingPos.y = y;
		}
		break;

	case MEVENT_LEFT_DRAG:
	case MEVENT_DOUBLECLICK_DRAG:
		if (movingFlag) {
			moveRelative(x - movingPos.x, y - movingPos.y);
			movingPos.x = x;
			movingPos.y = y;
		}
		break;

	case MEVENT_LEFT_RELEASE:
	case MEVENT_DOUBLECLICK_RELEASE:
		captureEvents = false;
		movingFlag = false;
		break;

	default:
		break;
	}

	return true;
}

MenuObject *OrionMenuView::getItem(int objectId) {
	MenuObjectsIterator i;
	for (i = _menuObjects.begin(); i != _menuObjects.end(); ++i) {
		MenuObject *obj = *i;
		if (obj->getObjectId() == objectId)
			return obj;
	}

	return NULL;
}

void OrionMenuView::setTopSaveSlot(int slotNumber) {
	_topSaveSlotIndex = MAX(MIN(slotNumber, 89), 0);

	// Update the details of the load/save slots

	// Get save slot
	SaveGameIterator slot = _saveNames->begin();
	for (int i = 0; i < _topSaveSlotIndex; ++i)
		++slot;

	for (uint index = 0; index < SL_NUM_VISIBLE_SLOTS; ++index, ++slot) {
		MenuSaveLoadText *item = (MenuSaveLoadText *) getItem(SLTAG_SLOTS_START + index);
		uint slotIndex = _topSaveSlotIndex + index;

		bool isEmpty = (slotIndex >= _saveNames->size()) || slot->empty();
		item->setDisplay(slotIndex + 1, isEmpty ? EmptySaveString : slot->c_str());

		item->setState((_menuType == SAVE_MENU) || !isEmpty ? OS_NORMAL : OS_GREYED);
	}
}

void OrionMenuView::refresh(const Common::Rect &areaRect) {
	// Copy the selected portion of the background
	_sprites->getFrame(0)->copyTo(this, areaRect, areaRect.left, areaRect.top);

	for (MenuObjectsIterator i = _menuObjects.begin(); i != _menuObjects.end(); ++i) {
		MenuObject *obj = *i;
		if (obj->getBounds().intersects(areaRect))
			obj->onRefresh();
	}
}

}
