Files
commandergenius/project/jni/application/enigma/src/gui/LevelPackMenu.cpp

482 lines
20 KiB
C++

/*
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck, Ronald Lamprecht
*
* 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.
*
*/
#include "gui/LevelPackMenu.hh"
#include "gui/LevelMenu.hh"
#include "gui/LPGroupConfig.hh"
#include "gui/LevelPackConfig.hh"
#include "gui/SearchMenu.hh"
#include "gui/HelpMenu.hh"
#include "ecl.hh"
#include "errors.hh"
#include "nls.hh"
#include "video.hh"
#include "lev/Index.hh"
#include "lev/PersistentIndex.hh"
#include "main.hh"
using namespace ecl;
using namespace std;
namespace enigma { namespace gui {
/* -------------------- Level Pack Menu -------------------- */
std::map<std::string, std::string> LevelPackMenu::groupLastSelectedIndex;
std::map<std::string, int> LevelPackMenu::groupLastSelectedColumn;
std::string LevelPackMenu::lastGroupName;
int LevelPackMenu::firstDisplayedGroup = 0;
static const char *helptext[] = {
N_("Left column:"), N_("Levelpack groups"),
N_("Right columns:"), N_("Levelpacks of selected group"),
N_("Left click:"), N_("Select group or levelpack"),
N_("Right or control click:"), N_("Configure group or levelpack"),
0
};
LevelPackMenu::LevelPackMenu() : packsHList (NULL), groupsVList (NULL),
scrollLeft (NULL), scrollRight (NULL), scrollUp (NULL),
scrollDown (NULL), isLevelMenuSubmenu (false) {
const video::VMInfo &vminfo = *video::GetInfo();
vm = vminfo.videomode;
// Create buttons - positioning identical to Levelmenu
but_level = new StaticTextButton(N_("Start Game"), this);
but_main = new StaticTextButton(N_("Main Menu"), this);
commandHList = new HList;
commandHList->set_spacing(60);
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
commandHList->set_default_size(160, 50);
commandHList->add_back(but_level);
commandHList->add_back(but_main);
this->add(commandHList, Rect(130, vminfo.height-70, vminfo.width-260, 50));
}
void LevelPackMenu::setupMenu() {
static struct SpacingConfig {
int packcolumns, rows;
int vmargin, vrow_row;
int hmargin, hgroup_pack, hscrollbutton, hscroll_pack, hpack_pack;
} param[video::VM_COUNT] = {
{ // VM_640x480
2, 8,
15, 10,
8, 36, 35, 10, 20
},
{ // VM_640x512
2, 9,
15, 10,
20, 36, 22, 10, 20
},
{ // VM_800x600
3, 11,
15, 13,
15, 36, 22, 10, 15
},
{ // VM_1024x768
4, 15,
15, 10,
30, 36, 22, 12, 20
}
};
if (groupsVList != NULL) {
groupsVList->clear();
remove_child(groupsVList);
delete groupsVList;
groupsVList = NULL;
scrollUp = NULL; // deleted with groupsVList
scrollDown = NULL; // deleted with groupsVList
}
if (packsHList != NULL) {
packsHList->clear();
remove_child(packsHList);
delete packsHList;
packsHList = NULL;
}
if (scrollLeft != NULL) {
remove_child(scrollLeft);
delete scrollLeft;
scrollLeft = NULL;
}
if (scrollRight != NULL) {
remove_child(scrollRight);
delete scrollRight;
scrollRight = NULL;
}
packButtons.clear();
groupButtons.clear();
std::vector<std::string> groupNames = lev::Index::getGroupNames();
int groupCount = groupNames.size();
std::string curGroupName = lev::Index::getCurrentGroup();
bool needUpScroll = false;
bool needDownScroll = false;
int numDisplayGroups = param[vm].rows;
int usedGroupRows = (groupCount > numDisplayGroups) ? numDisplayGroups : groupCount;
// correct scroll attempts and screen resolution changes
firstDisplayedGroup = ecl::Clamp<int>(firstDisplayedGroup, 0,
(groupCount > numDisplayGroups) ? groupCount - numDisplayGroups : 0);
needUpScroll = firstDisplayedGroup > 0;
needDownScroll = firstDisplayedGroup < groupCount - numDisplayGroups;
if (curGroupName != lastGroupName) {
// group changed by indirect user action - ensure it is visible
int curGroupPos = getGroupPosition(&groupNames, curGroupName);
if (curGroupPos != -1) {
if (curGroupPos <= firstDisplayedGroup ) {
if (curGroupPos <= 1) {
needUpScroll = false;
firstDisplayedGroup = 0;
} else {
needUpScroll = true;
firstDisplayedGroup = curGroupPos -1;
}
needDownScroll = firstDisplayedGroup < groupCount - numDisplayGroups;
} else if (curGroupPos >= firstDisplayedGroup + numDisplayGroups - 1) {
if (curGroupPos >= groupCount - 2) {
needDownScroll = false;
firstDisplayedGroup = groupCount - numDisplayGroups;
} else {
needDownScroll = true;
firstDisplayedGroup = curGroupPos - numDisplayGroups + 2;
}
if (firstDisplayedGroup < 0)
firstDisplayedGroup = 0;
needUpScroll = firstDisplayedGroup > 0;
}
}
}
groupsVList = new VList;
groupsVList->set_spacing(param[vm].vrow_row);
groupsVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
groupsVList->set_default_size(160, 35);
for (int i = 0; i < usedGroupRows; i++) {
if (i == 0 && needUpScroll) {
scrollUp = new ImageButton("ic-up", "ic-up1", this);
groupsVList->add_back(scrollUp);
} else if (i == usedGroupRows -1 && needDownScroll) {
scrollDown = new ImageButton("ic-down", "ic-down1", this);
groupsVList->add_back(scrollDown);
} else {
TextButton * button = new UntranslatedStaticTextButton(
groupNames[firstDisplayedGroup + i], this);;
groupButtons.push_back(button);
groupsVList->add_back(button);
}
}
this->add(groupsVList, Rect(param[vm].hmargin, param[vm].vmargin,
160, param[vm].rows * 35 +
(param[vm].rows - 1) * param[vm].vrow_row));
lastGroupName = curGroupName;
std::vector<lev::Index *> * group = lev::Index::getGroup(curGroupName);
ASSERT(group != NULL, XFrontend,"");
unsigned packCount = group->size();
int posCurrentIndex = getIndexPosition(group, lev::Index::getCurrentIndex()->getName());
int selectedColumn = lev::Index::getGroupSelectedColumn(curGroupName);
int colCurrentIndex = 0;
int nextPack = 0; // pack displayed at top of first display column
if (selectedColumn != INDEX_GROUP_COLUMN_UNKNOWN ||
groupLastSelectedIndex.find(curGroupName) == groupLastSelectedIndex.end()) {
colCurrentIndex = checkColumn(param[vm].rows, param[vm].packcolumns,
packCount, posCurrentIndex, selectedColumn);
nextPack = (posCurrentIndex / param[vm].rows - colCurrentIndex) * param[vm].rows;
} else {
// the user selected a new level pack and the column was not yet
// calculated: we try to keep the display unchanged in respect of
// of the last selected pack and if necessary scroll minimum amount
// of columns
int posLastIndex = getIndexPosition(group,groupLastSelectedIndex[curGroupName]);
int colLastIndex = checkColumn(param[vm].rows, param[vm].packcolumns,
packCount, posLastIndex, groupLastSelectedColumn[curGroupName]);
nextPack = (posLastIndex / param[vm].rows - colLastIndex) * param[vm].rows;
if (posCurrentIndex < nextPack) {
// current index would be left of display - we need to scroll left
nextPack -= (((nextPack - posCurrentIndex - 1)/param[vm].rows) + 1) *
param[vm].rows;
colCurrentIndex = 0;
} else if (posCurrentIndex < nextPack + param[vm].rows * param[vm].packcolumns) {
// current index is still visible - keep nextPack
colCurrentIndex = (posCurrentIndex - nextPack) / param[vm].rows;
} else {
// current index would be right of display - we need to scroll right
nextPack += (((posCurrentIndex - nextPack)/param[vm].rows) -
(param[vm].packcolumns - 1)) * param[vm].rows;
colCurrentIndex = param[vm].packcolumns - 1;
}
}
bool needRightScroll = packCount > nextPack + param[vm].rows * param[vm].packcolumns;
bool needLeftScroll = nextPack > 0;
lev::Index::setGroupSelectedColumn(curGroupName, colCurrentIndex);
groupLastSelectedIndex[curGroupName] = lev::Index::getCurrentIndex()->getName();
groupLastSelectedColumn[curGroupName] = colCurrentIndex;
packsHList = new HList;
packsHList->set_spacing(param[vm].hpack_pack);
packsHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
packsHList->set_default_size(160, param[vm].rows*35 +
(param[vm].rows - 1) * param[vm].vrow_row);
for (int col = 0; col < param[vm].packcolumns; col++) {
if (packCount - nextPack > 0) {
VList * pl = new VList;
pl->set_spacing (param[vm].vrow_row);
// first column is centered - if it is full it is like top alignment:
pl->set_alignment (HALIGN_LEFT, col == 0 ? VALIGN_CENTER : VALIGN_TOP);
pl->set_default_size (160, 35);
for (int row = 0; row < param[vm].rows; row++) {
if (nextPack < packCount) {
lev::Index *ind = (*group)[nextPack];
TextButton * button = new UntranslatedStaticTextButton(ind->getName(), this);
packButtons.push_back(button);
pl->add_back(button);
nextPack++;
} else
break;
}
packsHList->add_back(pl);
} else
break;
}
this->add(packsHList, Rect(param[vm].hmargin + 160 + param[vm].hgroup_pack +
param[vm].hscrollbutton + param[vm].hscroll_pack,
param[vm].vmargin,
param[vm].packcolumns * 160 + (param[vm].packcolumns - 1) *
param[vm].hpack_pack,
param[vm].rows * 35 +
(param[vm].rows - 1) * param[vm].vrow_row));
if (needLeftScroll) {
scrollLeft = new ImageButton("ic-left", "ic-left1", this);
this->add(scrollLeft, Rect(param[vm].hmargin + 160 + param[vm].hgroup_pack,
param[vm].vmargin + param[vm].rows / 2 * (25 + param[vm].vrow_row),
param[vm].hscrollbutton, 45));
}
if (needRightScroll) {
scrollRight = new ImageButton("ic-right", "ic-right1", this);
this->add(scrollRight, Rect(param[vm].hmargin + 160 + param[vm].hgroup_pack +
param[vm].hscrollbutton + 2 * param[vm].hscroll_pack +
param[vm].packcolumns * 160 + (param[vm].packcolumns - 1) *
param[vm].hpack_pack,
param[vm].vmargin + param[vm].rows / 2 * (25 + param[vm].vrow_row),
param[vm].hscrollbutton, 45));
}
}
void LevelPackMenu::manageLevelMenu() {
bool finished = false;
while (!finished) {
{
LevelMenu m;
if (!m.manage() || m.isMainQuit()) {
// ESC or Main button has been pressed in LevelMenu -
// the user wants to return
finished = true;
}
}
if (!finished) {
// the user left LevelMenu via LevelPack button
this->isLevelMenuSubmenu = true;
if (this->manage()) {
// not ESC - the user pressed Main button
finished = true;
} else {
// the user pressed ESC - return to LevelMenu
}
}
}
}
bool LevelPackMenu::manage() {
setupMenu();
updateHighlight();
return Menu::manage();
}
bool LevelPackMenu::on_event (const SDL_Event &e) {
switch (e.type) {
case SDL_KEYDOWN:
SDLKey keysym = e.key.keysym.sym;
switch (keysym) {
case SDLK_F1:
displayHelp(helptext, 200);
invalidate_all();
return true;
default:
break;
}
break;
}
return false;
}
void LevelPackMenu::on_action(Widget *w) {
if (w == but_main) {
Menu::quit();
} else if (w == but_level) {
LevelMenu m;
if (!m.manage() && isLevelMenuSubmenu || m.isMainQuit()) {
// ESC in LevelMenu in case we are a submenu of LevelMenu or
// Main button has been pressed in LevelMenu
Menu::quit();
}
setupMenu();
updateHighlight();
invalidate_all();
} else if (w == scrollUp) {
firstDisplayedGroup--;
reset_active_widget(); // we will delete it with setup
setupMenu();
updateHighlight();
invalidate_all();
} else if (w == scrollDown) {
firstDisplayedGroup++;
reset_active_widget(); // we will delete it with setup
setupMenu();
updateHighlight();
invalidate_all();
} else if (w->get_parent() == groupsVList){
lev::Index::setCurrentGroup(dynamic_cast<TextButton *>(w)->get_text());
if ((w->lastMouseButton() == SDL_BUTTON_RIGHT ||
w->lastModifierKeys() & KMOD_CTRL) &&
dynamic_cast<TextButton *>(w)->get_text() != INDEX_ALL_PACKS) {
// configure group
// INDEX_ALL_PACKS cannot be renamed, deleted, no packs can be created
LPGroupConfig m(dynamic_cast<TextButton *>(w)->get_text());
m.manage();
lastGroupName = ""; // the group may have moved, force a recalc
}
reset_active_widget(); // we will delete it with setup
setupMenu();
updateHighlight();
invalidate_all();
} else if (w->get_parent()->get_parent() == packsHList){
lev::Index::setCurrentIndex(dynamic_cast<TextButton *>(w)->get_text());
if (w->lastMouseButton() == SDL_BUTTON_RIGHT ||
w->lastModifierKeys() & KMOD_CTRL) {
// configure levelpack index
LevelPackConfig m(dynamic_cast<TextButton *>(w)->get_text());
m.manage();
} else {
LevelMenu m;
if (!m.manage() && isLevelMenuSubmenu || m.isMainQuit()) {
// ESC in LevelMenu in case we are a submenu of LevelMenu or
// Main button has been pressed in LevelMenu
Menu::quit();
return;
}
}
reset_active_widget(); // we will delete it with setup
setupMenu();
updateHighlight();
invalidate_all();
} else if (w == scrollLeft) {
std::string curGroupName = lev::Index::getCurrentGroup();
lev::Index::setGroupSelectedColumn(curGroupName,
lev::Index::getGroupSelectedColumn(curGroupName) + 1);
reset_active_widget(); // we will delete it with setup
setupMenu();
updateHighlight();
invalidate_all();
} else if (w == scrollRight) {
std::string curGroupName = lev::Index::getCurrentGroup();
lev::Index::setGroupSelectedColumn(curGroupName,
lev::Index::getGroupSelectedColumn(curGroupName) - 1);
reset_active_widget(); // we will delete it with setup
setupMenu();
updateHighlight();
invalidate_all();
}
}
void LevelPackMenu::updateHighlight() {
for (int i = 0; i < packButtons.size(); i++) {
TextButton * button = packButtons[i];
if (button->get_text() == lev::Index::getCurrentIndex()->getName())
button->setHighlight(true);
else
button->setHighlight(false);
}
for (int i = 0; i < groupButtons.size(); i++) {
TextButton * button = groupButtons[i];
if (button->get_text() == lev::Index::getCurrentGroup())
button->setHighlight(true);
else
button->setHighlight(false);
}
}
void LevelPackMenu::draw_background(ecl::GC &gc) {
video::SetCaption(("Enigma - Level Pack Menu"));
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
}
int LevelPackMenu::getGroupPosition(std::vector<std::string> * groups, std::string groupName) {
std::vector<std::string>::iterator it;
int i = 0;
for (it = groups->begin(); it != groups->end(); it++, i++) {
if ((*it) == groupName) {
return i;
}
}
return -1;
}
int LevelPackMenu::getIndexPosition(std::vector<lev::Index *> * group, std::string indexName) {
std::vector<lev::Index *>::iterator it;
int i = 0;
for (it = group->begin(); it != group->end(); it++, i++) {
if ((*it)->getName() == indexName) {
return i;
}
}
return -1;
}
int LevelPackMenu::checkColumn(int rows, int columns, int size,
int position, int oldColumn) {
int naturalColumn = position / rows;
int numColumns = (size - 1) / rows + 1;
if (oldColumn == INDEX_GROUP_COLUMN_UNKNOWN)
return (naturalColumn > columns) ? columns - 1 : naturalColumn;
else
return ecl::Clamp<int>(oldColumn, naturalColumn -
((numColumns > columns) ? (numColumns - columns) : 0),
naturalColumn);
}
}} // namespace enigma::gui