Added Enigma game
This commit is contained in:
114
project/jni/application/enigma/src/gui/ErrorMenu.cpp
Normal file
114
project/jni/application/enigma/src/gui/ErrorMenu.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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/ErrorMenu.hh"
|
||||
#include "enigma.hh"
|
||||
#include "video.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/* -------------------- HelpMenu -------------------- */
|
||||
|
||||
ErrorMenu::ErrorMenu(std::string message, std::string quitTitle) :
|
||||
text (message), rejectQuit (false), laterQuit (false),
|
||||
quit (new gui::StaticTextButton(quitTitle, this)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
add(quit, Rect(vminfo->width-170, vminfo->height-60, 150, 40));
|
||||
}
|
||||
|
||||
ErrorMenu::ErrorMenu(std::string message, std::string quitTitle, std::string rejectTitle) :
|
||||
text (message), rejectQuit (false), laterQuit (false),
|
||||
quit (new gui::StaticTextButton(quitTitle, this)),
|
||||
reject (new gui::StaticTextButton(rejectTitle, this)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
add(quit, Rect(vminfo->width-170, vminfo->height-60, 150, 40));
|
||||
add(reject, Rect(vminfo->width-340, vminfo->height-60, 150, 40));
|
||||
}
|
||||
|
||||
ErrorMenu::ErrorMenu(std::string message, std::string quitTitle, std::string rejectTitle,
|
||||
std::string laterTitle) :
|
||||
text (message), rejectQuit (false), laterQuit (false),
|
||||
quit (new gui::StaticTextButton(quitTitle, this)),
|
||||
reject (new gui::StaticTextButton(rejectTitle, this)),
|
||||
later (new gui::StaticTextButton(laterTitle, this)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
add(quit, Rect(vminfo->width-170, vminfo->height-60, 150, 40));
|
||||
add(later, Rect(vminfo->width-340, vminfo->height-60, 150, 40));
|
||||
add(reject, Rect(vminfo->width-510, vminfo->height-60, 150, 40));
|
||||
}
|
||||
|
||||
bool ErrorMenu::isRejectQuit() {
|
||||
return rejectQuit;
|
||||
}
|
||||
|
||||
bool ErrorMenu::isLaterQuit() {
|
||||
return laterQuit;
|
||||
}
|
||||
|
||||
bool ErrorMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_RIGHT) {
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ErrorMenu::on_action (gui::Widget *w) {
|
||||
if (w == quit) {
|
||||
Menu::quit();
|
||||
} else if (w == reject) {
|
||||
rejectQuit = true;
|
||||
Menu::quit();
|
||||
} else if (w == later) {
|
||||
laterQuit = true;
|
||||
Menu::quit();
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorMenu::draw_background (ecl::GC &gc) {
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
Font *f = enigma::GetFont("menufont");
|
||||
|
||||
vector<string> lines;
|
||||
|
||||
ecl::split_copy (text, '\n', back_inserter(lines));
|
||||
int x = 60;
|
||||
int y = 60;
|
||||
int yskip = 25;
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
int width = vminfo->width - 120;
|
||||
for (unsigned i=0; i<lines.size(); ) {
|
||||
std::string::size_type breakPos = breakString(f, lines[i],
|
||||
" ", width);
|
||||
f->render(gc, x, y, lines[i].substr(0,breakPos).c_str());
|
||||
y += yskip;
|
||||
if (breakPos != lines[i].size()) {
|
||||
// process rest of line
|
||||
lines[i] = lines[i].substr(breakPos);
|
||||
} else {
|
||||
// process next line
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
50
project/jni/application/enigma/src/gui/ErrorMenu.hh
Normal file
50
project/jni/application/enigma/src/gui/ErrorMenu.hh
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GUI_ERRORMENU_HH_INCLUDED
|
||||
#define GUI_ERRORMENU_HH_INCLUDED
|
||||
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "ecl.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class ErrorMenu : public Menu {
|
||||
public:
|
||||
ErrorMenu (std::string message, std::string quitTitle);
|
||||
ErrorMenu (std::string message, std::string quitTitle, std::string rejectTitle);
|
||||
ErrorMenu (std::string message, std::string quitTitle, std::string rejectTitle,
|
||||
std::string laterTitle);
|
||||
bool isRejectQuit();
|
||||
bool isLaterQuit();
|
||||
private:
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action (gui::Widget *w);
|
||||
void draw_background (ecl::GC &gc);
|
||||
|
||||
std::string text;
|
||||
gui::Widget *quit;
|
||||
gui::Widget *reject;
|
||||
gui::Widget *later;
|
||||
bool rejectQuit;
|
||||
bool laterQuit;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif // GUI_ERRORMENU_HH_INCLUDED
|
||||
|
||||
177
project/jni/application/enigma/src/gui/GameMenu.cpp
Normal file
177
project/jni/application/enigma/src/gui/GameMenu.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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/GameMenu.hh"
|
||||
#include "gui/OptionsMenu.hh"
|
||||
#include "gui/LevelInspector.hh"
|
||||
#include "client.hh"
|
||||
#include "display.hh"
|
||||
#include "ecl.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "server.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- GameMenu -------------------- */
|
||||
|
||||
GameMenu::GameMenu (int zoomxpos_, int zoomypos_)
|
||||
: zoomed(0),
|
||||
zoomxpos(zoomxpos_),
|
||||
zoomypos(zoomypos_)
|
||||
{
|
||||
resume = new gui::StaticTextButton(N_("Resume Level"), this);
|
||||
restart = new gui::StaticTextButton(N_("Restart Level"), this);
|
||||
options = new gui::StaticTextButton(N_("Options"), this);
|
||||
info = new gui::StaticTextButton(N_("Level Info"), this);
|
||||
abort = new gui::StaticTextButton(N_("Abort Level"), this);
|
||||
|
||||
add(resume, Rect(0,0,180,40));
|
||||
add(restart, Rect(0,45,180,40));
|
||||
add(options, Rect(0,90,180,40));
|
||||
add(info, Rect(0,135,180,40));
|
||||
add(abort, Rect(0,180,180,40));
|
||||
center();
|
||||
}
|
||||
|
||||
GameMenu::~GameMenu() {
|
||||
delete(zoomed);
|
||||
}
|
||||
|
||||
void GameMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
if (!zoomed) {
|
||||
Rect game_area = display::GetGameArea();
|
||||
int part_width = game_area.w/3;
|
||||
int part_height = (part_width*vminfo->height)/vminfo->width;
|
||||
|
||||
if (part_height > game_area.h) {
|
||||
part_height = game_area.h/3;
|
||||
part_width = (part_height*vminfo->width)/vminfo->height;
|
||||
assert(part_width <= game_area.w);
|
||||
}
|
||||
|
||||
// randomly choose ball offset
|
||||
int x, y;
|
||||
for (int trials = 5; trials; --trials) {
|
||||
x = IntegerRand(0, 5);
|
||||
y = IntegerRand(0, 3);
|
||||
|
||||
// try to avoid menu-ball overlap:
|
||||
if (x<2 || x>3 || y<1 || y>2 || (trials == 1)) {
|
||||
int ax = zoomxpos-game_area.x;
|
||||
int ay = zoomypos-game_area.y;
|
||||
|
||||
// upper left corner of part
|
||||
x = ax/32-1-x;
|
||||
y = ay/32-1-y;
|
||||
|
||||
// ensure part is inside game_area
|
||||
x = max(0, min(x, (game_area.w-part_width)/32-1));
|
||||
y = max(0, min(y, (game_area.h-part_height)/32-1));
|
||||
|
||||
// adjust to game fields
|
||||
x = x*32+24;
|
||||
y = y*32+16;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Be sure to redraw everything, or actors may appear on top
|
||||
// of the stones (actors are drawn in one pass and only
|
||||
// clipped to the screen boundary).
|
||||
display::RedrawAll(video::GetScreen());
|
||||
|
||||
// get the selected part from screen
|
||||
// SDL_Surface *back = video::GetScreen()->get_surface();
|
||||
Rect src_area(game_area.x+x, game_area.y+y, part_width, part_height);
|
||||
Surface *src = Grab(video::GetScreen()->get_surface(), src_area);
|
||||
|
||||
// zoom multiple times for softer image
|
||||
// const double stepsize = 0.3;
|
||||
// for (double zoom = 0.4; zoom < 0.9; zoom += stepsize) {
|
||||
// int sx = round_down<int>(zoom * vminfo->width);
|
||||
// int sy = round_down<int>(zoom * vminfo->height);
|
||||
// Surface *tmp = src->zoom(sx, sy);
|
||||
|
||||
// delete src;
|
||||
// src = tmp;
|
||||
// }
|
||||
zoomed = src->zoom(vminfo->width, vminfo->height);
|
||||
delete src;
|
||||
}
|
||||
|
||||
ecl::blit(gc, 0,0, zoomed);
|
||||
}
|
||||
|
||||
bool GameMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN
|
||||
&& e.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GameMenu::on_action(gui::Widget *w) {
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
if (w == resume) {
|
||||
Menu::quit();
|
||||
}
|
||||
else if (w == abort) {
|
||||
client::Msg_Command("abort");
|
||||
Menu::quit();
|
||||
}
|
||||
else if (w == restart) {
|
||||
if (w->lastModifierKeys() & KMOD_CTRL && w->lastModifierKeys() & KMOD_SHIFT) {
|
||||
// force a reload from file
|
||||
lev::Proxy * curProxy = lev::Proxy::loadedLevel();
|
||||
if (curProxy != NULL)
|
||||
curProxy->release();
|
||||
}
|
||||
client::Stop ();
|
||||
server::Msg_LoadLevel(ind->getCurrent(), false);
|
||||
Menu::quit();
|
||||
|
||||
}
|
||||
else if (w == options) {
|
||||
enigma::gui::ShowOptionsMenu (0);
|
||||
invalidate_all();
|
||||
// Menu::quit();
|
||||
}
|
||||
else if (w == info) {
|
||||
LevelInspector m(ind->getCurrent());
|
||||
m.manage();
|
||||
invalidate_all();
|
||||
// Menu::quit();
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
40
project/jni/application/enigma/src/gui/GameMenu.hh
Normal file
40
project/jni/application/enigma/src/gui/GameMenu.hh
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_GAMEMENU_HH_INCLUDED
|
||||
#define GUI_GAMEMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- GameMenu -------------------- */
|
||||
class GameMenu : public Menu {
|
||||
public:
|
||||
GameMenu(int zoomxpos_, int zoomypos_);
|
||||
virtual ~GameMenu();
|
||||
private:
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
|
||||
gui::Widget *resume, *restart, *options, *info, *abort;
|
||||
ecl::Surface *zoomed;
|
||||
int zoomxpos, zoomypos; // position to be zoomed
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
86
project/jni/application/enigma/src/gui/HelpMenu.cpp
Normal file
86
project/jni/application/enigma/src/gui/HelpMenu.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2003,2004 Daniel Heck, Ralf Westram
|
||||
*
|
||||
* 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/HelpMenu.hh"
|
||||
#include "enigma.hh"
|
||||
#include "video.hh"
|
||||
#include "nls.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/* -------------------- HelpMenu -------------------- */
|
||||
|
||||
HelpMenu::HelpMenu (const char **helptext_, int xoffset_) :
|
||||
helptext (helptext_),
|
||||
ok (new gui::StaticTextButton(N_("Ok"), this)),
|
||||
cfg (xoffset_)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
add(ok, Rect(vminfo.width-170,vminfo.height-60,150,40));
|
||||
}
|
||||
|
||||
bool HelpMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HelpMenu::on_action (gui::Widget *w)
|
||||
{
|
||||
if (w == ok)
|
||||
Menu::quit();
|
||||
}
|
||||
|
||||
void HelpMenu::draw_background (ecl::GC &gc)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
Font *f = enigma::GetFont(cfg.fontname.c_str());
|
||||
|
||||
int y = cfg.y0 + (vminfo.height - 480)/2;
|
||||
int x = (vminfo.width-640)/2;
|
||||
for (int i = 0; helptext[i]; i += 2)
|
||||
{
|
||||
f->render (gc, cfg.x0 + x, y, _(helptext[i])); // translate
|
||||
f->render (gc, cfg.x1 + x, y, _(helptext[i+1])); // translate
|
||||
y += cfg.yskip;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void displayHelp(const char **helptext, int xoffset)
|
||||
{
|
||||
FX_Fade (video::FADEOUT);
|
||||
HelpMenu menu(helptext, xoffset);
|
||||
menu.draw_all();
|
||||
FX_Fade (video::FADEIN);
|
||||
menu.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
60
project/jni/application/enigma/src/gui/HelpMenu.hh
Normal file
60
project/jni/application/enigma/src/gui/HelpMenu.hh
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003 Daniel Heck, Ralf Westram
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_HELP_HH
|
||||
#define ENIGMA_HELP_HH
|
||||
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "ecl.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
struct HelpMenuConfig {
|
||||
int x0, x1; // x coordinates of first and second column
|
||||
int y0; // y coordinate
|
||||
int yskip;
|
||||
std::string fontname;
|
||||
|
||||
HelpMenuConfig (int xoffset) {
|
||||
x0 = 40;
|
||||
x1 = x0 + xoffset;
|
||||
y0 = 40;
|
||||
yskip = 30;
|
||||
fontname = "menufont";
|
||||
}
|
||||
};
|
||||
|
||||
class HelpMenu : public Menu {
|
||||
public:
|
||||
HelpMenu (const char **helptext_, int xoffset);
|
||||
private:
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action (gui::Widget *w);
|
||||
void draw_background (ecl::GC &gc);
|
||||
|
||||
const char **helptext;
|
||||
gui::Widget *ok;
|
||||
HelpMenuConfig cfg;
|
||||
};
|
||||
|
||||
void displayHelp (const char **helptext, int xoffset);
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif // ENIGMA_HELP_HH
|
||||
|
||||
84
project/jni/application/enigma/src/gui/InfoMenu.cpp
Normal file
84
project/jni/application/enigma/src/gui/InfoMenu.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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/InfoMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "video.hh"
|
||||
#include "nls.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
InfoMenu::InfoMenu(const char **infotext, int pages) : info (infotext),
|
||||
curPage (0), numPages (pages) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
but_ok = new StaticTextButton(N_("Ok"), this);
|
||||
pgup = new ImageButton("ic-up", "ic-up1", this);
|
||||
pgdown = new ImageButton("ic-down", "ic-down1", this);
|
||||
|
||||
add(but_ok, Rect(vminfo.width-120, vminfo.height-60, 100, 40));
|
||||
add(pgup, Rect(vminfo.width-30, vminfo.height/2, 20, 50));
|
||||
add(pgdown, Rect(vminfo.width-30, vminfo.height/2 +70, 20, 50));
|
||||
}
|
||||
|
||||
void InfoMenu::draw_background(ecl::GC &gc) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
|
||||
Font *f = enigma::GetFont("menufont");
|
||||
int row = 0;
|
||||
for (int p=0; p<curPage; p++) {
|
||||
while (info[row])
|
||||
row++;
|
||||
// select first row of next page
|
||||
row++;
|
||||
}
|
||||
for (int i = 0; info[row]; row++, i++) {
|
||||
const char *t = _(info[row]);
|
||||
f->render (gc, 40 + (vminfo.width-640)/2,
|
||||
20 + (vminfo.height-480)/2 + i*f->get_height(), t);
|
||||
}
|
||||
}
|
||||
|
||||
void InfoMenu::on_action (gui::Widget *w) {
|
||||
if (w == but_ok) {
|
||||
Menu::quit();
|
||||
} else if (w == pgup) {
|
||||
if (curPage > 0) {
|
||||
curPage--;
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == pgdown) {
|
||||
if (curPage < numPages - 1) {
|
||||
curPage++;
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayInfo(const char **infotext, int pages) {
|
||||
FX_Fade (video::FADEOUT);
|
||||
InfoMenu menu(infotext, pages);
|
||||
menu.draw_all();
|
||||
FX_Fade (video::FADEIN);
|
||||
menu.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
42
project/jni/application/enigma/src/gui/InfoMenu.hh
Normal file
42
project/jni/application/enigma/src/gui/InfoMenu.hh
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_INFOMENU_HH_INCLUDED
|
||||
#define GUI_INFOMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class InfoMenu : public gui::Menu {
|
||||
public:
|
||||
InfoMenu(const char **infotext, int pages);
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
private:
|
||||
const char **info;
|
||||
int curPage;
|
||||
int numPages;
|
||||
Widget *but_ok;
|
||||
Widget *pgup;
|
||||
Widget *pgdown;
|
||||
};
|
||||
|
||||
void displayInfo(const char **helptext, int pages);
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
231
project/jni/application/enigma/src/gui/LPGroupConfig.cpp
Normal file
231
project/jni/application/enigma/src/gui/LPGroupConfig.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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/LPGroupConfig.hh"
|
||||
#include "gui/LevelPackConfig.hh"
|
||||
#include "ecl.hh"
|
||||
#include "errors.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
LPGroupConfig::LPGroupConfig(std::string groupName) : oldGroupName (groupName) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
groups = lev::Index::getGroupNames();
|
||||
|
||||
position = -1;
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (groups[i] == groupName) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
oldPosition = position;
|
||||
if (position < 0) {
|
||||
groups.push_back(groupName);
|
||||
position = groups.size() - 1;
|
||||
}
|
||||
|
||||
VList * titleVList = new VList;
|
||||
titleVList->set_spacing(12);
|
||||
titleVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
titleVList->set_default_size(160, 35);
|
||||
Label * groupLabel = new Label(N_("Group:"), HALIGN_RIGHT);
|
||||
titleVList->add_back(groupLabel);
|
||||
|
||||
VList * groupsVList = new VList;
|
||||
groupsVList->set_spacing(12);
|
||||
groupsVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
groupsVList->set_default_size(160, 35);
|
||||
|
||||
Label * positionLabel = new Label(N_("Position:"), HALIGN_LEFT);
|
||||
pre2Group = new UntranslatedLabel("");
|
||||
pre1Group = new UntranslatedLabel("");
|
||||
tf_groupName = new TextField(groupName);
|
||||
post1Group = new UntranslatedLabel("");
|
||||
post2Group = new UntranslatedLabel("");
|
||||
Label * dummyLabel = new Label("");
|
||||
|
||||
groupsVList->add_back(positionLabel);
|
||||
groupsVList->add_back(pre2Group);
|
||||
groupsVList->add_back(pre1Group);
|
||||
groupsVList->add_back(tf_groupName);
|
||||
groupsVList->add_back(post1Group);
|
||||
groupsVList->add_back(post2Group);
|
||||
groupsVList->add_back(dummyLabel);
|
||||
|
||||
VList * scrollVList = new VList;
|
||||
scrollVList->set_spacing(12);
|
||||
scrollVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
scrollVList->set_default_size(40, 35);
|
||||
|
||||
scrollUp = new ImageButton("ic-up", "ic-up1", this);
|
||||
scrollDown = new ImageButton("ic-down", "ic-down1", this);
|
||||
scrollVList->add_back(scrollUp);
|
||||
scrollVList->add_back(scrollDown);
|
||||
|
||||
this->add(titleVList, Rect(vminfo.width/2 - 290, 0, 160, vminfo.height-100));
|
||||
this->add(groupsVList, Rect(vminfo.width/2 - 80, 0, 160, vminfo.height-100));
|
||||
this->add(scrollVList, Rect(vminfo.width/2 + 130, 0, 40, vminfo.height-100));
|
||||
|
||||
errorLabel = new Label("", HALIGN_CENTER);
|
||||
this->add(errorLabel, Rect(10, vminfo.height-100, vminfo.width-20, 35));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
but_newPack = new StaticTextButton(N_("New Pack"), this);
|
||||
but_delete = new StaticTextButton(N_("Delete Group"), this);
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_ok = new StaticTextButton(N_("Ok"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(but_newPack);
|
||||
commandHList->add_back(but_delete);
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_ok);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
updateGroupList();
|
||||
}
|
||||
|
||||
void LPGroupConfig::updateGroupList() {
|
||||
pre2Group->set_text((position > 1) ? groups[position - 2] : "");
|
||||
pre1Group->set_text((position > 0) ? groups[position - 1] : "");
|
||||
post1Group->set_text((position < groups.size() - 1) ? groups[position + 1] : "");
|
||||
post2Group->set_text((position < groups.size() - 2) ? groups[position + 2] : "");
|
||||
}
|
||||
|
||||
bool LPGroupConfig::doChanges() {
|
||||
// rename first for consistency
|
||||
std::string newName = tf_groupName->getText();
|
||||
std::string::size_type lastChar = newName.find_last_not_of(" ");
|
||||
if (lastChar == std::string::npos) {
|
||||
// the name is effectively an empty string
|
||||
errorLabel->set_text(N_("Error: empty group name not allowed - press \"Undo\" to exit without modifications"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// strip off trailing and leading spaces
|
||||
newName = newName.substr(0 , lastChar + 1);
|
||||
newName = newName.substr(newName.find_first_not_of(" "));
|
||||
|
||||
// check if new group name is unique
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (i != position && groups[i] == newName) {
|
||||
errorLabel->set_text(N_("Error: group name is a duplicate of an existing group"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (newName == INDEX_EVERY_GROUP) {
|
||||
errorLabel->set_text(N_("Error: \"Every group\" is a reserved group name"));
|
||||
return false;
|
||||
}
|
||||
if (newName.size() > 2 && newName[0] == '['
|
||||
&& newName[newName.size() -1] == ']') {
|
||||
errorLabel->set_text(N_("Error: group name must not be enclosed in square brackets"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (oldGroupName.empty()) {
|
||||
// menu called without an existing group
|
||||
lev::Index::insertGroup(newName, position);
|
||||
} else {
|
||||
// menu called with an existing group
|
||||
if (newName != oldGroupName)
|
||||
lev::Index::renameGroup(oldGroupName, newName);
|
||||
|
||||
if (oldPosition >= 0 && position != oldPosition) {
|
||||
// move the group to the new position
|
||||
lev::Index::moveGroup(newName, position);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LPGroupConfig::on_action(Widget *w) {
|
||||
if (w == but_ok) {
|
||||
if (doChanges())
|
||||
Menu::quit();
|
||||
else
|
||||
invalidate_all();
|
||||
} else if (w == but_ignore) {
|
||||
Menu::quit();
|
||||
} else if (w == scrollUp) {
|
||||
if (position > 0) {
|
||||
std::string tmp = groups[position];
|
||||
groups[position] = groups[position - 1];
|
||||
groups[position - 1] = tmp;
|
||||
position--;
|
||||
updateGroupList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == scrollDown) {
|
||||
if (position < groups.size() - 1) {
|
||||
std::string tmp = groups[position];
|
||||
groups[position] = groups[position + 1];
|
||||
groups[position + 1] = tmp;
|
||||
position++;
|
||||
updateGroupList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == but_delete) {
|
||||
std::vector<lev::Index *> * indices = lev::Index::getGroup(oldGroupName);
|
||||
if (indices != NULL) {
|
||||
// reassign remaining indices from back to front to keep the
|
||||
// group vector valid
|
||||
for (int i = indices->size() - 1; i >= 0; i--) {
|
||||
if ((*indices)[i]->getGroupName() != INDEX_EVERY_GROUP) {
|
||||
LevelPackConfig m((*indices)[i]->getName(), oldGroupName, true);
|
||||
if (!m.manage() || m.isUndoQuit()) {
|
||||
errorLabel->set_text(N_("Error: group not empty"));
|
||||
invalidate_all();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
lev::Index::deleteGroup(oldGroupName);
|
||||
}
|
||||
Menu::quit();
|
||||
} else if (w == but_newPack) {
|
||||
if (doChanges()) {
|
||||
LevelPackConfig m("");
|
||||
m.manage();
|
||||
Menu::quit();
|
||||
} else {
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LPGroupConfig::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Level Pack Group Configuration"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
|
||||
}} // namespace enigma::gui
|
||||
56
project/jni/application/enigma/src/gui/LPGroupConfig.hh
Normal file
56
project/jni/application/enigma/src/gui/LPGroupConfig.hh
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LPGROUPCONFIG_HH_INCLUDED
|
||||
#define GUI_LPGROUPCONFIG_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class LPGroupConfig : public gui::Menu {
|
||||
public:
|
||||
LPGroupConfig (std::string groupName);
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
private:
|
||||
void updateGroupList();
|
||||
bool doChanges();
|
||||
|
||||
TextField *tf_groupName;
|
||||
Label *pre2Group;
|
||||
Label *pre1Group;
|
||||
Label *post1Group;
|
||||
Label *post2Group;
|
||||
Widget *scrollUp;
|
||||
Widget *scrollDown;
|
||||
Label *errorLabel;
|
||||
Widget *but_newPack;
|
||||
Widget *but_delete;
|
||||
Widget *but_ignore;
|
||||
Widget *but_ok;
|
||||
std::vector<std::string> groups;
|
||||
int position; // new position of group that the user selected
|
||||
int oldPosition; // position of group when entering menu, -1 for new group
|
||||
std::string oldGroupName;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
|
||||
712
project/jni/application/enigma/src/gui/LevelInspector.cpp
Normal file
712
project/jni/application/enigma/src/gui/LevelInspector.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 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 "errors.hh"
|
||||
#include "gui/LevelInspector.hh"
|
||||
#include "main.hh"
|
||||
#include "enigma.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
#include "ecl_util.hh"
|
||||
#include "gui/MonospacedLabel.hh"
|
||||
#include "gui/LevelPreviewCache.hh"
|
||||
#include "gui/ScreenshotViewer.hh"
|
||||
#include "lev/RatingManager.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
#include "StateManager.hh"
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace enigma;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class IntelligenceButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getIntelligence(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setIntelligence(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
IntelligenceButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class DexterityButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getDexterity(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setDexterity(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
DexterityButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class PatienceButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getPatience(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setPatience(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
PatienceButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class KnowledgeButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getKnowledge(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setKnowledge(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
KnowledgeButton(lev::Proxy *aLevel) : ValueButton(0, 6),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class SpeedButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getSpeed(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setSpeed(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
SpeedButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class RatingButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theScoreMgr->getRating(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theScoreMgr->setRating(theLevel, value);
|
||||
if (get_parent() != NULL) {
|
||||
get_parent()->invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return (value == -1) ? "-" : ecl::strf("%d", value);
|
||||
}
|
||||
public:
|
||||
RatingButton(lev::Proxy *aLevel) : ValueButton(-1, 10),
|
||||
theLevel (aLevel) {
|
||||
theScoreMgr = lev::ScoreManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::ScoreManager *theScoreMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
LevelInspector::LevelInspector(lev::Proxy *aLevel, bool showDeveloperInfo):
|
||||
levelProxy(aLevel), isDeveloperMode(showDeveloperInfo), annotation (new TextField()),
|
||||
back (new StaticTextButton(N_("Ok"), this)),
|
||||
screenshot (new StaticTextButton(N_("Screenshot"), this))
|
||||
{
|
||||
bool didGenerate; // dummy
|
||||
previewImage = LevelPreviewCache::instance()->getPreview(aLevel, true, didGenerate);
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
vspacing = vminfo->height < 500 ? 2 :(vminfo->height < 650 ? 3 : 4);
|
||||
vspacing2 = vminfo->height < 500 ? 16 :(vminfo->height < 650 ? 14 : 16);
|
||||
vmargin = vminfo->height < 500 ? 10 :(vminfo->height < 650 ? 20 : 30);
|
||||
hmargin = vminfo->width < 660 ? 10 : (vminfo->width < 900 ? 20 : 30);
|
||||
bool highres = vminfo->height > 650 ? true : false;
|
||||
bool lowres = vminfo->height < 600 ? true : false;
|
||||
|
||||
add(back, Rect(vminfo->width-130-2*hmargin,vminfo->height-50,130,35));
|
||||
add(screenshot, Rect(vminfo->width-260-3*hmargin,vminfo->height-50,130,35));
|
||||
|
||||
try {
|
||||
aLevel->loadMetadata(true);
|
||||
}
|
||||
catch (XLevelLoading &err) {
|
||||
std::vector<string> lines;
|
||||
std::string errmsg = _("Server Error: could not load level '")
|
||||
+ aLevel->getNormLevelPath() + "'\n"
|
||||
+ err.what();
|
||||
ecl::split_copy (errmsg, '\n', back_inserter(lines));
|
||||
int x = 60;
|
||||
int y = 60;
|
||||
int yskip = 25;
|
||||
for (unsigned i=0; i<lines.size(); ++i) {
|
||||
add(new Label(lines[i], HALIGN_LEFT), Rect(x, y, vminfo->width-80,yskip));
|
||||
y += yskip;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::string tmp, tmp2;
|
||||
lev::RatingManager *theRatingMgr = lev::RatingManager::instance();
|
||||
lev::ScoreManager *theScoreMgr = lev::ScoreManager::instance();
|
||||
withEasy = aLevel->hasEasymode();
|
||||
ratingInherited = theScoreMgr->isRatingInherited(aLevel);
|
||||
ecl::Font *menufont = enigma::GetFont("menufont");
|
||||
levelPathString =
|
||||
(levelProxy->getNormPathType() == lev::Proxy::pt_resource) ?
|
||||
levelProxy->getAbsLevelPath() : levelProxy->getNormLevelPath();
|
||||
// substitute all backslashes by slashes
|
||||
for (std::string::size_type slpos = levelPathString.find('\\');
|
||||
slpos != std::string::npos; slpos = levelPathString.find('\\'))
|
||||
levelPathString.replace(slpos, 1, 1, '/');
|
||||
BuildVList authorT(this, Rect(hmargin,vmargin,110,25), vspacing);
|
||||
authorT.add(new Label(N_("Level: "), HALIGN_RIGHT));
|
||||
authorT.add(new Label((""), HALIGN_RIGHT)); // subtitle
|
||||
authorT.add(new Label(N_("Author: "), HALIGN_RIGHT));
|
||||
authorT.add(new Label(N_("Contact: "), HALIGN_RIGHT));
|
||||
authorT.add(new Label(N_("Homepage: "), HALIGN_RIGHT));
|
||||
|
||||
BuildVList author(this, Rect(hmargin+110+10,vmargin,
|
||||
vminfo->width-(hmargin+110+10)-10-(vminfo->thumbw+10)-hmargin,25), vspacing);
|
||||
tmp = levelProxy->getTitle();
|
||||
tmp2 = levelProxy->getLocalizedString("title");
|
||||
if (tmp != tmp2)
|
||||
tmp = tmp + " -- " + tmp2;
|
||||
author.add(new Label( tmp, HALIGN_LEFT));
|
||||
tmp = levelProxy->getLocalizedString("subtitle");
|
||||
if (tmp == "subtitle")
|
||||
tmp = "";
|
||||
author.add(new Label(tmp, HALIGN_LEFT)); // subtitle
|
||||
author.add(new Label(levelProxy->getAuthor(), HALIGN_LEFT));
|
||||
|
||||
BuildVList address(this, Rect(hmargin+110+10,vmargin+3*(25+vspacing),
|
||||
vminfo->width-(hmargin+110+10)-hmargin,25), vspacing);
|
||||
address.add(new Label(levelProxy->getContact(), HALIGN_LEFT));
|
||||
address.add(new Label(levelProxy->getHomepage(), HALIGN_LEFT));
|
||||
|
||||
BuildVList ratingPubT(this, Rect(hmargin+65,vmargin+5*25+4*vspacing+vspacing2, 130,25), 2);
|
||||
ratingPubT.add(new Label(N_("Public Ratings"), HALIGN_CENTER));
|
||||
BuildVList ratingPubST(this, Rect(hmargin,vmargin+6*25+5*vspacing+vspacing2, 130,25), 2);
|
||||
ratingPubST.add(new Label(N_("Intelligence: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Dexterity: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Patience: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Knowledge: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Speed: "), HALIGN_RIGHT));
|
||||
if (!lowres) ratingPubST.add(new Label(N_("Difficulty: "), HALIGN_RIGHT));
|
||||
|
||||
|
||||
BuildVList ratingPub(this, Rect(hmargin+130+15,vmargin+6*25+5*vspacing+vspacing2, 30,25), 2);
|
||||
if (WizardMode) {
|
||||
ratingPub.add(new IntelligenceButton(aLevel));
|
||||
ratingPub.add(new DexterityButton(aLevel));
|
||||
ratingPub.add(new PatienceButton(aLevel));
|
||||
ratingPub.add(new KnowledgeButton(aLevel));
|
||||
ratingPub.add(new SpeedButton(aLevel));
|
||||
if (!lowres) ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getDifficulty(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
} else {
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getIntelligence(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getDexterity(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getPatience(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getKnowledge(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getSpeed(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
if (!lowres) ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getDifficulty(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
}
|
||||
|
||||
BuildVList scoresT(this, Rect(vminfo->width/2-100-20,vmargin+5*25+4*vspacing+vspacing2,100,25), 2);
|
||||
scoresT.add(new Label(N_("Scores"), HALIGN_RIGHT));
|
||||
|
||||
BuildVList scoresST(this, Rect(vminfo->width/2-100-20,vmargin+6*25+5*vspacing+vspacing2,100,25), 2);
|
||||
scoresST.add(new Label(N_("You: "), HALIGN_RIGHT));
|
||||
scoresST.add(new Label(N_("World: "), HALIGN_RIGHT));
|
||||
// TRANSLATORS: PAR = professional average rate - an expression used by golfers
|
||||
scoresST.add(new Label(N_("PAR: "), HALIGN_RIGHT));
|
||||
scoresST.add(new Label(N_("Author: "), HALIGN_RIGHT));
|
||||
scoresST.add(new Label(N_("Solved %: "), HALIGN_RIGHT));
|
||||
if (!lowres) scoresST.add(new Label(N_("Solved #: "), HALIGN_RIGHT));
|
||||
|
||||
BuildVList scores(this, Rect(vminfo->width/2-15+(withEasy?0:20),
|
||||
vmargin+6*25+5*vspacing+vspacing2,(withEasy?117:54),25), 2);
|
||||
scores.add(new MonospacedLabel(scoreToString(theScoreMgr->getBestUserScore(aLevel, DIFFICULTY_EASY),
|
||||
theScoreMgr->getBestUserScore(aLevel, DIFFICULTY_HARD),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(scoreToString(theRatingMgr->getBestScoreEasy(aLevel),
|
||||
theRatingMgr->getBestScoreDifficult(aLevel),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(scoreToString(theRatingMgr->getParScoreEasy(aLevel),
|
||||
theRatingMgr->getParScoreDifficult(aLevel),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(scoreToString(aLevel->getEasyScore(),
|
||||
aLevel->getDifficultScore(),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(withEasy ? (theRatingMgr->getPcSolvedEasy(aLevel) +
|
||||
" /" + theRatingMgr->getPcSolvedDifficult(aLevel) + " ").c_str() :
|
||||
(theRatingMgr->getPcSolvedDifficult(aLevel) + " ").c_str(),
|
||||
'8', " 0123456789", HALIGN_CENTER));
|
||||
if (!lowres) scores.add(new MonospacedLabel(withEasy ? (ecl::strf("%5d", theRatingMgr->getNumSolvedEasy(aLevel)) +
|
||||
" /" + ecl::strf("%5d", theRatingMgr->getNumSolvedDifficult(aLevel)) + " ").c_str() :
|
||||
(ecl::strf("%5d", theRatingMgr->getNumSolvedDifficult(aLevel)) + " ").c_str(),
|
||||
'8', " 0123456789", HALIGN_CENTER));
|
||||
|
||||
BuildVList versionT(this, Rect(vminfo->width-100/2-90-2*hmargin,vmargin+5*25+4*vspacing+vspacing2,100,25), 2);
|
||||
versionT.add(new Label(N_("Version"), HALIGN_CENTER));
|
||||
BuildVList versionST(this, Rect(vminfo->width-110-90-2*hmargin,vmargin+6*25+5*vspacing+vspacing2,110,25), 2);
|
||||
if (!lowres || aLevel->getLevelStatus() == lev::STATUS_RELEASED)
|
||||
versionST.add(new Label(N_("Score: "), HALIGN_RIGHT));
|
||||
else
|
||||
versionST.add(new Label(N_("Status: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Release: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Revision: "), HALIGN_RIGHT));
|
||||
if (!lowres)
|
||||
versionST.add(new Label(N_("Status: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Control: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Target: "), HALIGN_RIGHT));
|
||||
|
||||
BuildVList version(this, Rect(vminfo->width-80-2*hmargin,vmargin+6*25+5*vspacing+vspacing2,80+2*hmargin,25), 2);
|
||||
if (!lowres || aLevel->getLevelStatus() == lev::STATUS_RELEASED)
|
||||
version.add(new MonospacedLabel(ecl::strf("%6d", aLevel->getScoreVersion()).c_str(),
|
||||
'8', " 0123456789", HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_STABLE)
|
||||
version.add(new Label(N_("stable"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_TEST)
|
||||
version.add(new Label(N_("test"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_EXPERIMENTAL)
|
||||
version.add(new Label(N_("experimental"), HALIGN_LEFT));
|
||||
else
|
||||
version.add(new Label(N_("unknown"), HALIGN_LEFT));
|
||||
|
||||
version.add(new MonospacedLabel(ecl::strf("%6d", aLevel->getReleaseVersion()).c_str(),
|
||||
'8', " 0123456789", HALIGN_LEFT));
|
||||
version.add(new MonospacedLabel(ecl::strf("%6d", aLevel->getRevisionNumber()).c_str(),
|
||||
'8', " 0123456789", HALIGN_LEFT));
|
||||
if (!lowres)
|
||||
if (aLevel->getLevelStatus() == lev::STATUS_RELEASED)
|
||||
version.add(new Label(N_("released"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_STABLE)
|
||||
version.add(new Label(N_("stable"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_TEST)
|
||||
version.add(new Label(N_("test"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_EXPERIMENTAL)
|
||||
version.add(new Label(N_("experimental"), HALIGN_LEFT));
|
||||
else
|
||||
version.add(new Label(N_("unknown"), HALIGN_LEFT));
|
||||
|
||||
switch (aLevel->getControl()) {
|
||||
case lev::force:
|
||||
version.add(new Label(N_("force"), HALIGN_LEFT));
|
||||
break;
|
||||
case lev::balance:
|
||||
version.add(new Label(N_("balance"), HALIGN_LEFT));
|
||||
break;
|
||||
case lev::key:
|
||||
version.add(new Label(N_("key"), HALIGN_LEFT));
|
||||
break;
|
||||
default:
|
||||
version.add(new Label(N_("unknown"), HALIGN_LEFT));
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
// fake gettext to register the following strings for I18N
|
||||
_("time")
|
||||
_("pushes")
|
||||
_("moves")
|
||||
#endif
|
||||
version.add(new Label(aLevel->getScoreTarget().c_str(), HALIGN_LEFT));
|
||||
|
||||
int bestScoreHolderLines = 0;
|
||||
int creditsLines = 0;
|
||||
int dedicationLines = 0;
|
||||
int levelPathLines = 0;
|
||||
int annotationLines = 0;
|
||||
int compatibilityLines = 0;
|
||||
int idLines = 0;
|
||||
int vnext = vmargin+ (lowres?11:12)*25+(lowres?9:10)*vspacing+2*vspacing2;
|
||||
int textwidth = vminfo->width-3*hmargin-110-10;
|
||||
dispatchBottomLines(bestScoreHolderLines, creditsLines, dedicationLines,
|
||||
levelPathLines, annotationLines, compatibilityLines, idLines,
|
||||
(vminfo->height-vnext-vmargin-25-vspacing2)/27, textwidth);
|
||||
if (bestScoreHolderLines == 1) {
|
||||
add(new Label(N_("World Record Holders: "), HALIGN_RIGHT),Rect(hmargin,vnext,200,25));
|
||||
std::string holders;
|
||||
if (withEasy) {
|
||||
holders = theRatingMgr->getBestScoreEasyHolder(aLevel);
|
||||
if (holders.empty())
|
||||
holders = " - ";
|
||||
holders += " / ";
|
||||
}
|
||||
if (theRatingMgr->getBestScoreDifficultHolder(aLevel).empty())
|
||||
holders += " -";
|
||||
else
|
||||
holders += theRatingMgr->getBestScoreDifficultHolder(aLevel);
|
||||
Label *wrLabel = new Label(holders, HALIGN_LEFT);
|
||||
add(wrLabel, Rect(hmargin+200+10,vnext,textwidth-90,25));
|
||||
if (!wrLabel->text_fits()) {
|
||||
int cutEasy = 0;
|
||||
int cutDiff = 0;
|
||||
std::string diffHolders = theRatingMgr->getBestScoreDifficultHolder(aLevel);
|
||||
if (withEasy) {
|
||||
std::string easyHolders = theRatingMgr->getBestScoreEasyHolder(aLevel);
|
||||
bool hasEasyHolders = !easyHolders.empty();
|
||||
bool hasDiffHolders = !diffHolders.empty();
|
||||
int limit = 10;
|
||||
do {
|
||||
std::string cutHolders;
|
||||
wrLabel->set_text(easyHolders);
|
||||
if (!wrLabel->text_fits(0.48)) {
|
||||
cutHolders = theRatingMgr->getBestScoreEasyHolder(aLevel, ++cutEasy);
|
||||
if (cutHolders.empty())
|
||||
cutEasy--;
|
||||
else
|
||||
easyHolders = cutHolders;
|
||||
}
|
||||
wrLabel->set_text(diffHolders);
|
||||
if (!wrLabel->text_fits(0.48)) {
|
||||
cutHolders = theRatingMgr->getBestScoreDifficultHolder(aLevel, ++cutDiff);
|
||||
if (cutHolders.empty())
|
||||
cutDiff--;
|
||||
else
|
||||
diffHolders = cutHolders;
|
||||
}
|
||||
holders = (hasEasyHolders ? easyHolders : std::string(" - "))
|
||||
+ " / " + (hasDiffHolders ? diffHolders : std::string(" -"));
|
||||
wrLabel->set_text(holders);
|
||||
limit--;
|
||||
} while (!wrLabel->text_fits() && limit > 0);
|
||||
} else {
|
||||
std::string cutHolders;
|
||||
do {
|
||||
cutHolders = theRatingMgr->getBestScoreDifficultHolder(aLevel, ++cutDiff);
|
||||
wrLabel->set_text(cutHolders);
|
||||
} while (!wrLabel->text_fits());
|
||||
if (cutHolders.empty()) {
|
||||
// we did cut off to many holders, take last attempt even if it was too long
|
||||
wrLabel->set_text(theRatingMgr->getBestScoreDifficultHolder(aLevel, --cutDiff));
|
||||
}
|
||||
}
|
||||
}
|
||||
vnext += 25 + vspacing;
|
||||
}
|
||||
if (creditsLines >= 1) {
|
||||
add(new Label(N_("Credits: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string creditsString = levelProxy->getCredits(true);
|
||||
for (int i = 0; i< creditsLines; i++) {
|
||||
std::string::size_type breakPos = breakString(menufont, creditsString,
|
||||
" ", textwidth);
|
||||
add(new Label(creditsString.substr(0,breakPos), HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
creditsString = creditsString.substr(breakPos);
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
}
|
||||
if (dedicationLines >= 1) {
|
||||
add(new Label(N_("Dedication: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string dedicationString = levelProxy->getDedication(true);
|
||||
for (int i = 0; i< dedicationLines; i++) {
|
||||
std::string::size_type breakPos = breakString( menufont, dedicationString,
|
||||
" ", textwidth);
|
||||
add(new Label(dedicationString.substr(0,breakPos), HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
dedicationString = dedicationString.substr(breakPos);
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
}
|
||||
if (levelPathLines >= 1) {
|
||||
add(new Label(N_("Level Path: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string workString = levelPathString;
|
||||
for (int i = 0; i< levelPathLines - 1; i++) {
|
||||
std::string::size_type breakPos = breakString(menufont, workString,
|
||||
"/", textwidth);
|
||||
add(new Label(workString.substr(0,breakPos), HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
workString = workString.substr(breakPos);
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
// show as much as possible from last line
|
||||
if (menufont->get_width(workString.c_str()) > textwidth) {
|
||||
// show the filename at the end - skip leading parts if necessary
|
||||
add(new Label(workString, HALIGN_RIGHT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
} else {
|
||||
// display up to the last character
|
||||
add(new Label(workString, HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
}
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
if (idLines >= 1) {
|
||||
add(new Label(N_("Id: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
add(new Label(levelProxy->getId(), HALIGN_LEFT),Rect(hmargin+110+10, vnext, textwidth, 25));
|
||||
vnext += (25 + vspacing)*idLines;
|
||||
}
|
||||
if (compatibilityLines >= 1) {
|
||||
add(new Label(N_("Compatibility: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string compString = ecl::strf("Enigma v%.2f / ", levelProxy->getEnigmaCompatibility()) +
|
||||
GetGameTypeName(levelProxy->getEngineCompatibility());
|
||||
add(new Label(compString , HALIGN_LEFT),Rect(hmargin+110+10, vnext, textwidth, 25));
|
||||
vnext += (25 + vspacing)*compatibilityLines;
|
||||
}
|
||||
annotation->set_text(app.state->getAnnotation(levelProxy->getId())); // field needs to initialized for saves
|
||||
if (annotationLines >= 1) {
|
||||
add(new Label(N_("Annotation: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
add(annotation, Rect(hmargin+110+10, vnext, textwidth, 25));
|
||||
vnext += (25 + vspacing)*annotationLines;
|
||||
}
|
||||
vnext += vspacing2 - vspacing;
|
||||
add(new Label(N_("Rating: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
add(new RatingButton(aLevel),Rect(hmargin+110+10,vnext,40,25));
|
||||
add(new Label(N_("Average: "), HALIGN_RIGHT),Rect(hmargin+110+10+40+20,vnext,105,25));
|
||||
add(new Label(theRatingMgr->getAverageRating(aLevel), HALIGN_RIGHT),Rect(hmargin+110+10+40+18+105+6,vnext,31,25));
|
||||
}
|
||||
|
||||
LevelInspector::~LevelInspector () {
|
||||
}
|
||||
|
||||
bool LevelInspector::isEndDeveloperMode() {
|
||||
return isDeveloperMode;
|
||||
}
|
||||
|
||||
bool LevelInspector::on_event (const SDL_Event &e) {
|
||||
bool handled = false;
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
handled=true;
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_F2:
|
||||
if (!isDeveloperMode) {
|
||||
if (!annotation->getText().empty() ||
|
||||
!app.state->getAnnotation(levelProxy->getId()).empty()) {
|
||||
app.state->setAnnotation(levelProxy->getId(), annotation->getText());
|
||||
}
|
||||
LevelInspector m(levelProxy, true);
|
||||
m.manage();
|
||||
if (m.isEndDeveloperMode()) {
|
||||
// reinit user input fields
|
||||
annotation->set_text(app.state->getAnnotation(levelProxy->getId()));
|
||||
invalidate_all();
|
||||
} else {
|
||||
Menu::quit();
|
||||
}
|
||||
} else {
|
||||
if (!annotation->getText().empty() ||
|
||||
!app.state->getAnnotation(levelProxy->getId()).empty()) {
|
||||
app.state->setAnnotation(levelProxy->getId(), annotation->getText());
|
||||
}
|
||||
Menu::quit();
|
||||
}
|
||||
break;
|
||||
default: handled=false; break;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void LevelInspector::on_action(gui::Widget *w) {
|
||||
if (w == back) {
|
||||
// save annotation - but avoid to save unnecessary empty annotations
|
||||
if (!annotation->getText().empty() ||
|
||||
!app.state->getAnnotation(levelProxy->getId()).empty()) {
|
||||
app.state->setAnnotation(levelProxy->getId(), annotation->getText());
|
||||
}
|
||||
isDeveloperMode = false;
|
||||
Menu::quit();
|
||||
} else if (w == screenshot) {
|
||||
ScreenshotViewer m(levelProxy);
|
||||
m.manage();
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
void LevelInspector::draw_background(ecl::GC &gc) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
video::SetCaption((std::string("Enigma - Level ") +
|
||||
(isDeveloperMode ? "Developer " : "") + "Inspector").c_str());
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
blit(gc, vminfo->width-vminfo->thumbw-10-hmargin, vmargin, previewImage);
|
||||
Surface *img_hard = enigma::GetImage("completed");
|
||||
if (withEasy) {
|
||||
Surface *img_easy = enigma::GetImage("completed-easy");
|
||||
blit (gc, vminfo->width/2-4, vmargin+5*25+4*vspacing+vspacing2, img_easy);
|
||||
blit (gc, vminfo->width/2-4+63, vmargin+5*25+4*vspacing+vspacing2, img_hard);
|
||||
} else {
|
||||
blit (gc, vminfo->width/2-4+20, vmargin+5*25+4*vspacing+vspacing2, img_hard);
|
||||
}
|
||||
Surface *img_changed = enigma::GetImage("changed");
|
||||
ratingInherited = lev::ScoreManager::instance()->isRatingInherited(levelProxy);
|
||||
if (ratingInherited) {
|
||||
int numLines = vminfo->height < 500 ? 14 :(vminfo->height < 650 ? 18 : 19);
|
||||
blit (gc, hmargin+110+10+40, vmargin + numLines*25 +
|
||||
(numLines-3)*vspacing + 3*vspacing2, img_changed);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelInspector::tick(double dtime) {
|
||||
}
|
||||
|
||||
std::string LevelInspector::ratingToString(int value) {
|
||||
if (value == 0) {
|
||||
// no rating available
|
||||
return " ";
|
||||
} else {
|
||||
return ecl::strf("%3d", value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LevelInspector::scoreToString(int easy, int difficult,
|
||||
lev::Proxy *aLevel, bool constLengthForCenteredClipping) {
|
||||
if (withEasy) {
|
||||
if (!constLengthForCenteredClipping)
|
||||
return scoreToString(easy, aLevel) + " / " +
|
||||
scoreToString(difficult, aLevel);
|
||||
else
|
||||
if (aLevel->getScoreUnit() == lev::duration)
|
||||
//
|
||||
return (easy >= 0 ? "- " : ": ") +
|
||||
scoreToString(easy, aLevel) + " / " +
|
||||
scoreToString(difficult, aLevel) +
|
||||
(difficult >= 0 ? " -" : " :") ;
|
||||
else
|
||||
return (easy >= 0 ? "- " : " ") +
|
||||
scoreToString(easy, aLevel) + " / " +
|
||||
scoreToString(difficult, aLevel) +
|
||||
(difficult >= 0 ? " -" : " ") ;
|
||||
} else {
|
||||
return scoreToString(difficult, aLevel);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LevelInspector::scoreToString(int score, lev::Proxy *aLevel) {
|
||||
if (aLevel->getScoreUnit() == lev::duration)
|
||||
if (score >= 0 && score <= (99*60+59))
|
||||
return ecl::strf("%2d:%02d", score/60, score%60);
|
||||
else
|
||||
return " - ";
|
||||
else
|
||||
if (score >= 0 && score <= 9999)
|
||||
return ecl::strf("%4d", score);
|
||||
else
|
||||
return " -";
|
||||
}
|
||||
|
||||
void LevelInspector::dispatchBottomLines(int &bestScoreHolderLines,
|
||||
int &creditsLines, int &dedicationLines, int &levelPathLines,
|
||||
int &annotationLines, int &compatibilityLines, int &idLines, int numLines, int width) {
|
||||
enum botType {holder, credits, dedication, path, annotation, compatibility, id};
|
||||
const int sequenceSize = 13;
|
||||
botType sequence1[sequenceSize] = {credits, dedication, annotation, path,
|
||||
holder, annotation, path, compatibility, credits, dedication,
|
||||
annotation, credits, annotation};
|
||||
botType sequence2[sequenceSize] = {id, path, compatibility, holder, path,
|
||||
annotation, annotation, credits, dedication,
|
||||
credits, dedication, annotation, annotation};
|
||||
botType *sequence = isDeveloperMode ? sequence2 : sequence1;
|
||||
int j = 0;
|
||||
std::string creditsString = levelProxy->getCredits(true);
|
||||
std::string dedicationString = levelProxy->getDedication(true);
|
||||
std::string pathWorkString = levelPathString;
|
||||
ecl::Font *menufont = enigma::GetFont("menufont");
|
||||
for (int i = 0; i<numLines; i++) {
|
||||
bool assigned = false;
|
||||
do {
|
||||
switch (sequence[j++]) {
|
||||
case holder:
|
||||
bestScoreHolderLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
case credits:
|
||||
if (!(creditsString.empty())) {
|
||||
creditsLines++;
|
||||
creditsString = creditsString.substr(breakString(menufont,
|
||||
creditsString, " ", width));
|
||||
assigned = true;
|
||||
}
|
||||
break;
|
||||
case dedication:
|
||||
if (!(dedicationString.empty())) {
|
||||
dedicationLines++;
|
||||
dedicationString = dedicationString.substr(breakString(menufont,
|
||||
dedicationString, " ", width));
|
||||
assigned = true;
|
||||
}
|
||||
break;
|
||||
case path:
|
||||
if (!(pathWorkString.empty())) {
|
||||
levelPathLines++;
|
||||
pathWorkString = pathWorkString.substr(breakString(menufont,
|
||||
pathWorkString, "/", width));
|
||||
assigned = true;
|
||||
}
|
||||
break;
|
||||
case annotation:
|
||||
annotationLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
case compatibility:
|
||||
compatibilityLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
case id:
|
||||
idLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!assigned && j < sequenceSize);
|
||||
if (j == sequenceSize)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace enigma::lev
|
||||
68
project/jni/application/enigma/src/gui/LevelInspector.hh
Normal file
68
project/jni/application/enigma/src/gui/LevelInspector.hh
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LEVELINSPECTOR_HH_INCLUDED
|
||||
#define GUI_LEVELINSPECTOR_HH_INCLUDED
|
||||
|
||||
#include "ecl.hh"
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class LevelInspector : public gui::Menu {
|
||||
public:
|
||||
LevelInspector (lev::Proxy *aLevel, bool showDeveloperInfo = false);
|
||||
~LevelInspector ();
|
||||
bool isEndDeveloperMode();
|
||||
private:
|
||||
// ActionListener interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
|
||||
// Menu interface.
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
//
|
||||
std::string ratingToString(int value);
|
||||
std::string scoreToString(int easy, int difficult, lev::Proxy *aLevel,
|
||||
bool constLengthForCenteredClipping);
|
||||
std::string scoreToString(int score, lev::Proxy *aLevel);
|
||||
void dispatchBottomLines(int &bestScoreHolderLines,
|
||||
int &creditsLines, int &dedicationLines, int &levelPathLines,
|
||||
int &annotationLines, int &compatibilityLines, int &idLines, int numLines, int width);
|
||||
// Variables.
|
||||
gui::Widget *back;
|
||||
gui::Widget *screenshot;
|
||||
gui::TextField *annotation;
|
||||
ecl::Surface *previewImage;
|
||||
lev::Proxy *levelProxy;
|
||||
std::string levelPathString;
|
||||
int vspacing;
|
||||
int vspacing2;
|
||||
int vmargin;
|
||||
int hmargin;
|
||||
bool withEasy;
|
||||
bool ratingInherited;
|
||||
bool isDeveloperMode;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
|
||||
499
project/jni/application/enigma/src/gui/LevelMenu.cpp
Normal file
499
project/jni/application/enigma/src/gui/LevelMenu.cpp
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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/LevelMenu.hh"
|
||||
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "gui/LevelPackMenu.hh"
|
||||
|
||||
#include "ecl.hh"
|
||||
#include "game.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "server.hh"
|
||||
#include "sound.hh"
|
||||
#include "StateManager.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ecl;
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Level Menu -------------------- */
|
||||
|
||||
struct LevelMenuConfig {
|
||||
int buttonw, ibuttonw, buttonh;
|
||||
int lbuttonw, lbuttonh;
|
||||
ecl::Rect previewarea;
|
||||
int thumbsy; // y coordinate of thumbnail window
|
||||
int leftborder;
|
||||
|
||||
LevelMenuConfig (const ecl::Rect &screen)
|
||||
: buttonw (140), ibuttonw (90), buttonh (35),
|
||||
lbuttonw (140), lbuttonh (100),
|
||||
previewarea (10, 60, screen.w-50, screen.h-130),
|
||||
thumbsy (60),
|
||||
leftborder (10)
|
||||
{}
|
||||
};
|
||||
|
||||
LevelMenu::LevelMenu()
|
||||
: but_advancemode (new AdvanceModeButton),
|
||||
but_next (new ImageButton("ic-next", "ic-next1", this)),
|
||||
but_back (new StaticTextButton(N_("Main Menu"), this)),
|
||||
but_difficulty (new DifficultyButton),
|
||||
but_levelpack (new StaticTextButton(N_("Level Pack"), this)),
|
||||
lbl_lpinfo (new Label("")),
|
||||
lbl_statistics (new Label("")),
|
||||
lbl_levelname (new Label("", HALIGN_LEFT)),
|
||||
lbl_levelinfo (new Label("", HALIGN_LEFT)),
|
||||
shown_text_ttl(-1.0), main_quit (false)
|
||||
{
|
||||
HList *hl, *hll, *hlr ;
|
||||
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
|
||||
// Levelmenu configuration
|
||||
const int Y2 = 10; // y position for information area
|
||||
const int Y3 = vminfo.height-50; // y position for bottom button row
|
||||
LevelMenuConfig c (Rect (0, 0, vminfo.width, vminfo.height));
|
||||
|
||||
but_difficulty->set_listener (this);
|
||||
|
||||
|
||||
// Create buttons
|
||||
hll = new HList;
|
||||
hll->set_spacing (10);
|
||||
hll->set_alignment (HALIGN_CENTER, VALIGN_TOP);
|
||||
hll->set_default_size (c.ibuttonw, c.buttonh);
|
||||
hll->add_back (but_advancemode);
|
||||
hll->add_back (but_next);
|
||||
hll->add_back (but_difficulty);
|
||||
|
||||
hlr = new HList;
|
||||
hlr->set_spacing (10);
|
||||
hlr->set_alignment (HALIGN_CENTER, VALIGN_TOP);
|
||||
hlr->set_default_size (c.buttonw, c.buttonh);
|
||||
hlr->add_back (but_levelpack);
|
||||
hlr->add_back (but_back);
|
||||
|
||||
hl = new HList;
|
||||
hl->set_spacing (10);
|
||||
hl->set_alignment (HALIGN_CENTER, VALIGN_TOP);
|
||||
hl->set_default_size (2*c.buttonw + 10, c.buttonh);
|
||||
hl->add_back (hll);
|
||||
hl->add_back (hlr);
|
||||
this->add (hl, Rect(c.leftborder, Y3, vminfo.width-20, c.buttonh));
|
||||
|
||||
// Add navigation buttons
|
||||
pgup = new ImageButton("ic-up", "ic-up1", this);
|
||||
pgdown = new ImageButton("ic-down", "ic-down1", this);
|
||||
start = new ImageButton("ic-top", "ic-top1", this);
|
||||
end = new ImageButton("ic-bottom", "ic-bottom1", this);
|
||||
|
||||
Rect r(vminfo.width-30, c.thumbsy, 20, 50);
|
||||
r.y = c.thumbsy;
|
||||
add (pgup, r);
|
||||
r.y += 60;
|
||||
add (pgdown, r);
|
||||
r.y = c.thumbsy + 240;
|
||||
add (start, r);
|
||||
r.y += 60;
|
||||
add (end, r);
|
||||
|
||||
// Information area
|
||||
hl = new HList;
|
||||
hl->add_back (lbl_levelname, List::EXPAND);
|
||||
hl->add_back (lbl_lpinfo, List::TIGHT);
|
||||
this->add (hl, Rect (5, Y2, vminfo.width - 10, 28));
|
||||
|
||||
hl_info_stat = new HList;
|
||||
hl_info_stat->add_back (lbl_levelinfo, List::EXPAND); //Rect (c.leftborder, Y2+20,305, 28));
|
||||
hl_info_stat->add_back (lbl_statistics, List::TIGHT);
|
||||
this->add (hl_info_stat, Rect (5, Y2+20, vminfo.width - 10, 28));
|
||||
|
||||
// Prepare level selection widget
|
||||
levelwidget = new LevelWidget();
|
||||
levelwidget->set_listener(this);
|
||||
levelwidget->realize (c.previewarea);
|
||||
levelwidget->set_area (c.previewarea);
|
||||
|
||||
this->add (levelwidget);
|
||||
|
||||
updateIndex();
|
||||
}
|
||||
|
||||
void LevelMenu::tick(double dtime)
|
||||
{
|
||||
levelwidget->tick(dtime);
|
||||
static double timeaccu = 0.0;
|
||||
|
||||
// info texts disappear after some time
|
||||
if (shown_text_ttl>0.0) {
|
||||
shown_text_ttl -= dtime;
|
||||
if (shown_text_ttl <= 0.0)
|
||||
shown_text = "";
|
||||
}
|
||||
timeaccu += dtime;
|
||||
if (timeaccu > 0.1) {
|
||||
update_info();
|
||||
timeaccu = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const char *helptext_levelmenu[] = {
|
||||
N_("Escape:"), N_("Skip to main menu"),
|
||||
"F1:", N_("Show this help"),
|
||||
"F5:", 0, // see below
|
||||
N_("Arrows:"), N_("Select level"),
|
||||
N_("Return:"), N_("Play selected level"),
|
||||
N_("Back/Space:"), N_("Previous/next levelpack"),
|
||||
"u", N_("Mark current level as Unsolved"),
|
||||
// "s", N_("Mark current level as Solved"),
|
||||
N_("Alt+Return:"), N_("Switch between fullscreen and window"),
|
||||
N_("Left click:"), N_("Play selected level"),
|
||||
N_("Right or control click:"), N_("Inspect selected level"),
|
||||
0
|
||||
};
|
||||
|
||||
bool LevelMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
// Pass all events to the level widget first
|
||||
bool handled=levelwidget->on_event(e);
|
||||
|
||||
if (!handled) {
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
handled=true;
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_SPACE: next_levelpack(); break;
|
||||
case SDLK_BACKSPACE: previous_levelpack(); break;
|
||||
case SDLK_F1:
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST)
|
||||
helptext_levelmenu[5] = N_("Select next level for world record hunt");
|
||||
else
|
||||
helptext_levelmenu[5] = N_("Select next unsolved level");
|
||||
|
||||
displayHelp(helptext_levelmenu, 200);
|
||||
draw_all();
|
||||
break;
|
||||
case SDLK_F5:
|
||||
next_unsolved();
|
||||
break;
|
||||
case SDLK_u: {
|
||||
lev::ScoreManager::instance()->markUnsolved(lev::Index::getCurrentProxy(),
|
||||
app.state->getInt("Difficulty"));
|
||||
invalidate_all();
|
||||
break;
|
||||
}
|
||||
case SDLK_s:
|
||||
lev::ScoreManager::instance()->markSolved(lev::Index::getCurrentProxy(),
|
||||
app.state->getInt("Difficulty"));
|
||||
invalidate_all();
|
||||
break;
|
||||
default: handled=false; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
handled = Menu::on_event (e);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void LevelMenu::on_action(Widget *w)
|
||||
{
|
||||
if (w==levelwidget) {
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int ilevel = ind->getCurrentPosition();
|
||||
if (w->lastModifierKeys() & KMOD_CTRL && w->lastModifierKeys() & KMOD_SHIFT) {
|
||||
// force a reload from file
|
||||
lev::Proxy * curProxy = lev::Proxy::loadedLevel();
|
||||
if (curProxy != NULL)
|
||||
curProxy->release();
|
||||
}
|
||||
|
||||
if ((unsigned)ilevel < ind->size()) {
|
||||
if (ind->mayPlayLevel(ilevel+1)) {
|
||||
game::StartGame();
|
||||
ilevel = ind->getCurrentPosition();
|
||||
invalidate_all();
|
||||
ind->setCurrentPosition(ilevel);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
}
|
||||
else
|
||||
show_text(_("You are not allowed to play this level yet."));
|
||||
}
|
||||
} else if (w == but_back) {
|
||||
main_quit = true;
|
||||
Menu::quit();
|
||||
} else if (w == pgup) {
|
||||
levelwidget->page_up();
|
||||
} else if (w == pgdown) {
|
||||
levelwidget->page_down();
|
||||
} else if (w == start) {
|
||||
levelwidget->start();
|
||||
} else if (w == end) {
|
||||
levelwidget->end();
|
||||
} else if (w == but_next) {
|
||||
next_unsolved();
|
||||
} else if (w == but_levelpack) {
|
||||
main_quit = false;
|
||||
Menu::quit();
|
||||
} else if (w == but_difficulty) {
|
||||
but_difficulty->on_action(w);
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
void LevelMenu::update_info() {
|
||||
// Note: all format strings have to be translated directly
|
||||
// as the formatted strings can no longer be translated.
|
||||
// The instant language change is guaranteed by the frequent
|
||||
// call of is method!
|
||||
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int size = ind->size();
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
int difficulty = app.state->getInt("Difficulty");
|
||||
|
||||
lbl_lpinfo->set_text(ecl::strf(_("%s: %d levels"),
|
||||
ind->getName().c_str(), size));
|
||||
|
||||
if (size == 0) {
|
||||
// empty level pack
|
||||
lbl_statistics->set_text ("-");
|
||||
lbl_levelname->set_text ("-");
|
||||
lbl_levelinfo->set_text ("-");
|
||||
}
|
||||
else {
|
||||
int iselected = ind->getCurrentPosition();
|
||||
|
||||
// Display levelpack statistics (percentage of solved levels)
|
||||
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST) {
|
||||
int pct = 100* scm->countBestScore(ind, difficulty)/ size;
|
||||
lbl_statistics->set_text(ecl::strf(_("%d%% best"), pct));
|
||||
}
|
||||
else if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_OVER_PAR) {
|
||||
int pct = 100* scm->countParScore(ind, difficulty)/ size;
|
||||
double hcp = scm->calcHCP(ind, difficulty);
|
||||
lbl_statistics->set_text(ecl::strf(_("%d%% par, hcp %.1f"), pct, hcp));
|
||||
}
|
||||
else {
|
||||
int pct = 100* scm->countSolved(ind, difficulty) / size;
|
||||
lbl_statistics->set_text(ecl::strf(_("%d%% solved"), pct));
|
||||
}
|
||||
|
||||
// Display level name
|
||||
if (enigma::WizardMode) {
|
||||
// add level path info - we just can display the normalized path
|
||||
// as we did not yet locate the absolute path - the user can
|
||||
// use the inspector to check the absolute path!
|
||||
lbl_levelname->set_text(ecl::strf("#%d: %s (%s)",
|
||||
ind->getCurrentLevel(), curProxy->getTitle().c_str(),
|
||||
curProxy->getNormLevelPath().c_str()));
|
||||
} else {
|
||||
lbl_levelname->set_text(ecl::strf("#%d: %s",
|
||||
ind->getCurrentLevel(), curProxy->getTitle().c_str()));
|
||||
}
|
||||
|
||||
// Display best time
|
||||
if (shown_text.length()) {
|
||||
lbl_levelinfo->set_text(shown_text);
|
||||
}
|
||||
else {
|
||||
// TODO prepare for scores that are not time based!
|
||||
char txt[200];
|
||||
lev::RatingManager *ratingMgr = lev::RatingManager::instance();
|
||||
int wr_time = ratingMgr->getBestScore(curProxy, difficulty);
|
||||
int par_time = ratingMgr->getParScore(curProxy, difficulty);
|
||||
bool is_par = scm->parScoreReached(curProxy, difficulty);
|
||||
int best_user_time = scm->getBestUserScore(curProxy, difficulty);
|
||||
string wr_name = ratingMgr->getBestScoreHolder(curProxy, difficulty);
|
||||
bool wr_name_displayed = false;
|
||||
|
||||
string your_time;
|
||||
string wr_text;
|
||||
|
||||
if (best_user_time>0) {
|
||||
your_time = strf(_("Your time: %d:%02d"),
|
||||
best_user_time/60, best_user_time%60);
|
||||
|
||||
if (wr_time>0) {
|
||||
int below = wr_time - best_user_time;
|
||||
if (below == 0)
|
||||
wr_text = _("That's world record.");
|
||||
else if (below>0)
|
||||
wr_text = strf(_("That's %d:%02d below world record."),
|
||||
below/60, below%60);
|
||||
}
|
||||
}
|
||||
|
||||
if (wr_text.length() == 0 && wr_time>0) {
|
||||
if (wr_name.length()) {
|
||||
wr_name_displayed = true;
|
||||
} else
|
||||
if (is_par || par_time < 0)
|
||||
wr_text = strf(_("World record: %d:%02d"), wr_time/60, wr_time%60);
|
||||
else
|
||||
wr_text = strf(_("Par: %d:%02d World record: %d:%02d"),
|
||||
par_time/60, par_time%60, wr_time/60, wr_time%60);
|
||||
}
|
||||
|
||||
if (!your_time.empty())
|
||||
your_time += " ";
|
||||
|
||||
int wr_cut = 0;
|
||||
do {
|
||||
if (wr_name_displayed) {
|
||||
std::string tmp = ratingMgr->getBestScoreHolder(curProxy, difficulty, wr_cut++);
|
||||
if (!tmp.empty())
|
||||
wr_name = tmp;
|
||||
if (is_par || par_time < 0)
|
||||
wr_text = strf(_("World record by %s: %d:%02d"),
|
||||
wr_name.c_str(), wr_time/60, wr_time%60);
|
||||
else
|
||||
wr_text = strf(_("Par: %d:%02d World record by %s: %d:%02d"),
|
||||
par_time/60, par_time%60, wr_name.c_str(), wr_time/60, wr_time%60);
|
||||
}
|
||||
lbl_levelinfo->set_text(your_time + wr_text);
|
||||
} while (!hl_info_stat->fits() && wr_name_displayed && (wr_cut < 20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelMenu::updateIndex()
|
||||
{
|
||||
levelwidget->syncFromIndexMgr();
|
||||
|
||||
update_info();
|
||||
}
|
||||
|
||||
void LevelMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
video::SetCaption(("Enigma - Level Menu"));
|
||||
sound::PlayMusic (options::GetString("MenuMusicFile"));
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
void LevelMenu::next_unsolved()
|
||||
{
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
if (ind->advanceLevel(lev::ADVANCE_NEXT_MODE)) {
|
||||
levelwidget->syncFromIndexMgr();
|
||||
} else
|
||||
show_text(_("No further unsolved level available!"));
|
||||
}
|
||||
|
||||
void LevelMenu::next_levelpack()
|
||||
{
|
||||
lev::Index::setCurrentIndex(lev::Index::nextGroupIndex()->getName());
|
||||
updateIndex();
|
||||
}
|
||||
|
||||
void LevelMenu::previous_levelpack() {
|
||||
lev::Index::setCurrentIndex(lev::Index::previousGroupIndex()->getName());
|
||||
updateIndex();
|
||||
}
|
||||
|
||||
void LevelMenu::show_text(const string& text) {
|
||||
shown_text = text;
|
||||
shown_text_ttl = 2.0; // show for two seconds
|
||||
}
|
||||
|
||||
bool LevelMenu::isMainQuit() {
|
||||
return main_quit;
|
||||
}
|
||||
|
||||
/* -------------------- DifficultyButton -------------------- */
|
||||
|
||||
DifficultyButton::DifficultyButton() : ImageButton("ic-easymode","ic-easymode",this) {
|
||||
update();
|
||||
}
|
||||
|
||||
void DifficultyButton::update() {
|
||||
if (app.state->getInt("Difficulty") == DIFFICULTY_EASY)
|
||||
ImageButton::set_images("ic-easymode","ic-normalmode");
|
||||
else
|
||||
ImageButton::set_images("ic-normalmode","ic-easymode");
|
||||
}
|
||||
|
||||
void DifficultyButton::on_action(Widget *)
|
||||
{
|
||||
int newdifficulty = (DIFFICULTY_EASY+DIFFICULTY_HARD) - app.state->getInt("Difficulty");
|
||||
app.state->setProperty("Difficulty", newdifficulty); update();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void DifficultyButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
update();
|
||||
ImageButton::draw(gc, r);
|
||||
}
|
||||
|
||||
/* -------------------- AdvanceModeButton -------------------- */
|
||||
|
||||
AdvanceModeButton::AdvanceModeButton() : ImageButton("","",this) {
|
||||
update();
|
||||
}
|
||||
|
||||
void AdvanceModeButton::update() {
|
||||
switch (app.state->getInt("NextLevelMode")) {
|
||||
case lev::NEXT_LEVEL_UNSOLVED :
|
||||
ImageButton::set_images("ic-unsolved", "par");
|
||||
break;
|
||||
case lev::NEXT_LEVEL_OVER_PAR :
|
||||
ImageButton::set_images("par", "ic-worldrecord");
|
||||
break;
|
||||
case lev::NEXT_LEVEL_NOT_BEST :
|
||||
ImageButton::set_images("ic-worldrecord", "ic-strictlynext");
|
||||
break;
|
||||
case lev::NEXT_LEVEL_STRICTLY : // use as default, too
|
||||
default:
|
||||
ImageButton::set_images("ic-strictlynext","ic-unsolved");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AdvanceModeButton::on_action(Widget *)
|
||||
{
|
||||
switch (app.state->getInt("NextLevelMode")) {
|
||||
case lev::NEXT_LEVEL_STRICTLY :
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_UNSOLVED);
|
||||
break;
|
||||
case lev::NEXT_LEVEL_UNSOLVED :
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_OVER_PAR);
|
||||
break;
|
||||
case lev::NEXT_LEVEL_OVER_PAR :
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_NOT_BEST);
|
||||
break;
|
||||
case lev::NEXT_LEVEL_NOT_BEST :
|
||||
default:
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_STRICTLY);
|
||||
}
|
||||
update();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
99
project/jni/application/enigma/src/gui/LevelMenu.hh
Normal file
99
project/jni/application/enigma/src/gui/LevelMenu.hh
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELMENU_HH_INCLUDED
|
||||
#define GUI_LEVELMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/LevelWidget.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelMenu -------------------- */
|
||||
|
||||
class LevelMenu : public Menu {
|
||||
public:
|
||||
LevelMenu();
|
||||
|
||||
// Rotate through levels and packs
|
||||
void next_levelpack();
|
||||
void previous_levelpack();
|
||||
void show_text(const string& text);
|
||||
bool isMainQuit();
|
||||
|
||||
private:
|
||||
void update_info();
|
||||
void next_unsolved();
|
||||
|
||||
void updateIndex();
|
||||
|
||||
// Menu interface.
|
||||
void tick (double time);
|
||||
void draw_background(ecl::GC &gc);
|
||||
|
||||
// Widget interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *w);
|
||||
|
||||
// Variables.
|
||||
|
||||
|
||||
Widget *pgup, *pgdown, *start, *end;
|
||||
Widget *but_advancemode; // Next unsolved level button
|
||||
Widget *but_next;
|
||||
Widget *but_back; // "Back" button
|
||||
Widget *but_difficulty; // "Difficulty" button
|
||||
TextButton *but_levelpack; // "Levelpack" button
|
||||
HList *hl_info_stat;
|
||||
Label *lbl_lpinfo; // Levelpack information
|
||||
Label *lbl_statistics; // percentage solved
|
||||
Label *lbl_levelname;
|
||||
Label *lbl_levelinfo;
|
||||
LevelWidget *levelwidget;
|
||||
string shown_text; // info text (disappears automatically)
|
||||
double shown_text_ttl; // rest duration for shown_text
|
||||
bool main_quit;
|
||||
};
|
||||
|
||||
/* -------------------- Buttons -------------------- */
|
||||
|
||||
class DifficultyButton : public ImageButton {
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *);
|
||||
public:
|
||||
DifficultyButton();
|
||||
virtual void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
void update();
|
||||
};
|
||||
|
||||
class AdvanceModeButton : public ImageButton {
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *);
|
||||
public:
|
||||
AdvanceModeButton();
|
||||
private:
|
||||
void update();
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
391
project/jni/application/enigma/src/gui/LevelPackComposer.cpp
Normal file
391
project/jni/application/enigma/src/gui/LevelPackComposer.cpp
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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/LevelPackComposer.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "errors.hh"
|
||||
#include "nls.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
lev::PersistentIndex * LevelPackComposer::clipboard = NULL;
|
||||
|
||||
static const char *helptext[] = {
|
||||
N_("Shift click:"), N_("Add to clipboard"),
|
||||
N_("Shift delete:"), N_("Clear clipboard"),
|
||||
N_("F8:"), N_("Insert clipboard as reference"),
|
||||
N_("F9:"), N_("Insert clipboard as copy"),
|
||||
// N_("F10:"), N_("Move clipboard levels"),
|
||||
N_("Alt left arrow:"), N_("Exchange level with predecessor"),
|
||||
N_("Alt right arrow:"), N_("Exchange level with successor"),
|
||||
N_("Delete:"), N_("Delete level"),
|
||||
N_("F5:"), N_("Update index from levels"),
|
||||
0
|
||||
};
|
||||
#if 0
|
||||
// fake gettext to register the following strings for I18N
|
||||
_("F10")
|
||||
_("Move clipboard levels")
|
||||
#endif
|
||||
|
||||
|
||||
LevelPackComposer::LevelPackComposer(bool enableEdit) :
|
||||
isEditable (enableEdit), isModified (false) {
|
||||
if (clipboard == NULL) {
|
||||
std::vector<std::string> dummy;
|
||||
clipboard = new lev::PersistentIndex(" ", false); // mark as incomplete
|
||||
}
|
||||
|
||||
curIndex = dynamic_cast<lev::PersistentIndex *>(lev::Index::getCurrentIndex());
|
||||
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
// Add navigation buttons
|
||||
pgup = new ImageButton("ic-up", "ic-up1", this);
|
||||
pgdown = new ImageButton("ic-down", "ic-down1", this);
|
||||
start = new ImageButton("ic-top", "ic-top1", this);
|
||||
end = new ImageButton("ic-bottom", "ic-bottom1", this);
|
||||
|
||||
Rect r(vminfo.width-30, 60, 20, 50);
|
||||
r.y = 60;
|
||||
add (pgup, r);
|
||||
r.y += 60;
|
||||
add (pgdown, r);
|
||||
r.y = 60 + 240;
|
||||
add (start, r);
|
||||
r.y += 60;
|
||||
add (end, r);
|
||||
|
||||
// Prepare level selection widget
|
||||
levelwidget = new LevelWidget(false, isEditable);
|
||||
levelwidget->set_listener(this);
|
||||
ecl::Rect previewarea(10, 60, vminfo.width-50, vminfo.height-130);
|
||||
levelwidget->realize (previewarea);
|
||||
levelwidget->set_area (previewarea);
|
||||
|
||||
this->add(levelwidget);
|
||||
|
||||
// Information area
|
||||
lbl_lpinfo = new Label();
|
||||
lbl_clipinfo = new Label();
|
||||
lbl_levelname = new Label();
|
||||
lbl_clipcontent = new Label();
|
||||
|
||||
HList *hl = new HList;
|
||||
hl->set_spacing(10);
|
||||
hl->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
hl->set_default_size(vminfo.width/2 - 10, 28);
|
||||
hl->add_back (lbl_lpinfo);
|
||||
hl->add_back (lbl_clipinfo);
|
||||
this->add (hl, Rect (5, 10, vminfo.width - 10, 28));
|
||||
|
||||
hl = new HList;
|
||||
hl->set_spacing(10);
|
||||
hl->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
clipContentWidth = vminfo.width/2 - 10;
|
||||
hl->set_default_size(clipContentWidth, 28);
|
||||
hl->add_back (lbl_levelname);
|
||||
hl->add_back (lbl_clipcontent);
|
||||
this->add (hl, Rect (5, 10+20, vminfo.width - 10, 28));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_back = new StaticTextButton(N_("Ok"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(new Label());
|
||||
commandHList->add_back(new Label());
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_back);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
}
|
||||
|
||||
void LevelPackComposer::tick(double dtime)
|
||||
{
|
||||
levelwidget->tick(dtime);
|
||||
static double timeaccu = 0.0;
|
||||
|
||||
// // info texts disappear after some time
|
||||
// if (shown_text_ttl>0.0) {
|
||||
// shown_text_ttl -= dtime;
|
||||
// if (shown_text_ttl <= 0.0)
|
||||
// shown_text = "";
|
||||
// }
|
||||
timeaccu += dtime;
|
||||
if (timeaccu > 0.1) {
|
||||
update_info();
|
||||
timeaccu = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelPackComposer::on_event (const SDL_Event &e) {
|
||||
// Pass all events to the level widget first
|
||||
bool handled=levelwidget->on_event(e);
|
||||
|
||||
if (!handled) {
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_DELETE:
|
||||
if (SDL_GetModState() & KMOD_SHIFT) {
|
||||
// delete clipboard
|
||||
clipboard->clear();
|
||||
handled=true;
|
||||
} else {
|
||||
// delete level
|
||||
if (isEditable) {
|
||||
int pos = curIndex->getCurrentPosition();
|
||||
lev::Proxy * curProxy = curIndex->getCurrent();
|
||||
if (curProxy == NULL) {
|
||||
// levelpack is empty
|
||||
handled=true;
|
||||
break;
|
||||
}
|
||||
if (curIndex->isSource(curProxy) &&
|
||||
backups.find(curProxy->getNormLevelPath()) == backups.end()) {
|
||||
// mark as deletion candidate - the final check
|
||||
// if we delete it really occurs on save
|
||||
deletions.insert(curProxy->getNormLevelPath());
|
||||
}
|
||||
curIndex->erase(pos);
|
||||
if (pos >= curIndex->size() && pos > 0)
|
||||
curIndex->setCurrentPosition(pos-1);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
isModified = true;
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_F8:
|
||||
if (isEditable) {
|
||||
int pos = (curIndex->size() == 0) ? 0 : curIndex->getCurrentPosition() + 1;
|
||||
for (int i = 0; i < clipboard->size(); i++) {
|
||||
lev::Variation var = clipboard->getVariation(i);
|
||||
curIndex->insertProxy(pos++, clipboard->getProxy(i), true,
|
||||
var.ctrl, var.unit, var.target, var.extensions);
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_F9:
|
||||
if (isEditable && !curIndex->isCross()) {
|
||||
int pos = (curIndex->size() == 0) ? 0 : curIndex->getCurrentPosition() + 1;
|
||||
for (int i = 0; i < clipboard->size(); i++) {
|
||||
lev::Variation var = clipboard->getVariation(i);
|
||||
lev::Proxy *levelCopy = clipboard->getProxy(i)->copy(app.userPath + "/levels",
|
||||
curIndex->getPackPath(), true);
|
||||
if (levelCopy == NULL) {
|
||||
// insert a crossreference
|
||||
curIndex->insertProxy(pos++, clipboard->getProxy(i), true,
|
||||
var.ctrl, var.unit, var.target, var.extensions);
|
||||
} else {
|
||||
// insert reference to our copy
|
||||
curIndex->insertProxy(pos++, levelCopy, true,
|
||||
var.ctrl, var.unit, var.target, var.extensions);
|
||||
backups.insert(levelCopy->getNormLevelPath());
|
||||
deletions.erase(levelCopy->getNormLevelPath());
|
||||
}
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
if (isEditable && (SDL_GetModState() & KMOD_ALT)) {
|
||||
int pos = curIndex->getCurrentPosition();
|
||||
if (pos > 0) {
|
||||
curIndex->exchange(pos, pos-1);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
if (isEditable && (SDL_GetModState() & KMOD_ALT)) {
|
||||
int pos = curIndex->getCurrentPosition();
|
||||
if (pos < curIndex->size() - 1) {
|
||||
curIndex->exchange(pos, pos+1);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_F5:
|
||||
if (isEditable) {
|
||||
curIndex->updateFromProxies();
|
||||
isModified = true;
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_F1:
|
||||
displayHelp(helptext, 200);
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
handled = Menu::on_event (e);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void LevelPackComposer::on_action(Widget *w) {
|
||||
if (w==levelwidget) {
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int ilevel = ind->getCurrentPosition();
|
||||
if (w->lastModifierKeys() & KMOD_SHIFT) {
|
||||
lev::Variation var;
|
||||
lev::Proxy * curProxy = lev::Index::getCurrentProxy();
|
||||
if (curProxy->getNormPathType() != lev::Proxy::pt_absolute) {
|
||||
// all but absolute commandline proxies may be put on the clipboard
|
||||
if (curIndex != NULL)
|
||||
var = curIndex->getVariation(curIndex->getCurrentPosition());
|
||||
clipboard->appendProxy(curProxy, var.ctrl,
|
||||
var.unit, var.target, var.extensions);
|
||||
sound::EmitSoundEvent ("menuok");
|
||||
} else {
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
}
|
||||
}
|
||||
} else if (w == but_back) {
|
||||
if (isModified) {
|
||||
// save index
|
||||
curIndex->save(true);
|
||||
// delete levelfiles
|
||||
std::set<std::string>::iterator it;
|
||||
for (it = deletions.begin(); it != deletions.end(); it++) {
|
||||
if (!curIndex->hasNormLevelPath(*it)) {
|
||||
// delete plain files on user path - ignore system and zip levels
|
||||
std::string path = app.userPath + "/levels/" + (*it);
|
||||
std::remove((path + ".xml").c_str());
|
||||
std::remove((path + ".lua").c_str());
|
||||
}
|
||||
}
|
||||
// delete backups
|
||||
std::string base = app.userPath + "/levels/";
|
||||
for (it = backups.begin(); it != backups.end(); it++) {
|
||||
std::remove((base + *it + ".xml~").c_str());
|
||||
std::remove((base + *it + ".lua~").c_str());
|
||||
}
|
||||
}
|
||||
Menu::quit();
|
||||
} else if (w == but_ignore) {
|
||||
if (isModified) {
|
||||
// we need to reload the index
|
||||
curIndex->loadDoc();
|
||||
// restore backups
|
||||
std::string base = app.userPath + "/levels/";
|
||||
std::set<std::string>::iterator it;
|
||||
for (it = backups.begin(); it != backups.end(); it++) {
|
||||
std::remove((base + *it + ".xml").c_str());
|
||||
std::rename((base + *it + ".xml~").c_str(), (base + *it + ".xml").c_str());
|
||||
std::remove((base + *it + ".lua").c_str());
|
||||
std::rename((base + *it + ".lua~").c_str(), (base + *it + ".lua").c_str());
|
||||
}
|
||||
}
|
||||
Menu::quit();
|
||||
} else if (w == pgup) {
|
||||
levelwidget->page_up();
|
||||
} else if (w == pgdown) {
|
||||
levelwidget->page_down();
|
||||
} else if (w == start) {
|
||||
levelwidget->start();
|
||||
} else if (w == end) {
|
||||
levelwidget->end();
|
||||
}
|
||||
}
|
||||
void LevelPackComposer::update_info() {
|
||||
// Note: all format strings have to be translated directly
|
||||
// as the formatted strings can no longer be translated.
|
||||
// The instant language change is guaranteed by the frequent
|
||||
// call of is method!
|
||||
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int size = ind->size();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
|
||||
lbl_lpinfo->set_text(ecl::strf(_("%s: %d levels"),
|
||||
ind->getName().c_str(), size));
|
||||
|
||||
if (size == 0) {
|
||||
// empty level pack
|
||||
lbl_levelname->set_text ("-");
|
||||
}
|
||||
else {
|
||||
lbl_levelname->set_text(ecl::strf("#%d:(%s)",
|
||||
ind->getCurrentLevel(),
|
||||
curProxy->getNormLevelPath().c_str()));
|
||||
}
|
||||
|
||||
int csize = clipboard->size();
|
||||
lbl_clipinfo->set_text(ecl::strf(_("Clipboard: %d levels"), csize));
|
||||
if (csize == 0) {
|
||||
// empty level pack
|
||||
lbl_clipcontent->set_text ("-");
|
||||
}
|
||||
else {
|
||||
std::string clipstring = clipboard->getProxy(0)->getTitle();
|
||||
for (int i = 1; i < csize; i++)
|
||||
clipstring += ", " + clipboard->getProxy(i)->getTitle();
|
||||
lbl_clipcontent->set_text(clipstring);
|
||||
if (enigma::GetFont("menufont")->get_width(clipstring.c_str()) > clipContentWidth)
|
||||
lbl_clipcontent->set_alignment(HALIGN_RIGHT);
|
||||
else
|
||||
lbl_clipcontent->set_alignment(HALIGN_CENTER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LevelPackComposer::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Level Pack Composer"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
if (isModified)
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("changed"));
|
||||
}
|
||||
|
||||
|
||||
}} // namespace enigma::gui
|
||||
61
project/jni/application/enigma/src/gui/LevelPackComposer.hh
Normal file
61
project/jni/application/enigma/src/gui/LevelPackComposer.hh
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LEVELPACKCOMPOSER_HH_INCLUDED
|
||||
#define GUI_LEVELPACKCOMPOSER_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/LevelWidget.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/PersistentIndex.hh"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class LevelPackComposer : public gui::Menu {
|
||||
public:
|
||||
LevelPackComposer(bool enableEdit);
|
||||
|
||||
void tick(double dtime);
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
private:
|
||||
void update_info();
|
||||
|
||||
static lev::PersistentIndex * clipboard;
|
||||
bool isEditable;
|
||||
bool isModified;
|
||||
lev::PersistentIndex * curIndex;
|
||||
std::set<std::string> deletions; // normLevelPath
|
||||
std::set<std::string> backups; // normLevelPath
|
||||
Widget *pgup, *pgdown, *start, *end;
|
||||
LevelWidget *levelwidget;
|
||||
Label *lbl_lpinfo; // Levelpack information
|
||||
Label *lbl_levelname;
|
||||
Label *lbl_clipinfo;
|
||||
Label *lbl_clipcontent;
|
||||
int clipContentWidth;
|
||||
Widget *but_ignore;
|
||||
Widget *but_back;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
540
project/jni/application/enigma/src/gui/LevelPackConfig.cpp
Normal file
540
project/jni/application/enigma/src/gui/LevelPackConfig.cpp
Normal file
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 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/LevelPackConfig.hh"
|
||||
#include "gui/LevelPackComposer.hh"
|
||||
#include "ecl.hh"
|
||||
#include "errors.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
GroupButton::GroupButton(std::vector<std::string> groups, int pos) :
|
||||
ValueButton(0, groups.size() - 1),
|
||||
position (pos), groupNames (groups) {
|
||||
init();
|
||||
}
|
||||
|
||||
int GroupButton::get_value() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
void GroupButton::set_value(int value) {
|
||||
position = value;
|
||||
}
|
||||
|
||||
std::string GroupButton::get_text(int value) const {
|
||||
return groupNames[value];
|
||||
}
|
||||
|
||||
/* ------------------- LevelmodeButton -------------------- */
|
||||
|
||||
LevelmodeButton::LevelmodeButton(bool initialMode) :
|
||||
ImageButton("ic-link_copy","ic-link_copy",this), mode (initialMode) {
|
||||
update();
|
||||
}
|
||||
|
||||
bool LevelmodeButton::isLinkOnly() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
void LevelmodeButton::update() {
|
||||
if (mode)
|
||||
ImageButton::set_images("ic-link","ic-link_copy");
|
||||
else
|
||||
ImageButton::set_images("ic-link_copy","ic-link");
|
||||
}
|
||||
|
||||
void LevelmodeButton::on_action(Widget *)
|
||||
{
|
||||
mode = !mode;
|
||||
update();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void LevelmodeButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
update();
|
||||
ImageButton::draw(gc, r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LevelPackConfig::LevelPackConfig(std::string indexName, std::string groupName,
|
||||
bool forceGroupReasign) : isReasignOnly (forceGroupReasign),
|
||||
undo_quit (false), didEditMetaData (false), titleTF (NULL) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
if (indexName.empty())
|
||||
// new levelpack
|
||||
packIndex = new lev::PersistentIndex(" ", false,
|
||||
INDEX_DEFAULT_PACK_LOCATION, "",
|
||||
INDEX_STD_FILENAME, lev::Index::getCurrentGroup()); // mark as incomplete
|
||||
else
|
||||
packIndex = lev::Index::findIndex(indexName);
|
||||
ASSERT (packIndex != NULL, XFrontend, "not existing index Name");
|
||||
persIndex = dynamic_cast<lev::PersistentIndex *>(packIndex);
|
||||
isPersistent = (persIndex != NULL);
|
||||
isEditable = isPersistent ? persIndex->isUserEditable() : false;
|
||||
|
||||
// build a list of allowed group
|
||||
std::vector<std::string> groups = lev::Index::getGroupNames();
|
||||
// eliminate pseudo group "All Packs"
|
||||
std::vector<std::string>::iterator itg = groups.begin();
|
||||
while (itg != groups.end()) {
|
||||
if (*itg == INDEX_ALL_PACKS) {
|
||||
itg = groups.erase(itg);
|
||||
break;
|
||||
}
|
||||
if (itg != groups.end())
|
||||
itg++;
|
||||
}
|
||||
// add pseudo group "[Every Group]"
|
||||
groups.push_back(std::string("[") + INDEX_EVERY_GROUP +"]");
|
||||
intialGroupPosition = groups.size() - 1; // INDEX_EVERY_GROUP as default
|
||||
// mark index's default group with square brackets and find current group
|
||||
bool defaultGroupFound = false;
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (groups[i] == packIndex->getGroupName()) {
|
||||
intialGroupPosition = i;
|
||||
}
|
||||
if (groups[i] == packIndex->getDefaultGroupName()) {
|
||||
groups[i] = std::string("[") + groups[i] +"]";
|
||||
defaultGroupFound = true;
|
||||
}
|
||||
}
|
||||
if (!defaultGroupFound) {
|
||||
groups.push_back(std::string("[") + packIndex->getDefaultGroupName() +"]");
|
||||
}
|
||||
groupButton = new GroupButton(groups, intialGroupPosition);
|
||||
|
||||
// index location list setup
|
||||
std::vector<lev::Index *> * allIndices = lev::Index::getGroup(INDEX_ALL_PACKS);
|
||||
for (int i = 0; i < allIndices->size(); i++)
|
||||
locationList.push_back((*allIndices)[i]->getName());
|
||||
position = -1;
|
||||
for (int i = 0; i < locationList.size(); i++) {
|
||||
if (locationList[i] == indexName) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
oldPosition = position;
|
||||
if (position < 0) {
|
||||
// append new levelpack as last
|
||||
locationList.push_back(indexName);
|
||||
position = locationList.size() - 1;
|
||||
}
|
||||
|
||||
VList * titleLeftVList = new VList;
|
||||
titleLeftVList->set_spacing(11);
|
||||
titleLeftVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
titleLeftVList->set_default_size(140, 35);
|
||||
Label * titleLabel = new Label(N_("Levelpack:"), HALIGN_RIGHT);
|
||||
Label * ownerLabel = new Label(N_("Owner:"), HALIGN_RIGHT);
|
||||
Label * groupLabel = new Label(N_("Group:"), HALIGN_RIGHT);
|
||||
Label * loactionLabel1 = new Label(N_("Location"), HALIGN_LEFT);
|
||||
Label * loactionLabel2 = new Label(N_("in [All Packs]:"), HALIGN_RIGHT);
|
||||
titleLeftVList->add_back(titleLabel);
|
||||
if (!isReasignOnly) {
|
||||
titleLeftVList->add_back(ownerLabel);
|
||||
}
|
||||
titleLeftVList->add_back(groupLabel);
|
||||
if (!isReasignOnly) {
|
||||
titleLeftVList->add_back(new Label());
|
||||
titleLeftVList->add_back(loactionLabel1);
|
||||
titleLeftVList->add_back(loactionLabel2);
|
||||
titleLeftVList->add_back(new Label());
|
||||
titleLeftVList->add_back(new Label());
|
||||
}
|
||||
|
||||
valueLeftVList = new VList;
|
||||
valueLeftVList->set_spacing(11);
|
||||
valueLeftVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
valueLeftVList->set_default_size(160, 35);
|
||||
|
||||
titleValueLabel = new UntranslatedLabel(indexName, HALIGN_CENTER);
|
||||
ownerValueLabel = new UntranslatedLabel(isPersistent ? persIndex->getOwner() : "System");
|
||||
|
||||
pre2Index = new UntranslatedLabel();
|
||||
pre1Index = new UntranslatedLabel();
|
||||
thisIndex = new UntranslatedLabel();
|
||||
post1Index = new UntranslatedLabel();
|
||||
post2Index = new UntranslatedLabel();
|
||||
|
||||
valueLeftVList->add_back(titleValueLabel);
|
||||
if (!isReasignOnly) {
|
||||
valueLeftVList->add_back(ownerValueLabel);
|
||||
}
|
||||
valueLeftVList->add_back(groupButton);
|
||||
if (!isReasignOnly) {
|
||||
valueLeftVList->add_back(pre2Index);
|
||||
valueLeftVList->add_back(pre1Index);
|
||||
valueLeftVList->add_back(thisIndex);
|
||||
valueLeftVList->add_back(post1Index);
|
||||
valueLeftVList->add_back(post2Index);
|
||||
}
|
||||
|
||||
VList * scrollVList = new VList;
|
||||
scrollVList->set_spacing(12);
|
||||
scrollVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
scrollVList->set_default_size(30, 35);
|
||||
|
||||
scrollUp = new ImageButton("ic-up", "ic-up1", this);
|
||||
scrollDown = new ImageButton("ic-down", "ic-down1", this);
|
||||
scrollVList->add_back(scrollUp);
|
||||
scrollVList->add_back(scrollDown);
|
||||
|
||||
VList * metaVList = new VList;
|
||||
metaVList->set_spacing(12);
|
||||
metaVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
metaVList->set_default_size(140, 35);
|
||||
|
||||
if (isEditable)
|
||||
but_metadata = new StaticTextButton(N_("Edit Metadata"), this);
|
||||
else
|
||||
but_metadata = new Label();
|
||||
Label * releaseLabel = new Label(N_("Release:"), HALIGN_RIGHT);
|
||||
Label * revisionLabel = new Label(N_("Revision:"), HALIGN_RIGHT);
|
||||
Label * compatibilityLabel = new Label(N_("Compatibility:"), HALIGN_RIGHT);
|
||||
Label * defLocationLabel = new Label(N_("Default Location:"), HALIGN_RIGHT);
|
||||
Label * crossmodeLabel = new Label(N_("Level types:"), HALIGN_RIGHT);
|
||||
|
||||
if (!isReasignOnly) {
|
||||
metaVList->add_back(but_metadata);
|
||||
metaVList->add_back(new Label());
|
||||
if (WizardMode) {
|
||||
metaVList->add_back(releaseLabel);
|
||||
metaVList->add_back(revisionLabel);
|
||||
} else {
|
||||
metaVList->add_back(new Label());
|
||||
metaVList->add_back(new Label());
|
||||
}
|
||||
metaVList->add_back(crossmodeLabel);
|
||||
if (WizardMode) {
|
||||
metaVList->add_back(compatibilityLabel);
|
||||
} else {
|
||||
metaVList->add_back(new Label());
|
||||
}
|
||||
metaVList->add_back(defLocationLabel);
|
||||
metaVList->add_back(new Label());
|
||||
}
|
||||
|
||||
valueMetaVList = new VList;
|
||||
valueMetaVList->set_spacing(12);
|
||||
valueMetaVList->set_alignment(HALIGN_CENTER, VALIGN_CENTER);
|
||||
valueMetaVList->set_default_size(75, 35);
|
||||
Widget * levelmodeWidget;
|
||||
if (indexName.empty()){
|
||||
levelmode = new LevelmodeButton(false);
|
||||
levelmodeWidget = levelmode;
|
||||
} else {
|
||||
levelmodeWidget = new Image(isPersistent && !(persIndex->isCross()) ?
|
||||
"ic-link_copy" : "ic-link");
|
||||
}
|
||||
defLocationValueLabel = new Label(ecl::strf("%g", packIndex->getDefaultLocation()));
|
||||
releaseValueLabel = new Label(isPersistent ? ecl::strf("%d", persIndex->getRelease()) : "-");
|
||||
revisionValueLabel = new Label(isPersistent ? ecl::strf("%d", persIndex->getRevision()) : "-");
|
||||
compatibilityValueLabel = new Label(isPersistent ? ecl::strf("%.2f", persIndex->getCompatibility()) : "-");
|
||||
|
||||
if (!isReasignOnly) {
|
||||
valueMetaVList->add_back(new Label());
|
||||
valueMetaVList->add_back(new Label());
|
||||
if (WizardMode) {
|
||||
valueMetaVList->add_back(releaseValueLabel);
|
||||
valueMetaVList->add_back(revisionValueLabel);
|
||||
} else {
|
||||
valueMetaVList->add_back(new Label());
|
||||
valueMetaVList->add_back(new Label());
|
||||
}
|
||||
valueMetaVList->add_back(levelmodeWidget);
|
||||
if (WizardMode) {
|
||||
valueMetaVList->add_back(compatibilityValueLabel);
|
||||
} else {
|
||||
valueMetaVList->add_back(new Label());
|
||||
}
|
||||
valueMetaVList->add_back(defLocationValueLabel);
|
||||
valueMetaVList->add_back(new Label());
|
||||
}
|
||||
|
||||
|
||||
if (isReasignOnly) {
|
||||
this->add(titleLeftVList, Rect(vminfo.width/2 - 270, 15, 140, vminfo.height-97));
|
||||
this->add(valueLeftVList, Rect(vminfo.width/2 - 80, 15, 160, vminfo.height-97));
|
||||
} else {
|
||||
this->add(titleLeftVList, Rect(vminfo.width/2 - 300, 15, 140, vminfo.height-97));
|
||||
this->add(valueLeftVList, Rect(vminfo.width/2 - 140, 15, 160, vminfo.height-97));
|
||||
this->add(scrollVList, Rect(vminfo.width/2 + 30, 15+3*(35+12) + (vminfo.height-480)/2, 30, 5*35+4*12));
|
||||
this->add(metaVList, Rect(vminfo.width/2 + 80, 15, 140, vminfo.height-97));
|
||||
this->add(valueMetaVList, Rect(vminfo.width/2 + 235, 15, 75, vminfo.height-97));
|
||||
}
|
||||
|
||||
errorLabel = new Label("", HALIGN_CENTER);
|
||||
this->add(errorLabel, Rect(10, vminfo.height-97, vminfo.width-20, 35));
|
||||
|
||||
if (isReasignOnly)
|
||||
errorLabel->set_text(N_("Please reasign levelpack to another group for group deletion"));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
but_edit = new StaticTextButton(N_("Compose Pack"), this);
|
||||
if (isPersistent && persIndex->isUpdatable() && persIndex->isCross()) {
|
||||
but_update = new StaticTextButton(N_("Update Pack"), this);
|
||||
} else {
|
||||
but_update = new Label();
|
||||
}
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_back = new StaticTextButton(N_("Ok"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
if (isReasignOnly) {
|
||||
commandHList->add_back(new Label());
|
||||
commandHList->add_back(new Label());
|
||||
} else {
|
||||
commandHList->add_back(but_edit);
|
||||
commandHList->add_back(but_update);
|
||||
}
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_back);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
updateLocationList();
|
||||
if (indexName.empty())
|
||||
// new levelpack
|
||||
switchToMetadataEdit();
|
||||
}
|
||||
|
||||
void LevelPackConfig::updateLocationList() {
|
||||
pre2Index->set_text((position > 1) ? locationList[position - 2] : "");
|
||||
pre1Index->set_text((position > 0) ? locationList[position - 1] : "");
|
||||
thisIndex->set_text(didEditMetaData ? titleTF->getText() : packIndex->getName());
|
||||
post1Index->set_text((position < locationList.size() - 1) ? locationList[position + 1] : "");
|
||||
post2Index->set_text((position < locationList.size() - 2) ? locationList[position + 2] : "");
|
||||
}
|
||||
|
||||
void LevelPackConfig::switchToMetadataEdit() {
|
||||
if (!didEditMetaData) {
|
||||
didEditMetaData = true;
|
||||
titleTF = new TextField(titleValueLabel->getText(), this);
|
||||
valueLeftVList->exchange_child(titleValueLabel, titleTF);
|
||||
delete titleValueLabel;
|
||||
ownerTF = new TextField(ownerValueLabel->getText());
|
||||
valueLeftVList->exchange_child(ownerValueLabel, ownerTF);
|
||||
delete ownerValueLabel;
|
||||
defLocationTF = new TextField(defLocationValueLabel->getText());
|
||||
valueMetaVList->exchange_child(defLocationValueLabel, defLocationTF);
|
||||
delete defLocationValueLabel;
|
||||
if (WizardMode) {
|
||||
releaseTF = new TextField(releaseValueLabel->getText());
|
||||
valueMetaVList->exchange_child(releaseValueLabel, releaseTF);
|
||||
delete releaseValueLabel;
|
||||
revisionTF = new TextField(revisionValueLabel->getText());
|
||||
valueMetaVList->exchange_child(revisionValueLabel, revisionTF);
|
||||
delete revisionValueLabel;
|
||||
compatibilityTF = new TextField(compatibilityValueLabel->getText());
|
||||
valueMetaVList->exchange_child(compatibilityValueLabel, compatibilityTF);
|
||||
delete compatibilityValueLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelPackConfig::isUndoQuit() {
|
||||
return undo_quit;
|
||||
}
|
||||
|
||||
bool LevelPackConfig::doChanges() {
|
||||
// change metadata
|
||||
if (didEditMetaData) {
|
||||
// the Index is persistent, user editabel and the user did switch to edit mode
|
||||
bool needSave = false;
|
||||
bool isNewIndex = persIndex->getName().empty();
|
||||
|
||||
// check for valid input
|
||||
// title
|
||||
std::string newtitle = titleTF->getText();
|
||||
std::string::size_type lastChar = newtitle.find_last_not_of(" ");
|
||||
if (lastChar == std::string::npos) {
|
||||
// the title is effectively an empty string
|
||||
errorLabel->set_text(N_("Error: empty title not allowed - press \"Undo\" to exit without modifications"));
|
||||
return false;
|
||||
}
|
||||
// strip off trailing and leading spaces
|
||||
newtitle = newtitle.substr(0 , lastChar + 1);
|
||||
newtitle = newtitle.substr(newtitle.find_first_not_of(" "));
|
||||
if (newtitle != persIndex->getName()) {
|
||||
if (isNewIndex) {
|
||||
// check for filename usability of title
|
||||
const std::string validChars("_- .#0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
if (newtitle.find_first_not_of(validChars, 0) != std::string::npos ||
|
||||
(newtitle.length() >= 1 && newtitle[0] == '.')) {
|
||||
errorLabel->set_text(N_("Error: use only \"a-zA-Z0-9 _-#\" for levelpack title"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// set packPath to cross if link only
|
||||
if (levelmode->isLinkOnly())
|
||||
persIndex->markNewAsCross();
|
||||
}
|
||||
if (!persIndex->setName(newtitle)) {
|
||||
errorLabel->set_text(N_("Error: title already in use - choose another title"));
|
||||
return false;
|
||||
}
|
||||
needSave = true;
|
||||
}
|
||||
|
||||
// check rest for need of save
|
||||
if (ownerTF->getText() != persIndex->getOwner()) {
|
||||
persIndex->setOwner(ownerTF->getText());
|
||||
needSave = true;
|
||||
}
|
||||
if (defLocationTF->getText() != ecl::strf("%g", packIndex->getDefaultLocation())) {
|
||||
double d = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(defLocationTF->getText().c_str(),"%lg", &d) == 1) &&
|
||||
d > 0) {
|
||||
packIndex->setDefaultLocation(d);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (WizardMode) {
|
||||
if (releaseTF->getText() != ecl::strf("%d", persIndex->getRelease())) {
|
||||
int i = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(releaseTF->getText().c_str(),"%d", &i) == 1) &&
|
||||
i > 0) {
|
||||
persIndex->setRelease(i);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
if (revisionTF->getText() != ecl::strf("%d", persIndex->getRevision())) {
|
||||
int i = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(revisionTF->getText().c_str(),"%d", &i) == 1) &&
|
||||
i > 0) {
|
||||
persIndex->setRevision(i);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
if (compatibilityTF->getText() != ecl::strf("%.2f", persIndex->getCompatibility())) {
|
||||
double d = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(compatibilityTF->getText().c_str(),"%lg", &d) == 1) &&
|
||||
d >= 1) {
|
||||
persIndex->setCompatibility(d);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save
|
||||
if (needSave)
|
||||
persIndex->save();
|
||||
if (isNewIndex) {
|
||||
lev::Index::registerIndex(persIndex);
|
||||
lev::Index::setCurrentIndex(persIndex->getName());
|
||||
}
|
||||
}
|
||||
// regroup
|
||||
if (groupButton->get_value() != intialGroupPosition) {
|
||||
std::string newGroupName = groupButton->get_text(groupButton->get_value());
|
||||
// strip off square brackets used to mark default and pseudo groups
|
||||
if (newGroupName.size() > 2 && newGroupName[0] == '[' &&
|
||||
newGroupName[newGroupName.size() -1] == ']') {
|
||||
newGroupName = newGroupName.substr(1, newGroupName.size() - 2);
|
||||
}
|
||||
packIndex->moveToGroup(newGroupName);
|
||||
} else if (isReasignOnly) {
|
||||
// the user did not reasign - take as an undo request
|
||||
undo_quit = true;
|
||||
}
|
||||
// relocate
|
||||
if (position != oldPosition)
|
||||
packIndex->locateBehind(position > 0 ? locationList[position - 1] : "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LevelPackConfig::on_action(Widget *w) {
|
||||
if (w == but_back) {
|
||||
if (doChanges())
|
||||
Menu::quit();
|
||||
else
|
||||
invalidate_all();
|
||||
} else if (w == but_ignore) {
|
||||
if (packIndex->getName().empty()) {
|
||||
delete packIndex;
|
||||
}
|
||||
undo_quit = true;
|
||||
Menu::quit();
|
||||
} else if (w == but_update) {
|
||||
if (isPersistent && doChanges()) {
|
||||
persIndex->load(false, true);
|
||||
persIndex->save(true);
|
||||
Menu::quit();
|
||||
}
|
||||
invalidate_all();
|
||||
} else if (w == but_edit) {
|
||||
if (doChanges()) {
|
||||
LevelPackComposer m(isEditable);
|
||||
m.manage();
|
||||
Menu::quit();
|
||||
} else {
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == scrollUp) {
|
||||
if (position > 0) {
|
||||
std::string tmp = locationList[position];
|
||||
locationList[position] = locationList[position - 1];
|
||||
locationList[position - 1] = tmp;
|
||||
position--;
|
||||
updateLocationList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == scrollDown) {
|
||||
if (position < locationList.size() - 1) {
|
||||
std::string tmp = locationList[position];
|
||||
locationList[position] = locationList[position + 1];
|
||||
locationList[position + 1] = tmp;
|
||||
position++;
|
||||
updateLocationList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == but_metadata && !didEditMetaData) {
|
||||
switchToMetadataEdit();
|
||||
invalidate_all();
|
||||
} else if (w == titleTF && w != NULL) {
|
||||
thisIndex->set_text(titleTF->getText());
|
||||
}
|
||||
}
|
||||
|
||||
void LevelPackConfig::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Level Pack Configuration"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
|
||||
}} // namespace enigma::gui
|
||||
112
project/jni/application/enigma/src/gui/LevelPackConfig.hh
Normal file
112
project/jni/application/enigma/src/gui/LevelPackConfig.hh
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LEVELPACKCONFIG_HH_INCLUDED
|
||||
#define GUI_LEVELPACKCONFIG_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/PersistentIndex.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class GroupButton : public ValueButton {
|
||||
public:
|
||||
GroupButton(std::vector<std::string> groups, int pos);
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
private:
|
||||
std::vector<std::string> groupNames;
|
||||
int position;
|
||||
};
|
||||
|
||||
class LevelmodeButton : public ImageButton {
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *);
|
||||
public:
|
||||
LevelmodeButton(bool initialMode = false);
|
||||
bool isLinkOnly();
|
||||
virtual void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
void update();
|
||||
bool mode;
|
||||
};
|
||||
|
||||
|
||||
class LevelPackConfig : public gui::Menu {
|
||||
public:
|
||||
LevelPackConfig (std::string indexName, std::string groupName = "",
|
||||
bool forceGroupReasign = false);
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
bool isUndoQuit();
|
||||
private:
|
||||
void updateLocationList();
|
||||
void switchToMetadataEdit();
|
||||
bool doChanges();
|
||||
|
||||
lev::Index *packIndex;
|
||||
lev::PersistentIndex *persIndex;
|
||||
bool isPersistent;
|
||||
bool isEditable;
|
||||
TextField *tf_packName;
|
||||
GroupButton *groupButton;
|
||||
int intialGroupPosition;
|
||||
VList *valueLeftVList;
|
||||
Label *titleValueLabel;
|
||||
TextField *titleTF;
|
||||
Label *ownerValueLabel;
|
||||
TextField *ownerTF;
|
||||
VList *valueMetaVList;
|
||||
LevelmodeButton *levelmode;
|
||||
Label *defLocationValueLabel;
|
||||
TextField *defLocationTF;
|
||||
Label *releaseValueLabel;
|
||||
TextField *releaseTF;
|
||||
Label *revisionValueLabel;
|
||||
TextField *revisionTF;
|
||||
Label *compatibilityValueLabel;
|
||||
TextField *compatibilityTF;
|
||||
Label *pre2Index;
|
||||
Label *pre1Index;
|
||||
Label *thisIndex;
|
||||
Label *post1Index;
|
||||
Label *post2Index;
|
||||
Widget *scrollUp;
|
||||
Widget *scrollDown;
|
||||
Label *errorLabel;
|
||||
Widget *but_metadata;
|
||||
Widget *but_up;
|
||||
Widget *but_down;
|
||||
Widget *but_edit;
|
||||
Widget *but_update;
|
||||
Widget *but_ignore;
|
||||
Widget *but_back;
|
||||
bool isReasignOnly;
|
||||
bool didEditMetaData;
|
||||
bool undo_quit;
|
||||
std::vector<std::string> locationList;
|
||||
int position; // new position of index in locationList that the user selected
|
||||
int oldPosition; // position of index when entering menu, -1 for new index
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
506
project/jni/application/enigma/src/gui/LevelPackMenu.cpp
Normal file
506
project/jni/application/enigma/src/gui/LevelPackMenu.cpp
Normal file
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* 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_new = new StaticTextButton(N_("New Group"), this);
|
||||
but_search = new StaticTextButton(N_("Search"), this);
|
||||
but_level = new StaticTextButton(N_("Start Game"), this);
|
||||
but_main = new StaticTextButton(N_("Main Menu"), this);
|
||||
|
||||
commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(but_new);
|
||||
commandHList->add_back(but_search);
|
||||
commandHList->add_back(but_level);
|
||||
commandHList->add_back(but_main);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
}
|
||||
|
||||
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, 9,
|
||||
15, 10,
|
||||
20, 36, 22, 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 * (35 + param[vm].vrow_row),
|
||||
param[vm].hscrollbutton, 35));
|
||||
}
|
||||
|
||||
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 * (35 + param[vm].vrow_row),
|
||||
param[vm].hscrollbutton, 35));
|
||||
}
|
||||
}
|
||||
|
||||
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_new) {
|
||||
LPGroupConfig m("");
|
||||
m.manage();
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} 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 == but_search) {
|
||||
SearchMenu ml;
|
||||
ml.manage();
|
||||
if (ml.isSearchQuit()) {
|
||||
// show search result levelpack
|
||||
LevelMenu ml;
|
||||
if (!ml.manage() && isLevelMenuSubmenu || ml.isMainQuit()) {
|
||||
// ESC in LevelMenu in cade 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
|
||||
87
project/jni/application/enigma/src/gui/LevelPackMenu.hh
Normal file
87
project/jni/application/enigma/src/gui/LevelPackMenu.hh
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELPACKMENU_HH_INCLUDED
|
||||
#define GUI_LEVELPACKMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelPackMenu -------------------- */
|
||||
|
||||
/**
|
||||
* The levelpack selection menu.
|
||||
*
|
||||
* The used strategy for horizontal scrolling of the levelpack columns
|
||||
* is to avoid scrolling as long as the target levelpack is still visible.
|
||||
* The current levelpack may be scrolled out of visibility by using the
|
||||
* scoll buttons within this menu. But if the user changes the current
|
||||
* levelpack via indirect methods besides
|
||||
* using the levelpack menu, f.e. the jumpto command, we ensure that
|
||||
* the new current levelpack is visible when the menu is redisplayed.
|
||||
* If it is necessary to scroll we scroll only the minimum amount of columns
|
||||
* needed to display the current levelpack. Even on screen resolution changes
|
||||
* we try to keep the column of the current levelpack unchanged.
|
||||
*/
|
||||
class LevelPackMenu : public Menu {
|
||||
public:
|
||||
LevelPackMenu();
|
||||
void manageLevelMenu();
|
||||
virtual bool manage();
|
||||
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
|
||||
private:
|
||||
static std::map<std::string, std::string> groupLastSelectedIndex;
|
||||
static std::map<std::string, int> groupLastSelectedColumn;
|
||||
static std::string lastGroupName;
|
||||
static int firstDisplayedGroup;
|
||||
|
||||
video::VideoModes vm;
|
||||
std::vector<TextButton *> packButtons;
|
||||
std::vector<TextButton *> groupButtons;
|
||||
|
||||
HList *packsHList;
|
||||
ImageButton *scrollLeft;
|
||||
ImageButton *scrollRight;
|
||||
ImageButton *scrollUp;
|
||||
ImageButton *scrollDown;
|
||||
VList *groupsVList;
|
||||
HList *commandHList;
|
||||
Widget *but_search;
|
||||
Widget *but_new;
|
||||
Widget *but_level;
|
||||
Widget *but_main;
|
||||
|
||||
bool isLevelMenuSubmenu;
|
||||
|
||||
void setupMenu();
|
||||
void updateHighlight();
|
||||
int getGroupPosition(std::vector<std::string> * groups, std::string groupName);
|
||||
int getIndexPosition(std::vector<lev::Index *> * group, std::string indexName);
|
||||
int checkColumn(int rows, int columns, int size, int position, int oldColumn);
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
178
project/jni/application/enigma/src/gui/LevelPreviewCache.cpp
Normal file
178
project/jni/application/enigma/src/gui/LevelPreviewCache.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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/LevelPreviewCache.hh"
|
||||
#include "ecl.hh"
|
||||
#include "file.hh"
|
||||
#include "game.hh"
|
||||
#include "main.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
#include "SDL.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelPreviewCache -------------------- */
|
||||
|
||||
LevelPreviewCache *LevelPreviewCache::theSingleton = 0;
|
||||
|
||||
LevelPreviewCache* LevelPreviewCache::instance() {
|
||||
if (theSingleton == 0) {
|
||||
theSingleton = new LevelPreviewCache();
|
||||
}
|
||||
return theSingleton;
|
||||
}
|
||||
|
||||
LevelPreviewCache::LevelPreviewCache() : cachedIndex (NULL) {
|
||||
}
|
||||
|
||||
void LevelPreviewCache::clear() {
|
||||
Log << "LevelPreviewCache clear\n";
|
||||
cache.clear();
|
||||
imgCache.clear();
|
||||
}
|
||||
|
||||
Surface *LevelPreviewCache::getPreview(lev::Proxy *levelProxy,
|
||||
bool allowGeneration, bool &didGenerate) {
|
||||
didGenerate = false;
|
||||
std::string mapIndex = levelProxy->getId() +
|
||||
ecl::strf("#%d", levelProxy->getReleaseVersion());
|
||||
// first look in cache
|
||||
PreviewMap::iterator i = cache.find(mapIndex);
|
||||
if (i != cache.end())
|
||||
return i->second;
|
||||
|
||||
// we have to cache a new preview - check if we should clear cache first
|
||||
if (cachedIndex == NULL) {
|
||||
// remember the index we are caching
|
||||
cachedIndex = lev::Index::getCurrentIndex();
|
||||
} else if (cachedIndex != lev::Index::getCurrentIndex()) {
|
||||
//the index changed - cache only previews from new index
|
||||
clear();
|
||||
cachedIndex = lev::Index::getCurrentIndex();
|
||||
}
|
||||
|
||||
std::string previewSubPath = makePreviewPath(levelProxy);
|
||||
Surface *surface = 0;
|
||||
|
||||
// load preview from file bundled with the level itself
|
||||
std::string absLevelPath ;
|
||||
std::auto_ptr<std::istream> isptr;
|
||||
ByteVec imageData;
|
||||
if(levelProxy->getNormPathType() == lev::Proxy::pt_resource &&
|
||||
app.resourceFS->findFile ("levels/" + levelProxy->getNormLevelPath() + ".png",
|
||||
absLevelPath, isptr)) {
|
||||
// load plain image file or zipped image
|
||||
if (isptr.get() != NULL) {
|
||||
// zipped file
|
||||
Readfile (*isptr, imageData);
|
||||
} else {
|
||||
// plain file
|
||||
basic_ifstream<char> ifs(absLevelPath.c_str(), ios::binary | ios::in);
|
||||
Readfile (ifs, imageData);
|
||||
}
|
||||
SDL_RWops *imageHandle = SDL_RWFromMem(&(imageData[0]), imageData.size());
|
||||
surface = ecl::LoadImage(imageHandle, 1);
|
||||
imgCache.store(previewSubPath, surface); // insert in imgCache
|
||||
}
|
||||
|
||||
// load preview from stored file if possible
|
||||
string previewFullPath;
|
||||
if (!surface && app.resourceFS->findFile(previewSubPath, previewFullPath))
|
||||
surface = imgCache.get(previewFullPath);
|
||||
|
||||
// generate new preview otherwise
|
||||
if (!surface && allowGeneration) {
|
||||
surface = newPreview(levelProxy);
|
||||
if (surface) {
|
||||
imgCache.store(previewSubPath, surface); // insert in imgCache
|
||||
savePreview(levelProxy, surface); // save on filesystem
|
||||
} else {
|
||||
surface = enigma::GetImage("error");
|
||||
}
|
||||
didGenerate = true;
|
||||
}
|
||||
|
||||
// update index
|
||||
if (surface)
|
||||
cache[mapIndex] = surface;
|
||||
return surface;
|
||||
}
|
||||
|
||||
ecl::Surface *LevelPreviewCache::newPreview (lev::Proxy *levelProxy) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
Surface *surface = 0;
|
||||
ecl::GC gc(video::BackBuffer());
|
||||
if (game::DrawLevelPreview (gc, levelProxy)) {
|
||||
surface = Resample (video::BackBuffer(),
|
||||
vminfo.gamearea, vminfo.thumbw, vminfo.thumbh);
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
Surface *LevelPreviewCache::updatePreview (lev::Proxy *levelProxy) {
|
||||
if (Surface *surface = newPreview (levelProxy)) {
|
||||
std::string idx = levelProxy->getId() +
|
||||
ecl::strf("#%d", levelProxy->getReleaseVersion());
|
||||
cache[idx] = surface;
|
||||
|
||||
string preview_name = makePreviewPath(levelProxy);
|
||||
imgCache.store (preview_name, surface); // insert in imgCache
|
||||
savePreview(levelProxy, surface); // save on filesystem
|
||||
return surface;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string LevelPreviewCache::makePreviewPath(lev::Proxy *levelProxy) {
|
||||
return "thumbs/" +
|
||||
levelProxy->getLocalSubstitutionLevelPath() +
|
||||
ecl::strf("#%d", levelProxy->getReleaseVersion()) + ".png";
|
||||
}
|
||||
|
||||
void LevelPreviewCache::savePreview(lev::Proxy *levelProxy, ecl::Surface *s) {
|
||||
std::string savePath = app.userImagePath + "/" + makePreviewPath(levelProxy);
|
||||
Log << "savePreview to " << savePath << "\n";
|
||||
// auto-create the directory if necessary
|
||||
string directory;
|
||||
if (ecl::split_path (savePath, &directory, 0) && !ecl::FolderExists(directory)) {
|
||||
ecl::FolderCreate (directory);
|
||||
}
|
||||
ecl::SavePNG(s, savePath);
|
||||
}
|
||||
|
||||
void LevelPreviewCache::makeSystemPreview(lev::Proxy *levelProxy, std::string systemDataPath) {
|
||||
std::string savePath = systemDataPath + "/levels/" + levelProxy->getNormLevelPath() + ".png";
|
||||
// auto-create the directory if necessary -- on an installed Enigma
|
||||
// distribution this is of course unnecessary, but you start Enigma
|
||||
// without prior installation. This is useful to get a directory with
|
||||
// just the previews.
|
||||
string directory;
|
||||
if (ecl::split_path (savePath, &directory, 0) && !ecl::FolderExists(directory)) {
|
||||
ecl::FolderCreate (directory);
|
||||
}
|
||||
ecl::Surface * s = newPreview(levelProxy);
|
||||
if (s != NULL)
|
||||
ecl::SavePNG(s, savePath);
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
91
project/jni/application/enigma/src/gui/LevelPreviewCache.hh
Normal file
91
project/jni/application/enigma/src/gui/LevelPreviewCache.hh
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELPREVIEWCACHE_HH_INCLUDED
|
||||
#define GUI_LEVELPREVIEWCACHE_HH_INCLUDED
|
||||
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include <map>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/**
|
||||
* A singleton manager for level previews with autocaching.
|
||||
* Clients just need to know the level proxy to request a preview.
|
||||
* <p>
|
||||
* Previews will be loaded from levelpack bundles if provided. These
|
||||
* preview files have the same name as the levels themself but the
|
||||
* suffix ".png". They just sit aside the levels in the same directory
|
||||
* or in the same zip archive. Only local stored previews will be looked
|
||||
* for.<p>
|
||||
* If no bundled preview exists the preview will be loaded from prior
|
||||
* generated and saved instances. Previews will be looked up at the
|
||||
* resourceFS with play time generated previews stored at the userImagePath
|
||||
* and installation time generated previews at the system path. The previews
|
||||
* will be stored at "data/thumbs" with a subpath that reflectes the level
|
||||
* subpath with critical characters replaced for url and other special levels.
|
||||
* The level release number is attached to the previewname as "#n" to allow
|
||||
* different previews for different releases to exist in parallel.<p>
|
||||
*
|
||||
* If no stored preview exists a new one will be generated by loading the
|
||||
* level. The preview will be stored to the userImagePath for future use.<p>
|
||||
*
|
||||
* All loaded previews will be autocached. Futher requests will be served
|
||||
* by the cache. The cache will be autocleared when a change in the
|
||||
* current Index is detected.<p>
|
||||
*
|
||||
* TODO remove unused preview on filesystem
|
||||
* TODO autogenerate previews on install
|
||||
*/
|
||||
class LevelPreviewCache {
|
||||
public:
|
||||
static LevelPreviewCache *instance();
|
||||
static void makeSystemPreview(lev::Proxy *levelProxy, std::string systemDataPath);
|
||||
~LevelPreviewCache();
|
||||
|
||||
ecl::Surface *getPreview (lev::Proxy *levelProxy,
|
||||
bool allowGeneration, bool &didGenerate);
|
||||
ecl::Surface *updatePreview (lev::Proxy *levelProxy);
|
||||
void clear();
|
||||
protected:
|
||||
LevelPreviewCache();
|
||||
private:
|
||||
static LevelPreviewCache *theSingleton;
|
||||
|
||||
/**
|
||||
* A mapping of "levelId+levelRelease" to preview surfaces
|
||||
*/
|
||||
typedef std::map<std::string, ecl::Surface*> PreviewMap;
|
||||
|
||||
// ---------- Internal methods ----------
|
||||
|
||||
static ecl::Surface *newPreview (lev::Proxy *levelProxy);
|
||||
std::string makePreviewPath(lev::Proxy *levelProxy);
|
||||
void savePreview(lev::Proxy *levelProxy, ecl::Surface *s);
|
||||
|
||||
// ---------- Variables ----------
|
||||
|
||||
PreviewMap cache; // a second mapping to avoid searched on the filesystem
|
||||
enigma::ImageCache imgCache; // the owner of the preview surfaces -
|
||||
// cannot be used as mapping as this cache
|
||||
// uses the filepath as index and autoloads
|
||||
// files on "get"-access
|
||||
lev::Index *cachedIndex; // the index that is currently cached
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
489
project/jni/application/enigma/src/gui/LevelWidget.cpp
Normal file
489
project/jni/application/enigma/src/gui/LevelWidget.cpp
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
* Copyright (C) 2006,2007 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/LevelWidget.hh"
|
||||
#include "gui/LevelMenu.hh"
|
||||
#include "gui/LevelInspector.hh"
|
||||
|
||||
#include "ecl.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "sound.hh"
|
||||
#include "StateManager.hh"
|
||||
#include "video.hh"
|
||||
#include "file.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include <cassert>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelWidget -------------------- */
|
||||
|
||||
LevelWidget::LevelWidget(bool withScoreIcons, bool withEditBorder) :
|
||||
displayScoreIcons (withScoreIcons), displayEditBorder (withEditBorder),
|
||||
width (0), height (0), m_areas(),
|
||||
listener(0), isInvalidateUptodate (true), lastUpdate (0)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
buttonw = vminfo.thumbw + 20;
|
||||
buttonh = vminfo.thumbh + 28;
|
||||
curIndex = lev::Index::getCurrentIndex();
|
||||
iselected = curIndex->getCurrentPosition();
|
||||
ifirst = curIndex->getScreenFirstPosition();
|
||||
preview_cache = LevelPreviewCache::instance();
|
||||
scoreMgr = lev::ScoreManager::instance();
|
||||
img_link = enigma::GetImage("ic-link");
|
||||
img_copy = enigma::GetImage("ic-copy");
|
||||
img_feather = enigma::GetImage("ic-feather");
|
||||
img_easy = enigma::GetImage("completed-easy");
|
||||
img_hard = enigma::GetImage("completed");
|
||||
img_changed = enigma::GetImage("changed");
|
||||
img_unavailable = enigma::GetImage("unavailable");
|
||||
// img_unknown = enigma::GetImage("unknown");
|
||||
img_par = enigma::GetImage("par");
|
||||
img_wrEasy = enigma::GetImage("ic-wr-easy");
|
||||
img_wrDifficult = enigma::GetImage("ic-wr-difficult");
|
||||
img_border = enigma::GetImage("thumbborder");
|
||||
img_editborder = enigma::GetImage("editborder");
|
||||
}
|
||||
|
||||
void LevelWidget::syncFromIndexMgr() {
|
||||
if (curIndex != lev::Index::getCurrentIndex()) {
|
||||
curIndex = lev::Index::getCurrentIndex();
|
||||
iselected = curIndex->getCurrentPosition();
|
||||
ifirst = curIndex->getScreenFirstPosition();
|
||||
invalidate();
|
||||
sound::EmitSoundEvent ("menumove");
|
||||
} else if (iselected != curIndex->getCurrentPosition()) {
|
||||
sound::EmitSoundEvent ("menumove");
|
||||
}
|
||||
// repair ifirst on boot and screen resolution changes
|
||||
set_selected(curIndex->getScreenFirstPosition(),
|
||||
curIndex->getCurrentPosition());
|
||||
}
|
||||
|
||||
void LevelWidget::syncToIndexMgr() {
|
||||
curIndex->setCurrentPosition(iselected);
|
||||
curIndex->setScreenFirstPosition(ifirst);
|
||||
}
|
||||
|
||||
void LevelWidget::realize (const ecl::Rect &area_)
|
||||
{
|
||||
Widget::realize (area_);
|
||||
width = area_.w / buttonw;
|
||||
height = area_.h / buttonh;
|
||||
}
|
||||
|
||||
void LevelWidget::trigger_action() {
|
||||
if (listener) {
|
||||
listener->on_action(this);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelWidget::scroll_up (int nlines)
|
||||
{
|
||||
int newFirst = ifirst;
|
||||
int newSelected = iselected;
|
||||
for (; nlines; --nlines) {
|
||||
if (newFirst+width*height >= curIndex->size())
|
||||
break;
|
||||
newFirst += width;
|
||||
if (newSelected < newFirst)
|
||||
newSelected += width;
|
||||
}
|
||||
set_selected (newFirst, newSelected);
|
||||
}
|
||||
|
||||
void LevelWidget::scroll_down(int nlines)
|
||||
{
|
||||
int newFirst = ifirst;
|
||||
int newSelected = iselected;
|
||||
for (; nlines; --nlines) {
|
||||
if (newFirst == 0) {
|
||||
break;
|
||||
} else if (newFirst < width) {
|
||||
newFirst = 0;
|
||||
if (newSelected >= width*height)
|
||||
newSelected = width*height - 1;
|
||||
} else {
|
||||
newFirst -= width;
|
||||
if (newSelected >= newFirst+width*height)
|
||||
newSelected -= width;
|
||||
}
|
||||
}
|
||||
set_selected (newFirst, newSelected);
|
||||
}
|
||||
|
||||
void LevelWidget::page_up() {
|
||||
set_selected ((ifirst >= width*height ? ifirst - width*height : 0),
|
||||
(iselected >= width*height ? iselected - width*height : 0));
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::page_down()
|
||||
{
|
||||
int s = lev::Index::getCurrentIndex()->size() - 1; // last position
|
||||
int lastPageFirst = (s >= width*height ? (s / width - height + 1) * width : 0);
|
||||
|
||||
// make sure last page is shown as a whole
|
||||
int first = std::min<int> (lastPageFirst, ifirst + width*height);
|
||||
// set_selected (first, s-1);
|
||||
set_selected (first, iselected + width*height);
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::start() {
|
||||
set_selected(0,0);
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::end() {
|
||||
int s = lev::Index::getCurrentIndex()->size() - 1; // last position
|
||||
int lastPageFirst = (s >= width*height ? (s / width - height + 1) * width : 0);
|
||||
set_selected(lastPageFirst, s);
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::set_current (int newsel)
|
||||
{
|
||||
set_selected (ifirst, newsel);
|
||||
}
|
||||
|
||||
void LevelWidget::set_selected (int newfirst, int newsel)
|
||||
{
|
||||
int numlevels = curIndex->size();
|
||||
newsel = Clamp<int> (newsel, 0, numlevels-1);
|
||||
if (newsel < 0) newsel = 0;
|
||||
|
||||
if (newsel < newfirst)
|
||||
newfirst = (newsel/width)*width;
|
||||
if (newsel >= newfirst+width*height)
|
||||
newfirst = (newsel/width-height+1)*width;
|
||||
|
||||
newfirst = Clamp<int> (newfirst, 0, numlevels-1);
|
||||
if (newfirst < 0) newfirst = 0;
|
||||
|
||||
size_t oldsel = iselected;
|
||||
if (newfirst != ifirst) {
|
||||
ifirst = newfirst;
|
||||
iselected = newsel;
|
||||
|
||||
if (!m_areas.empty()) {
|
||||
sound::EmitSoundEvent ("menumove");
|
||||
if (oldsel != newsel)
|
||||
sound::EmitSoundEvent ("menuswitch");
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
else if (newsel != iselected) {
|
||||
iselected = newsel;
|
||||
|
||||
if (!m_areas.empty()) {
|
||||
sound::EmitSoundEvent ("menuswitch");
|
||||
invalidate_area(m_areas[oldsel-ifirst]); // old selection
|
||||
invalidate_area(m_areas[iselected-ifirst]); // new selection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelWidget::draw_level_preview (ecl::GC &gc, int x, int y,
|
||||
lev::Proxy *proxy, bool selected, bool isCross, bool locked,
|
||||
bool allowGeneration, bool &didGenerate) {
|
||||
// Draw button with level preview
|
||||
|
||||
Surface *img = preview_cache->getPreview(proxy, allowGeneration, didGenerate);
|
||||
if (img == NULL)
|
||||
return false;
|
||||
|
||||
if (selected) {
|
||||
blit (gc, x-4, y-4, displayEditBorder ? img_editborder : img_border);
|
||||
blit (gc, x, y, img);
|
||||
}
|
||||
else {
|
||||
img->set_alpha (127);
|
||||
blit (gc, x, y, img);
|
||||
img->set_alpha(255);
|
||||
}
|
||||
|
||||
// Shade unavailable levels
|
||||
if (locked)
|
||||
blit (gc, x, y, img_unavailable);
|
||||
|
||||
if (displayScoreIcons) {
|
||||
// Draw solved/changed icons on top of level preview
|
||||
// Easy/difficult mode and solved status:
|
||||
// None: Level not beaten - no easy mode available
|
||||
// Feather: Level not beaten - easy mode available
|
||||
// Feather + Gold: Level beaten in normal mode - easy available
|
||||
// Silver: Level beaten in easy mode (normal mode available)
|
||||
// Gold: Level beaten in normal mode - easy not availabe
|
||||
// Silver + Gold: Level beaten in all modes - easy available
|
||||
Surface *useAsEasy = NULL;
|
||||
Surface *useAsDifficult = NULL;
|
||||
if (proxy->hasEasymode()) {
|
||||
useAsEasy = img_feather;
|
||||
if (scoreMgr->isSolved(proxy, DIFFICULTY_EASY))
|
||||
useAsEasy = img_easy;
|
||||
}
|
||||
if (scoreMgr->isSolved(proxy, DIFFICULTY_HARD))
|
||||
useAsDifficult = img_hard;
|
||||
|
||||
if (app.state->getInt("Difficulty") == DIFFICULTY_HARD) {
|
||||
// draw golden medal over silber medal
|
||||
if (useAsEasy != NULL)
|
||||
blit (gc, x, y, useAsEasy);
|
||||
if (useAsDifficult != NULL)
|
||||
blit (gc, x+5, y, useAsDifficult);
|
||||
}
|
||||
else {
|
||||
// draw silver medal over golden medal
|
||||
if (useAsDifficult != NULL)
|
||||
blit (gc, x+5, y, useAsDifficult);
|
||||
if (useAsEasy != NULL)
|
||||
blit (gc, x, y, useAsEasy);
|
||||
}
|
||||
|
||||
// Add warning sign if level has been changed since player solved it
|
||||
if (scoreMgr->isOutdated(proxy, app.state->getInt("Difficulty")))
|
||||
blit (gc, x-3, y-3, img_changed);
|
||||
|
||||
// Add icon if worldrecord or par
|
||||
if (scoreMgr->bestScoreReached(proxy, app.state->getInt("Difficulty"))) {
|
||||
blit(gc, x+35, y+5,
|
||||
(app.state->getInt("Difficulty") != DIFFICULTY_HARD &&
|
||||
proxy->hasEasymode()) ? img_wrEasy : img_wrDifficult);
|
||||
} else if (scoreMgr->parScoreReached(proxy, app.state->getInt("Difficulty"))){
|
||||
blit(gc, x+30, y+12, img_par);
|
||||
}
|
||||
} else {
|
||||
// Draw solved/changed icons on top of level preview
|
||||
if (isCross)
|
||||
blit (gc, x+4, y+4, img_link);
|
||||
else
|
||||
blit (gc, x+4, y+4, img_copy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LevelWidget::draw (ecl::GC &gc, const ecl::Rect &r)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
const int imgw = vminfo.thumbw; // Size of the preview images
|
||||
const int imgh = vminfo.thumbh;
|
||||
|
||||
const int hgap = Max(0, (get_w() - width*buttonw) / (width));
|
||||
const int vgap = Max(0, (get_h() - height*buttonh)/ (height-1));
|
||||
|
||||
unsigned i=ifirst; // level index
|
||||
bool allowGeneration = true;
|
||||
|
||||
for (int y=0; y<height; y++)
|
||||
{
|
||||
for (int x=0; x<width; x++, i++)
|
||||
{
|
||||
if (i >= curIndex->size())
|
||||
goto done_painting;
|
||||
|
||||
int xpos = get_x() + hgap/2 + x*(buttonw + hgap);
|
||||
int ypos = get_y() + y*(buttonh + vgap);
|
||||
|
||||
Rect buttonarea(xpos, ypos, buttonw, buttonh);
|
||||
if (!(r.overlaps(buttonarea) || r.w == 0))
|
||||
continue; // r.w==0 if repainting whole screen
|
||||
|
||||
if( (i-ifirst) >= m_areas.size()) {
|
||||
m_areas.push_back(buttonarea);
|
||||
pending_redraws.push_back(false);
|
||||
} else {
|
||||
m_areas[(i-ifirst)] = buttonarea;
|
||||
}
|
||||
// Draw level preview
|
||||
lev::Proxy *levelProxy = curIndex->getProxy(i);
|
||||
int imgx = xpos+(buttonw-imgw)/2;
|
||||
int imgy = ypos + 4;
|
||||
if (levelProxy != NULL) {
|
||||
bool didGenerate;
|
||||
bool didDraw = draw_level_preview (gc, imgx, imgy, levelProxy,
|
||||
i == iselected, !curIndex->isSource(levelProxy),
|
||||
!curIndex->mayPlayLevel(i+1),
|
||||
allowGeneration, didGenerate);
|
||||
if (didGenerate) {
|
||||
// do not generate more than 1 preview from level source
|
||||
// per draw call
|
||||
allowGeneration = false;
|
||||
}
|
||||
if (didDraw) {
|
||||
pending_redraws[(i-ifirst)] = false;
|
||||
} else {
|
||||
// the button is not drawn - mark it to be drawn on
|
||||
// a future tick
|
||||
pending_redraws[(i-ifirst)] = true;
|
||||
isInvalidateUptodate = false;
|
||||
}
|
||||
}
|
||||
// Draw level name
|
||||
Font *smallfnt = enigma::GetFont("levelmenu");
|
||||
Font *altsmallfnt = enigma::GetFont("smallalternative");;
|
||||
std::string caption = levelProxy->getTitle();
|
||||
smallfnt->render (gc,
|
||||
xpos + buttonw/2 - ecl::Min(smallfnt->get_width(caption.c_str(), altsmallfnt)/2, (buttonw+hgap)/2),
|
||||
imgy + imgh + 2,
|
||||
caption, altsmallfnt, buttonw + hgap);
|
||||
}
|
||||
}
|
||||
done_painting:
|
||||
m_areas.resize (i-ifirst); // Remove unused areas (if any) from the list
|
||||
return;
|
||||
}
|
||||
|
||||
void LevelWidget::tick (double time) {
|
||||
if (!isInvalidateUptodate) {
|
||||
// invalidate just 1 button for redraw
|
||||
bool isFirst = true;
|
||||
for (int i = 0; i < pending_redraws.size(); i++) {
|
||||
if (pending_redraws[i] == true) {
|
||||
if (isFirst) {
|
||||
invalidate_area(m_areas[i]);
|
||||
isInvalidateUptodate = true;
|
||||
isFirst = false;
|
||||
} else {
|
||||
isInvalidateUptodate = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelWidget::on_event(const SDL_Event &e)
|
||||
{
|
||||
bool handled = Widget::on_event(e);
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
if (get_area().contains(e.motion.x, e.motion.y)) {
|
||||
int newsel=iselected;
|
||||
for (unsigned i=0; i<m_areas.size(); ++i)
|
||||
if (m_areas[i].contains(e.motion.x, e.motion.y))
|
||||
{
|
||||
newsel = ifirst+i;
|
||||
break;
|
||||
}
|
||||
set_current(newsel);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (get_area().contains(e.button.x, e.button.y))
|
||||
handled = handle_mousedown (&e);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
handled = handle_keydown (&e);
|
||||
break;
|
||||
}
|
||||
syncToIndexMgr();
|
||||
return handled;
|
||||
}
|
||||
|
||||
bool LevelWidget::handle_mousedown (const SDL_Event *e)
|
||||
{
|
||||
switch (e->button.button) {
|
||||
case SDL_BUTTON_LEFT:
|
||||
for (unsigned i=0; i<m_areas.size(); ++i)
|
||||
if (m_areas[i].contains(e->button.x, e->button.y))
|
||||
{
|
||||
sound::EmitSoundEvent ("menuok");
|
||||
iselected = ifirst+i;
|
||||
syncToIndexMgr();
|
||||
if (SDL_GetModState() & KMOD_CTRL && !(SDL_GetModState() & KMOD_SHIFT)) {
|
||||
// control key pressed - level inspector
|
||||
LevelInspector m(curIndex->getProxy(iselected));
|
||||
m.manage();
|
||||
get_parent()->draw_all();
|
||||
} else {
|
||||
// no control key - start level
|
||||
trigger_action();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
for (unsigned i=0; i<m_areas.size(); ++i)
|
||||
if (m_areas[i].contains(e->button.x, e->button.y))
|
||||
{
|
||||
sound::EmitSoundEvent ("menuok");
|
||||
iselected = ifirst+i;
|
||||
syncToIndexMgr();
|
||||
LevelInspector m(curIndex->getProxy(iselected));
|
||||
m.manage();
|
||||
get_parent()->draw_all();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 4: scroll_down(1); return true;
|
||||
case 5: scroll_up(1); return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LevelWidget::handle_keydown (const SDL_Event *e)
|
||||
{
|
||||
switch (e->key.keysym.sym) {
|
||||
|
||||
case SDLK_t:
|
||||
// Generate new level preview for current level
|
||||
preview_cache->updatePreview(curIndex->getProxy(iselected));
|
||||
invalidate();
|
||||
break;
|
||||
|
||||
case SDLK_LEFT:
|
||||
if (!(SDL_GetModState() & KMOD_ALT)) {
|
||||
set_current (iselected>1 ? iselected-1 : 0);
|
||||
break;
|
||||
} else
|
||||
return false;
|
||||
case SDLK_RIGHT:
|
||||
if (!(SDL_GetModState() & KMOD_ALT)) {
|
||||
set_current (iselected+1);
|
||||
break;
|
||||
} else
|
||||
return false;
|
||||
case SDLK_DOWN: set_current (iselected+width); break;
|
||||
case SDLK_UP: set_current (iselected>width ? iselected-width : 0); break;
|
||||
case SDLK_PAGEDOWN: page_down(); break;
|
||||
case SDLK_PAGEUP: page_up(); break;
|
||||
case SDLK_HOME: start(); break;
|
||||
case SDLK_END: end(); break;
|
||||
|
||||
case SDLK_RETURN:
|
||||
trigger_action();
|
||||
break;
|
||||
|
||||
default:
|
||||
return false; // key not handled
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
111
project/jni/application/enigma/src/gui/LevelWidget.hh
Normal file
111
project/jni/application/enigma/src/gui/LevelWidget.hh
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELWIDGET_HH_INCLUDED
|
||||
#define GUI_LEVELWIDGET_HH_INCLUDED
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
#include "gui/LevelPreviewCache.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelWidget -------------------- */
|
||||
|
||||
class LevelMenu;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class LevelWidget : public Widget {
|
||||
public:
|
||||
LevelWidget(bool withScoreIcons = true, bool withEditBorder = false);
|
||||
|
||||
//---------- Widget interface ----------//
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
void tick (double time);
|
||||
|
||||
void set_listener(ActionListener *al) {
|
||||
listener = al;
|
||||
}
|
||||
void trigger_action();
|
||||
|
||||
virtual void realize (const ecl::Rect &r);
|
||||
|
||||
//---------- Cursor motion ----------//
|
||||
|
||||
void page_up();
|
||||
void page_down();
|
||||
void start();
|
||||
void end();
|
||||
|
||||
bool on_event(const SDL_Event &e);
|
||||
void syncFromIndexMgr(); // external change of currentIndex, currentLevel
|
||||
|
||||
private:
|
||||
//---------- Private functions ----------//
|
||||
void syncToIndexMgr();
|
||||
void set_current (int newsel);
|
||||
void scroll_up(int lines);
|
||||
void scroll_down(int lines);
|
||||
void set_selected (int newfirst, int newsel);
|
||||
bool draw_level_preview (ecl::GC &gc, int x, int y,
|
||||
lev::Proxy *proxy, bool selected, bool isCross, bool locked,
|
||||
bool allowGeneration, bool &didGenerate);
|
||||
|
||||
bool handle_keydown (const SDL_Event *e);
|
||||
bool handle_mousedown (const SDL_Event *e);
|
||||
|
||||
//---------- Variables ----------//
|
||||
bool displayScoreIcons;
|
||||
bool displayEditBorder;
|
||||
LevelPreviewCache *preview_cache;
|
||||
lev::ScoreManager *scoreMgr;
|
||||
lev::Index *curIndex;
|
||||
ActionListener *listener;
|
||||
|
||||
int ifirst; // Index of "upper left" level
|
||||
int iselected; // Index of selected level
|
||||
int width; // number of buttons in a row
|
||||
int height; // number of buttons in a column
|
||||
int buttonw; // pixelwidth of a button
|
||||
int buttonh; // pixelheight of a button
|
||||
std::vector<ecl::Rect> m_areas; // Screen areas occupied by level previews
|
||||
std::vector<bool> pending_redraws;
|
||||
bool isInvalidateUptodate;
|
||||
double lastUpdate;
|
||||
|
||||
// some image pointers for efficiency
|
||||
ecl::Surface *img_link;
|
||||
ecl::Surface *img_copy;
|
||||
ecl::Surface *img_feather;
|
||||
ecl::Surface *img_easy;
|
||||
ecl::Surface *img_hard;
|
||||
ecl::Surface *img_changed;
|
||||
ecl::Surface *img_unavailable;
|
||||
// Surface *img_unknown;
|
||||
ecl::Surface *img_par;
|
||||
ecl::Surface *img_wrEasy;
|
||||
ecl::Surface *img_wrDifficult;
|
||||
ecl::Surface *img_border;
|
||||
ecl::Surface *img_editborder;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
392
project/jni/application/enigma/src/gui/MainMenu.cpp
Normal file
392
project/jni/application/enigma/src/gui/MainMenu.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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/MainMenu.hh"
|
||||
#include "gui/LevelMenu.hh"
|
||||
#include "gui/OptionsMenu.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "gui/InfoMenu.hh"
|
||||
#include "gui/LevelPackMenu.hh"
|
||||
#include "gui/LevelPreviewCache.hh"
|
||||
#include "display.hh"
|
||||
#include "ecl.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "world.hh"
|
||||
|
||||
#include "netgame.hh"
|
||||
#include "editor.hh"
|
||||
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Helper routines -------------------- */
|
||||
|
||||
// namespace
|
||||
// {
|
||||
/*! Change the video mode. Because this opens a new screen with a
|
||||
new resolution, the display engine must be re-initialized to
|
||||
load the appropriate models. */
|
||||
void ChangeVideoMode()
|
||||
{
|
||||
world::PrepareLevel(); // make sure no references to models remain
|
||||
video::ChangeVideoMode();
|
||||
LevelPreviewCache::instance()->clear();
|
||||
enigma::ClearImageCache();
|
||||
display::Shutdown();
|
||||
display::Init();
|
||||
}
|
||||
// }
|
||||
|
||||
|
||||
/* -------------------- NetworkMenu -------------------- */
|
||||
|
||||
NetworkMenu::NetworkMenu ()
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
BuildVList b(this, Rect((vminfo->width - 150)/2,150,150,40), 5);
|
||||
m_startgame = b.add(new StaticTextButton(N_("Start Game"), this));
|
||||
m_joingame = b.add(new StaticTextButton(N_("Join Game"), this));
|
||||
m_back = b.add(new StaticTextButton(N_("Back"), this));
|
||||
}
|
||||
|
||||
NetworkMenu::~NetworkMenu ()
|
||||
{
|
||||
}
|
||||
|
||||
bool NetworkMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkMenu::on_action(gui::Widget *w)
|
||||
{
|
||||
if (w == m_startgame) {
|
||||
netgame::Start();
|
||||
}
|
||||
else if (w == m_joingame) {
|
||||
netgame::Join("localhost", 12345);
|
||||
}
|
||||
if (w == m_back)
|
||||
Menu::quit();
|
||||
}
|
||||
|
||||
void NetworkMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
video::SetCaption (("Enigma - Network Menu"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
void NetworkMenu::tick(double dtime)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Main menu -------------------- */
|
||||
static const char *credit_text[] = {
|
||||
N_("Main developers of the 1.0 release:"),
|
||||
N_(" RONALD LAMPRECHT (lead)"),
|
||||
" RAOUL BOURQUIN",
|
||||
" ANDREAS LOCHMANN",
|
||||
" ",
|
||||
N_("Special Thanks To:"),
|
||||
N_(" DANIEL HECK (project founder)"),
|
||||
N_(" MEINOLF SCHNEIDER (game idea, level design)"),
|
||||
" ",
|
||||
N_("Please refer to the manual or the next pages for full credits."),
|
||||
" ",
|
||||
N_("Home Page: http://www.nongnu.org/enigma"),
|
||||
N_("Contact: enigma-devel@nongnu.org"),
|
||||
" ",
|
||||
N_("Enigma is free software and may be distributed under the"),
|
||||
N_("terms of the GNU General Public License, version 2."),
|
||||
" ",
|
||||
N_("Copyright (C) 2002-2007 Daniel Heck and contributors."),
|
||||
0,
|
||||
N_("Main developer of all releases:"),
|
||||
" ",
|
||||
" Raoul Bourquin (Level admin. & design, all over invaluable additions)",
|
||||
" Siegfried Fennig (Level design, graphics)",
|
||||
" Martin Hawlisch (Level design, graphics, programming)",
|
||||
" Daniel Heck (Main developer, graphics, documentation)",
|
||||
" Ronald Lamprecht (XML, Gui, portability, core prog., documentation)",
|
||||
" Andreas Lochmann (Programming, level admin. & design, documentation)",
|
||||
" Petr Machata (Level design, programming)",
|
||||
" Nat Pryce (Level design)",
|
||||
" Jacob Scott (Level design)",
|
||||
" Sven Siggelkow (Level design and special Oxyd expertise)",
|
||||
" Ralf Westram (Programming, level design)",
|
||||
0,
|
||||
N_("Special Thanks:"),
|
||||
" Johannes Fortmann (Mac OS X port, some programming, graphics)",
|
||||
" illmind (Forum mag-heut.net administration, Level design)",
|
||||
// waiting for licence to add the sounds
|
||||
// " \'Cellar of Rats\' (Sound effects)",
|
||||
" Jennifer Robertson (Graphics second generation)",
|
||||
" Jeremy Sawicki (Oxydlib)",
|
||||
" Erich Schubert (Debian/Ubuntu packages, level design)",
|
||||
" Lukas Schüller (Level design)",
|
||||
" Andrew \'Necros\' Sega (Menu music \'Pentagonal Dreams\')",
|
||||
" David W. Skinner (Many Sokoban Levels)",
|
||||
" Clifford J. Tasner (Music second generation, Proof reading)",
|
||||
0,
|
||||
N_("Contributors:"),
|
||||
" Roberto Bardin (Level design)",
|
||||
" Alain Busser (Level design, French translation, manual)",
|
||||
" Guy Busser (Level design)",
|
||||
" Richi Bützer (Level design)",
|
||||
" Capkoh (Level design)",
|
||||
" Christoph & Anita (Level design)",
|
||||
" Дремук Сергей - Serge Dremuk (Russian translation)",
|
||||
" Joseph Dunne (Level design)",
|
||||
" Xerxes M. Dynatos (Level design)",
|
||||
" Edward (Level design)",
|
||||
" Stephanie Fabian (Invaluable bug reports)",
|
||||
" Roberto García (Spanish translation)",
|
||||
" Andy Geldmacher (Level design)",
|
||||
" Edwin Groothuis (FreeBSD port)",
|
||||
" Immanuel Herrmann (Level design)",
|
||||
" Máté Lehel Juhász (Hungarian translation)",
|
||||
0,
|
||||
" Samuele Kaplun (Italian translation)",
|
||||
" Jens-Christian Korth (Level design)",
|
||||
" Manuel König (Level design, bug reports)",
|
||||
" Johannes Laire (Level design)",
|
||||
" Joona Laire (Level design)",
|
||||
" Markus Laire (Level design)",
|
||||
" Dominik Lehmann (Level design)",
|
||||
" Edward Leuf (Feedback, bug reports)",
|
||||
" Ingo van Lil (Feedback, bug reports)",
|
||||
" Frank van der Loo (Dutch translation)",
|
||||
" Sidney Markowitz (Mac OS X port)",
|
||||
" Barry & Lori Mead (Level design)",
|
||||
" Linda Mihalic (English proof reading)",
|
||||
" moonpearl (Level design)",
|
||||
" Krishnamurti L.L.V. Nunes (Portuguese translation)",
|
||||
" Daniel Nylander (Swedish translation)",
|
||||
0,
|
||||
" Andreas Persenius (Level design)",
|
||||
" Peter Santo (Level design)",
|
||||
" Tobias Schmidbauer (Windows installer and icon)",
|
||||
" Achim Settelmeier (RPM specfile)",
|
||||
" Jon Sneyers (Level design)",
|
||||
" Spaceman (Level design)",
|
||||
" Ulf Stegemann (Level design)",
|
||||
" Jürgen Sticht (Level design)",
|
||||
" Mikke Surakka (Finnish translation)",
|
||||
" Andrzej Szombierski (Level design)",
|
||||
" Tacvek (Lua 5.1 upgrade)",
|
||||
" Michael Terry (.desktop file)",
|
||||
" Ray Wick (Level design)",
|
||||
" Joe Wreschnig (Manual page)",
|
||||
" Юрий Жиромский - Yuriy Zhyromskiy (Russian Manual)",
|
||||
0,
|
||||
};
|
||||
|
||||
MainMenu::MainMenu()
|
||||
{
|
||||
build_menu();
|
||||
}
|
||||
|
||||
void MainMenu::build_menu()
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
BuildVList b(this, Rect((vminfo->width - 150)/2,150,150,40), 5);
|
||||
m_startgame = b.add(new StaticTextButton(N_("Start Game"), this));
|
||||
m_levelpack = b.add(new StaticTextButton(N_("Level Pack"), this));
|
||||
#ifdef ENABLE_EXPERIMENTAL
|
||||
m_netgame = b.add (new StaticTextButton (N_("Network Game"), this));
|
||||
leveled = b.add(new StaticTextButton(N_("Editor"), this));
|
||||
#endif
|
||||
options = b.add(new StaticTextButton(N_("Options"), this));
|
||||
credits = b.add(new StaticTextButton(N_("Credits"), this));
|
||||
quit = b.add(new StaticTextButton(N_("Quit"), this));
|
||||
}
|
||||
|
||||
void MainMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
video::SetCaption (("Enigma - Main Menu"));
|
||||
sound::PlayMusic (options::GetString("MenuMusicFile"));
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
|
||||
Font *f = enigma::GetFont("levelmenu");
|
||||
Surface * logo(enigma::GetImage("enigma_logo3"));
|
||||
int x0=(vminfo->width - logo->width())/2;
|
||||
int y0=30;
|
||||
blit(gc, x0, y0, logo);
|
||||
f->render (gc, 5, vminfo->height - 20, app.getVersionInfo().c_str());
|
||||
}
|
||||
|
||||
bool MainMenu::on_event (const SDL_Event &e) {
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
SDLKey keysym = e.key.keysym.sym;
|
||||
switch (keysym) {
|
||||
case SDLK_F2:
|
||||
show_paths();
|
||||
invalidate_all();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainMenu::on_action(Widget *w)
|
||||
{
|
||||
if (w == m_startgame) {
|
||||
LevelPackMenu m;
|
||||
m.manageLevelMenu();
|
||||
invalidate_all();
|
||||
} else if (w == m_levelpack) {
|
||||
LevelPackMenu m;
|
||||
m.manage();
|
||||
invalidate_all();
|
||||
} else if (w == credits) {
|
||||
displayInfo(credit_text, 6);
|
||||
invalidate_all();
|
||||
} else if (w == options) {
|
||||
ShowOptionsMenu(0);
|
||||
|
||||
#ifdef ENABLE_EXPERIMENTAL
|
||||
} else if (w == m_netgame) {
|
||||
ShowNetworkMenu();
|
||||
} else if (w == leveled) {
|
||||
editor::Run();
|
||||
#endif
|
||||
} else if (w == quit) {
|
||||
Menu::quit();
|
||||
} else
|
||||
return;
|
||||
invalidate_all();
|
||||
}
|
||||
|
||||
void MainMenu::tick(double /* dtime */)
|
||||
{
|
||||
bool option_fullscreen = options::GetInt ("FullScreen") != 0;
|
||||
if (options::GetInt ("VideoMode") != video::GetVideoMode()
|
||||
|| option_fullscreen != video::IsFullScreen())
|
||||
{
|
||||
ChangeVideoMode();
|
||||
clear();
|
||||
reset_active_widget ();
|
||||
build_menu();
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
void MainMenu::show_paths() {
|
||||
const char *pathtext[25];
|
||||
std::string pathstrings[25];
|
||||
std::string work;
|
||||
Font *menufont = enigma::GetFont("menufont");
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
int width = vminfo->width - 80;
|
||||
int i = 0;
|
||||
|
||||
pathtext[i++] = N_("Preferences Path:");
|
||||
work = app.prefPath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("User Path:");
|
||||
work = app.userPath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("User Image Path:");
|
||||
work = app.userImagePath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("System Path:");
|
||||
work = app.systemFS->getDataPath();
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("Resource Paths:");
|
||||
work = app.resourceFS->getDataPath();
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("L10n Path:");
|
||||
work = app.l10nPath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = 0;
|
||||
displayInfo(pathtext, 1);
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void ShowMainMenu() {
|
||||
MainMenu m;
|
||||
m.manage();
|
||||
}
|
||||
|
||||
void ShowNetworkMenu()
|
||||
{
|
||||
NetworkMenu m;
|
||||
m.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
83
project/jni/application/enigma/src/gui/MainMenu.hh
Normal file
83
project/jni/application/enigma/src/gui/MainMenu.hh
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_MAINMENU_HH_INCLUDED
|
||||
#define GUI_MAINMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- MainMenu -------------------- */
|
||||
|
||||
class MainMenu : public Menu {
|
||||
public:
|
||||
MainMenu();
|
||||
private:
|
||||
// Menu interface
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
// Widget interface
|
||||
virtual bool on_event(const SDL_Event &e);
|
||||
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *w);
|
||||
|
||||
// Private methods.
|
||||
void show_paths();
|
||||
void build_menu();
|
||||
|
||||
// Variables.
|
||||
Widget *m_startgame;
|
||||
Widget *m_levelpack;
|
||||
Widget *m_netgame;
|
||||
Widget *leveled;
|
||||
Widget *manual;
|
||||
Widget *options;
|
||||
Widget *credits;
|
||||
Widget *quit;
|
||||
Widget *lpack;
|
||||
};
|
||||
|
||||
/* -------------------- NetworkMenu -------------------- */
|
||||
|
||||
class NetworkMenu : public gui::Menu {
|
||||
public:
|
||||
NetworkMenu ();
|
||||
~NetworkMenu ();
|
||||
private:
|
||||
// ActionListener interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
|
||||
// Menu interface.
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
// Variables.
|
||||
gui::Widget *m_startgame;
|
||||
gui::Widget *m_joingame;
|
||||
gui::Widget *m_back;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
void ShowMainMenu();
|
||||
void ShowNetworkMenu();
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
213
project/jni/application/enigma/src/gui/Menu.cpp
Normal file
213
project/jni/application/enigma/src/gui/Menu.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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/Menu.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "options.hh"
|
||||
#include "nls.hh"
|
||||
#include "ecl.hh"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
#define SCREEN ecl::Screen::get_instance()
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Menu -------------------- */
|
||||
|
||||
Menu::Menu()
|
||||
: active_widget(0), quitp(false), abortp(false) {
|
||||
}
|
||||
|
||||
void Menu::add(Widget *w) {
|
||||
Container::add_child(w);
|
||||
}
|
||||
|
||||
void Menu::add(Widget *w, ecl::Rect r) {
|
||||
w->move (r.x, r.y);
|
||||
w->resize (r.w, r.h);
|
||||
add(w);
|
||||
}
|
||||
|
||||
|
||||
void Menu::quit() {
|
||||
quitp=true;
|
||||
}
|
||||
|
||||
void Menu::abort() {
|
||||
abortp=true;
|
||||
}
|
||||
|
||||
bool Menu::manage() {
|
||||
quitp=abortp=false;
|
||||
SDL_Event e;
|
||||
Uint32 enterTickTime = SDL_GetTicks(); // protection against ESC D.o.S. attacks
|
||||
while (SDL_PollEvent(&e)) {} // clear event queue
|
||||
draw_all();
|
||||
while (!(quitp || abortp)) {
|
||||
SCREEN->flush_updates();
|
||||
while (SDL_PollEvent(&e)) {
|
||||
handle_event(e);
|
||||
}
|
||||
SDL_Delay(10);
|
||||
if(active_widget) active_widget->tick(0.01);
|
||||
tick (0.01);
|
||||
refresh();
|
||||
}
|
||||
sound::EmitSoundEvent ("menuexit");
|
||||
// protection against ESC D.o.S. attacks
|
||||
Uint32 menuTickDuration = SDL_GetTicks() - enterTickTime;
|
||||
Uint32 minMenuTickDuration = 300;
|
||||
if (menuTickDuration < minMenuTickDuration)
|
||||
SDL_Delay(minMenuTickDuration - menuTickDuration);
|
||||
while (SDL_PollEvent(&e)) {} // clear event queue
|
||||
return !abortp;
|
||||
}
|
||||
|
||||
void Menu::goto_adjacent_widget(int xdir, int ydir) {
|
||||
Widget *next_widget = 0;
|
||||
if (active_widget) {
|
||||
next_widget = find_adjacent_widget(active_widget, xdir, ydir);
|
||||
}
|
||||
else { // no active_widget yet
|
||||
if ((xdir+ydir)>0) { // take first
|
||||
next_widget = *begin();
|
||||
}
|
||||
else { // take last
|
||||
iterator e = end();
|
||||
for (iterator i = begin(); i != e; ++i) {
|
||||
next_widget = *i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next_widget) {
|
||||
switch_active_widget(next_widget);
|
||||
}
|
||||
else { // no more widgets into that direction found
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::handle_event(const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_KEYDOWN &&
|
||||
e.key.keysym.sym == SDLK_RETURN &&
|
||||
e.key.keysym.mod & KMOD_ALT)
|
||||
{
|
||||
video::ToggleFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
if (on_event(e))
|
||||
return;
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_QUIT:
|
||||
abort();
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
track_active_widget( e.motion.x, e.motion.y );
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if (!active_widget || !active_widget->on_event(e)) {
|
||||
// if not handled by active_widget
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
abort();
|
||||
break;
|
||||
case SDLK_DOWN: goto_adjacent_widget( 0, 1); break;
|
||||
case SDLK_UP: goto_adjacent_widget( 0, -1); break;
|
||||
case SDLK_RIGHT: goto_adjacent_widget( 1, 0); break;
|
||||
case SDLK_LEFT: goto_adjacent_widget(-1, 0); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
track_active_widget( e.button.x, e.button.y );
|
||||
if (active_widget) active_widget->on_event(e);
|
||||
break;
|
||||
case SDL_VIDEOEXPOSE:
|
||||
draw_all();
|
||||
break;
|
||||
default:
|
||||
if (active_widget) active_widget->on_event(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::switch_active_widget(Widget *to_activate) {
|
||||
if (to_activate != active_widget) {
|
||||
if (active_widget)
|
||||
active_widget->deactivate();
|
||||
if (to_activate)
|
||||
to_activate->activate();
|
||||
active_widget = to_activate;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::track_active_widget( int x, int y ) {
|
||||
switch_active_widget(find_widget(x, y));
|
||||
}
|
||||
|
||||
|
||||
void Menu::center() {
|
||||
if (m_widgets.size() > 0) {
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
Rect a = m_widgets[0]->get_area();
|
||||
for (unsigned i=1; i<m_widgets.size(); ++i)
|
||||
{
|
||||
Rect r = m_widgets[i]->get_area();
|
||||
a.x = min(r.x, a.x);
|
||||
a.y = min(r.y, a.y);
|
||||
a.w += max(0, r.x+r.w-a.x-a.w);
|
||||
a.h += max(0, r.y+r.h-a.y-a.h);
|
||||
}
|
||||
Rect c=ecl::center(SCREEN->size(), a);
|
||||
int dx = c.x-a.x;
|
||||
int dy = c.y-a.y;
|
||||
|
||||
for (unsigned i=0; i<m_widgets.size(); ++i) {
|
||||
Rect r = m_widgets[i]->get_area();
|
||||
r.x += dx;
|
||||
r.y += dy;
|
||||
|
||||
m_widgets[i]->move (r.x, r.y);
|
||||
m_widgets[i]->resize (r.w, r.h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::draw (ecl::GC &gc, const ecl::Rect &r)
|
||||
{
|
||||
clip(gc, r);
|
||||
draw_background(gc);
|
||||
Container::draw(gc,r);
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
111
project/jni/application/enigma/src/gui/Menu.hh
Normal file
111
project/jni/application/enigma/src/gui/Menu.hh
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_MENU_HH_INCLUDED
|
||||
#define GUI_MENU_HH_INCLUDED
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
#include "gui/Menu.hh"
|
||||
#include "ecl_fwd.hh"
|
||||
#include "ecl_geom.hh"
|
||||
#include "SDL.h"
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Menu -------------------- */
|
||||
|
||||
class Menu : public Container {
|
||||
public:
|
||||
Menu();
|
||||
|
||||
//! true: ok, false: menu aborted by user
|
||||
virtual bool manage();
|
||||
|
||||
void add(Widget *w);
|
||||
void add(Widget *w, ecl::Rect r);
|
||||
void center();
|
||||
|
||||
void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
|
||||
virtual void quit();
|
||||
void abort();
|
||||
|
||||
protected:
|
||||
void reset_active_widget()
|
||||
{ active_widget = 0; }
|
||||
|
||||
// Menu interface.
|
||||
virtual void draw_background(ecl::GC &/*gc*/) {}
|
||||
|
||||
private:
|
||||
void handle_event(const SDL_Event &e);
|
||||
|
||||
void switch_active_widget(Widget *to_activate);
|
||||
void track_active_widget( int x, int y ); // used by mouse
|
||||
void goto_adjacent_widget(int xdir, int ydir); // used by keyboard
|
||||
|
||||
// Variables.
|
||||
Widget *active_widget;
|
||||
bool quitp, abortp;
|
||||
};
|
||||
|
||||
class BuildVList {
|
||||
ecl::Rect r;
|
||||
Menu *container;
|
||||
int skip;
|
||||
public:
|
||||
BuildVList(Menu *cc, const ecl::Rect &rr, int s)
|
||||
: r(rr), container(cc), skip(s)
|
||||
{}
|
||||
|
||||
Widget *add(Widget *w) {
|
||||
container->add(w, r);
|
||||
r.y += r.h+skip;
|
||||
return w;
|
||||
}
|
||||
|
||||
ecl::Rect pos() const { return r; }
|
||||
};
|
||||
|
||||
class BuildHList {
|
||||
ecl::Rect r;
|
||||
Menu *container;
|
||||
int skip;
|
||||
public:
|
||||
BuildHList(Menu *cc, const ecl::Rect &rr, int s)
|
||||
: r(rr), container(cc), skip(s)
|
||||
{}
|
||||
|
||||
Widget * add(Widget *w) {
|
||||
container->add(w, r);
|
||||
r.x += r.w+skip;
|
||||
return w;
|
||||
}
|
||||
Widget *add (Widget *w, int width) {
|
||||
ecl::Rect rr(r.x, r.y, width, r.h);
|
||||
container->add(w, rr);
|
||||
r.x += width + skip;
|
||||
return w;
|
||||
}
|
||||
|
||||
ecl::Rect pos() const { return r; }
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
85
project/jni/application/enigma/src/gui/MonospacedLabel.cpp
Normal file
85
project/jni/application/enigma/src/gui/MonospacedLabel.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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/MonospacedLabel.hh"
|
||||
#include "ecl.hh"
|
||||
#include "nls.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
MonospacedLabel::MonospacedLabel (const std::string &text, char widthSample,
|
||||
std::string monospaceCharacters, HAlignment halign, VAlignment valign) :
|
||||
Label (text, halign, valign), sampleChar (widthSample),
|
||||
monoChars (monospaceCharacters) {
|
||||
}
|
||||
|
||||
void MonospacedLabel::draw (ecl::GC &gc, const ecl::Rect &) {
|
||||
Font *f = m_font;
|
||||
int w, h;
|
||||
naturalsize (w, h);
|
||||
|
||||
int x = get_x(), y=get_y();
|
||||
switch (m_halign) {
|
||||
case HALIGN_LEFT: break;
|
||||
case HALIGN_RIGHT: x += get_w() - w; break;
|
||||
case HALIGN_CENTER: x += (get_w()-w)/2; break;
|
||||
}
|
||||
switch (m_valign) {
|
||||
case VALIGN_TOP: break;
|
||||
case VALIGN_BOTTOM: y += get_h() - h; break;
|
||||
case VALIGN_CENTER: y += (get_h()-h)/2; break;
|
||||
}
|
||||
// translate if not an empty string
|
||||
const char * translation = _(m_text.c_str());
|
||||
int len = strlen(translation);
|
||||
int monoWidth = m_font->get_width(sampleChar);
|
||||
char c[] = " ";
|
||||
for (int i = 0; i<len; i++) {
|
||||
c[0] = translation[i];
|
||||
if (monoChars.empty() || monoChars.find_first_of(c[0]) !=
|
||||
std::string::npos) {
|
||||
int charWidth = m_font->get_width(c[0]);
|
||||
// centere char into monoWodth
|
||||
f->render (gc, x + (monoWidth-charWidth)/2, y, c);
|
||||
x += monoWidth;
|
||||
} else {
|
||||
f->render (gc, x, y, c);
|
||||
x += m_font->get_width(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonospacedLabel::naturalsize (int &w, int &h) const {
|
||||
h = m_font->get_height();
|
||||
w = 0;
|
||||
const char * translation = _(m_text.c_str());
|
||||
int len = strlen(translation);
|
||||
int monoWidth = m_font->get_width(sampleChar);
|
||||
for (int i = 0; i<len; i++) {
|
||||
if (monoChars.empty() || monoChars.find_first_of(translation[i]) !=
|
||||
std::string::npos) {
|
||||
w += monoWidth;
|
||||
} else {
|
||||
w += m_font->get_width(translation[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::lev
|
||||
57
project/jni/application/enigma/src/gui/MonospacedLabel.hh
Normal file
57
project/jni/application/enigma/src/gui/MonospacedLabel.hh
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_MONOSPACEDLABEL_HH_INCLUDED
|
||||
#define GUI_MONOSPACEDLABEL_HH_INCLUDED
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/**
|
||||
* A text label that uses the same width for each character even for
|
||||
* proportional fonts. Character positions of the label text is predictable
|
||||
* and alignment of several labels is thus possible. Usefull for output of
|
||||
* formatted numbers like score values.<p>
|
||||
* Not all characters have to be monospaced. The set of characters that
|
||||
* should have a constant width can be limited f.e. to the numbers 0-9.
|
||||
*/
|
||||
class MonospacedLabel : public Label {
|
||||
public:
|
||||
/**
|
||||
* The standard constructor.
|
||||
* @arg text The constant output text.
|
||||
* @arg widthSample The character that defines the width. Default is 'm'.
|
||||
* @arg monospaceCharacters The set of monospace characters. An empty
|
||||
* string means all characters. Example "0123456789".
|
||||
* @arg halign
|
||||
* @arg valign
|
||||
*/
|
||||
MonospacedLabel (const std::string &text="", char widthSample = 'm',
|
||||
std::string monospaceCharacters = "",
|
||||
HAlignment halign=HALIGN_CENTER, VAlignment valign=VALIGN_CENTER);
|
||||
|
||||
// Widget interface
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
virtual void naturalsize (int &w, int &h) const;
|
||||
protected:
|
||||
char sampleChar;
|
||||
std::string monoChars;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
477
project/jni/application/enigma/src/gui/OptionsMenu.cpp
Normal file
477
project/jni/application/enigma/src/gui/OptionsMenu.cpp
Normal file
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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/OptionsMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
#include "LocalToXML.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "oxyd.hh"
|
||||
#include "sound.hh"
|
||||
#include "Utf8ToXML.hh"
|
||||
#include "video.hh"
|
||||
#include "XMLtoLocal.hh"
|
||||
#include "XMLtoUtf8.hh"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/* -------------------- Buttons for Options -------------------- */
|
||||
|
||||
class MouseSpeedButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return ecl::round_nearest<int>(options::GetMouseSpeed());
|
||||
}
|
||||
void set_value(int value) {
|
||||
options::SetMouseSpeed (value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
MouseSpeedButton()
|
||||
: ValueButton(options::MIN_MouseSpeed, options::MAX_MouseSpeed)
|
||||
{ init(); }
|
||||
};
|
||||
|
||||
class SoundVolumeButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return round_nearest<int>(options::GetDouble("SoundVolume")*10.0);
|
||||
}
|
||||
void set_value(int value) {
|
||||
options::SetOption("SoundVolume", value/10.0);
|
||||
options::UpdateVolume();
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
if (value == 0) {
|
||||
return _("muted");
|
||||
}
|
||||
else {
|
||||
return strf("%d", value);
|
||||
}
|
||||
}
|
||||
public:
|
||||
SoundVolumeButton() : ValueButton(0, 10) { init(); }
|
||||
};
|
||||
|
||||
class MusicVolumeButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return round_nearest<int> (options::GetDouble("MusicVolume")*10.0);
|
||||
}
|
||||
void set_value(int value) {
|
||||
options::SetOption("MusicVolume", value/10.0);
|
||||
options::UpdateVolume();
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
if (value == 0)
|
||||
return _("muted");
|
||||
else
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
MusicVolumeButton() : ValueButton(0, 10) { init(); }
|
||||
};
|
||||
|
||||
class InGameMusicButton : public BoolOptionButton {
|
||||
void on_action(Widget *) {
|
||||
if (toggle())
|
||||
sound::PlayMusic (options::GetString("LevelMusicFile"));
|
||||
else
|
||||
sound::StopMusic (options::GetString("LevelMusicFile"));
|
||||
}
|
||||
public:
|
||||
InGameMusicButton() :
|
||||
BoolOptionButton("InGameMusic", N_("Music in game"), N_("No music in game"), this)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct SkipSolvedButton : public BoolOptionButton {
|
||||
SkipSolvedButton() : BoolOptionButton("SkipSolvedLevels", N_("Yes"), N_("No"), this) {}
|
||||
};
|
||||
|
||||
struct TimeHuntButton : public BoolOptionButton {
|
||||
TimeHuntButton() : BoolOptionButton("TimeHunting", N_("Yes"), N_("No"), this) {}
|
||||
};
|
||||
|
||||
struct RatingsUpdateButton : public BoolOptionButton {
|
||||
RatingsUpdateButton() : BoolOptionButton("RatingsAutoUpdate", N_("Auto"), N_("Never"), this) {}
|
||||
};
|
||||
|
||||
class VideoModeButton : public TextButton {
|
||||
|
||||
video::VideoModes get_mode() const {
|
||||
int mode = Clamp(options::GetInt("VideoMode"), 0, int(video::VM_COUNT));
|
||||
return static_cast<video::VideoModes>(mode);
|
||||
}
|
||||
string get_text() const {
|
||||
return GetInfo(get_mode())->name;
|
||||
}
|
||||
void on_action(Widget *) {
|
||||
int mode = get_mode();
|
||||
|
||||
// cycle at most once through all available video modes
|
||||
do {
|
||||
mode += 1;
|
||||
if (mode >= video::VM_COUNT)
|
||||
mode = 0;
|
||||
|
||||
const video::VMInfo *vminfo = GetInfo (static_cast<video::VideoModes>(mode));
|
||||
if (vminfo->available) {
|
||||
options::SetOption("VideoMode", mode);
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
} while (mode != get_mode());
|
||||
}
|
||||
public:
|
||||
VideoModeButton() : TextButton(this) { }
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- SoundSetButton -------------------- */
|
||||
|
||||
SoundSetButton::SoundSetButton() : ValueButton(0, 1) {
|
||||
int numAvail = sound::GetOptionSoundSetCount();
|
||||
setMaxValue(numAvail - 1);
|
||||
init();
|
||||
}
|
||||
|
||||
int SoundSetButton::get_value() const {
|
||||
return sound::GetOptionSoundSet();
|
||||
}
|
||||
|
||||
void SoundSetButton::set_value(int value) {
|
||||
sound::SetOptionSoundSet(value);
|
||||
}
|
||||
|
||||
string SoundSetButton::get_text(int value) const {
|
||||
return _(sound::GetOptionSoundSetText(value).c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- StereoButton -------------------- */
|
||||
|
||||
StereoButton::StereoButton() : ValueButton(-1, 1)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
int StereoButton::get_value() const
|
||||
{
|
||||
double separation = options::GetDouble("StereoSeparation");
|
||||
if (separation == 0)
|
||||
return 0;
|
||||
else
|
||||
return (separation > 0) ? 1 : -1;
|
||||
}
|
||||
void StereoButton::set_value(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
options::SetOption("StereoSeparation", 0.0);
|
||||
else if (value > 0)
|
||||
options::SetOption("StereoSeparation", 10.0);
|
||||
else
|
||||
options::SetOption("StereoSeparation", -10.0);
|
||||
}
|
||||
|
||||
string StereoButton::get_text(int value) const
|
||||
{
|
||||
switch (value) {
|
||||
case -1: return _("reversed");
|
||||
case 0: return _("mono");
|
||||
case 1: return _("normal");
|
||||
}
|
||||
assert(0);
|
||||
return string();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- FullscreenButton -------------------- */
|
||||
|
||||
FullscreenButton::FullscreenButton()
|
||||
: BoolOptionButton("FullScreen", N_("Yes"), N_("No"), this)
|
||||
{
|
||||
}
|
||||
|
||||
/* -------------------- LanguageButton -------------------- */
|
||||
|
||||
struct Language {
|
||||
const char *name;
|
||||
const char *localename;
|
||||
};
|
||||
|
||||
Language languages[] = {
|
||||
{ "default", "" },
|
||||
{ "Deutsch", "de_DE" },
|
||||
{ "English", "en_EN" },
|
||||
{ "Español", "es_ES" },
|
||||
{ "Français", "fr_FR" },
|
||||
{ "Italiano", "it_IT" },
|
||||
{ "Nederlands", "nl_NL" },
|
||||
{ "Svenska", "sv_SE" },
|
||||
{ "Русский", "ru_RU" },
|
||||
{ "Magyar", "hu_HU" },
|
||||
{ "Português", "pt_BR" },
|
||||
{ "Suomi", "fi_FI" },
|
||||
};
|
||||
|
||||
int LanguageButton::get_value() const
|
||||
{
|
||||
string localename; // = ecl::DefaultMessageLocale ();
|
||||
options::GetOption ("Language", localename);
|
||||
|
||||
int lang = 0; // unknown language
|
||||
for (size_t i=0; i<NUMENTRIES(languages); ++i) {
|
||||
if (localename == languages[i].localename)
|
||||
lang = int(i);
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
void LanguageButton::set_value(int value)
|
||||
{
|
||||
options::SetOption ("Language", languages[value].localename);
|
||||
|
||||
if ( not inInit) {
|
||||
// change language only on user action
|
||||
app.setLanguage(languages[value].localename);
|
||||
myListener->on_action(this);
|
||||
}
|
||||
}
|
||||
|
||||
string LanguageButton::get_text(int value) const
|
||||
{
|
||||
if (value == -1)
|
||||
return _("unknown");
|
||||
else
|
||||
return languages[value].name;
|
||||
}
|
||||
|
||||
LanguageButton::LanguageButton (ActionListener *al)
|
||||
: ValueButton(0, NUMENTRIES(languages)-1), myListener(al)
|
||||
{
|
||||
inInit = true;
|
||||
init();
|
||||
inInit = false;
|
||||
}
|
||||
|
||||
/* -------------------- GammaButton -------------------- */
|
||||
|
||||
|
||||
GammaButton::GammaButton()
|
||||
: ValueButton(1, 10)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void GammaButton::set_value(int value)
|
||||
{
|
||||
double gamma = double(value) / 5.0;
|
||||
options::SetOption ("Gamma", gamma);
|
||||
video::UpdateGamma();
|
||||
}
|
||||
|
||||
int GammaButton::get_value() const
|
||||
{
|
||||
double gamma = options::GetDouble ("Gamma");
|
||||
int value = round_down<int>(gamma * 5.0);
|
||||
return value;
|
||||
}
|
||||
|
||||
string GammaButton::get_text(int value) const
|
||||
{
|
||||
return ecl::strf ("%d", value-5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Options Menu -------------------- */
|
||||
|
||||
OptionsMenu::OptionsMenu(ecl::Surface *background_)
|
||||
: back(new StaticTextButton(N_("Back"), this)),
|
||||
fullscreen(new FullscreenButton),
|
||||
m_restartinfo (new Label("")),
|
||||
background(background_),
|
||||
previous_caption(video::GetCaption())
|
||||
{
|
||||
const int spacing = 5;
|
||||
const int big_spacing = 60;
|
||||
const int label_width = 180;
|
||||
const int but_width = 100;
|
||||
const int but_height = 30;
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
int hmargin = vminfo->width < 660 ? 10 : (vminfo->width < 900 ? 20 : 80);
|
||||
int midspacing = vminfo->width - 2*hmargin - 2*but_width - 2*label_width;
|
||||
|
||||
BuildVList leftlabels (this, Rect(-label_width, 0, label_width, but_height), spacing);
|
||||
BuildVList left (this, Rect(0, 0, but_width, but_height), spacing);
|
||||
BuildVList rightlabels (this, Rect(but_width+midspacing, 0, label_width, but_height), spacing);
|
||||
BuildVList right(this, Rect(but_width+midspacing+label_width, 0, but_width, but_height), spacing);
|
||||
leftlabels.add (new Label(N_("Language: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Fullscreen: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Video mode: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Gamma correction: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Mouse speed: "), HALIGN_RIGHT));
|
||||
|
||||
language = new LanguageButton(this);
|
||||
left.add (language);
|
||||
left.add (fullscreen);
|
||||
left.add (new VideoModeButton);
|
||||
left.add (new GammaButton);
|
||||
left.add (new MouseSpeedButton);
|
||||
|
||||
rightlabels.add (new Label(N_("Sound volume: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Sound set: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Music volume: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Stereo: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Ratings update: "), HALIGN_RIGHT));
|
||||
|
||||
right.add (new SoundVolumeButton);
|
||||
right.add (new SoundSetButton);
|
||||
right.add (new MusicVolumeButton);
|
||||
// right.add (new InGameMusicButton);Über
|
||||
right.add (new StereoButton);
|
||||
right.add (new RatingsUpdateButton);
|
||||
|
||||
Rect l = left.pos();
|
||||
Rect r = right.pos();
|
||||
|
||||
BuildVList bottomlabels (this, Rect(-label_width, Max(l.y, r.y), label_width, but_height), spacing);
|
||||
BuildVList bottom (this, Rect(0, Max(l.y, r.y), vminfo->width - 2*hmargin - label_width, but_height), spacing);
|
||||
bottomlabels.add (new Label(N_("User name: "), HALIGN_RIGHT));
|
||||
bottomlabels.add (new Label(N_("User path: "), HALIGN_RIGHT));
|
||||
bottomlabels.add (new Label(N_("User image path: "), HALIGN_RIGHT));
|
||||
userNameTF = new TextField(app.state->getString("UserName"));
|
||||
userNameTF->setMaxChars(20);
|
||||
userNameTF->setInvalidChars("+");
|
||||
bottom.add (userNameTF);
|
||||
userPathTF = new TextField(XMLtoUtf8(LocalToXML(app.userPath.c_str()).x_str()).c_str());
|
||||
bottom.add (userPathTF);
|
||||
userImagePathTF = new TextField(XMLtoUtf8(LocalToXML(app.userImagePath.c_str()).x_str()).c_str());
|
||||
bottom.add (userImagePathTF);
|
||||
|
||||
// add (m_restartinfo, Rect (l.x, l.y + 15, 400, 20));
|
||||
// m_restartinfo->set_alignment (HALIGN_LEFT);
|
||||
// update_info();
|
||||
|
||||
Rect b = bottom.pos();
|
||||
l.x = (l.x+r.x)/2;
|
||||
l.y = b.y+big_spacing;
|
||||
|
||||
add(back, l);
|
||||
}
|
||||
|
||||
OptionsMenu::~OptionsMenu() {
|
||||
video::SetCaption(previous_caption.c_str());
|
||||
}
|
||||
|
||||
// void OptionsMenu::update_info()
|
||||
// {
|
||||
// if (options::MustRestart)
|
||||
// m_restartinfo->set_text (
|
||||
// N_("Please restart Enigma to activate your changes!"));
|
||||
// else
|
||||
// m_restartinfo->set_text ("");
|
||||
// }
|
||||
|
||||
void OptionsMenu::quit() {
|
||||
std::string tfUserPathLocal = XMLtoLocal(Utf8ToXML(userPathTF->getText().c_str()).x_str()).c_str();
|
||||
std::string tfUserImageLocal = XMLtoLocal(Utf8ToXML(userImagePathTF->getText().c_str()).x_str()).c_str();
|
||||
if ((app.state->getString("UserName") != userNameTF->getText())
|
||||
|| (app.userPath != tfUserPathLocal ) || (app.userImagePath != tfUserImageLocal)) {
|
||||
// ensure that enigma.score is saved with new Username or to new location
|
||||
lev::ScoreManager::instance()->markModified();
|
||||
}
|
||||
// strip off leading and trailing whitespace from user name
|
||||
std::string userName = userNameTF->getText();
|
||||
std::string::size_type firstChar = userName.find_first_not_of(" ");
|
||||
std::string::size_type lastChar = userName.find_last_not_of(" ");
|
||||
if (firstChar != std::string::npos)
|
||||
app.state->setProperty("UserName", userName.substr(firstChar, lastChar - firstChar + 1));
|
||||
else
|
||||
app.state->setProperty("UserName", std::string(""));
|
||||
app.setUserPath(tfUserPathLocal.c_str());
|
||||
app.setUserImagePath(tfUserImageLocal.c_str());
|
||||
Menu::quit();
|
||||
}
|
||||
|
||||
bool OptionsMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
bool handled=false;
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN
|
||||
&& e.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
quit();
|
||||
handled = true;
|
||||
}
|
||||
else if (e.type == SDL_KEYUP) {
|
||||
if ((e.key.keysym.sym==SDLK_RETURN) &&
|
||||
(e.key.keysym.mod & KMOD_ALT))
|
||||
{
|
||||
// update state of FullscreenButton :
|
||||
fullscreen->invalidate();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void OptionsMenu::on_action(Widget *w)
|
||||
{
|
||||
if (w == back)
|
||||
quit();
|
||||
else if (w == language)
|
||||
// language changed - retranslate and redraw everything
|
||||
invalidate_all();
|
||||
}
|
||||
|
||||
void OptionsMenu::tick (double)
|
||||
{
|
||||
// update_info();
|
||||
}
|
||||
|
||||
void OptionsMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
video::SetCaption(("Enigma - Options Menu"));
|
||||
// blit(gc, 0,0, enigma::GetImage("menu_bg"));
|
||||
blit(gc, 0,0, background);
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void ShowOptionsMenu(Surface *background) {
|
||||
if (background == 0)
|
||||
background = enigma::GetImage("menu_bg", ".jpg");
|
||||
OptionsMenu m(background);
|
||||
m.center();
|
||||
m.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
|
||||
104
project/jni/application/enigma/src/gui/OptionsMenu.hh
Normal file
104
project/jni/application/enigma/src/gui/OptionsMenu.hh
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_OPTIONSMENU_HH_INCLUDED
|
||||
#define GUI_OPTIONSMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- OptionsMenu -------------------- */
|
||||
|
||||
class OptionsMenu : public Menu {
|
||||
public:
|
||||
OptionsMenu(ecl::Surface *background_);
|
||||
~OptionsMenu();
|
||||
virtual void quit();
|
||||
private:
|
||||
void update_info();
|
||||
|
||||
// ActionListener interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
|
||||
// Menu interface.
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
// Variables.
|
||||
gui::Widget *back, *fullscreen, *language;
|
||||
gui::TextField *userNameTF;
|
||||
gui::TextField *userPathTF;
|
||||
gui::TextField *userImagePathTF;
|
||||
gui::Label *m_restartinfo;
|
||||
ecl::Surface *background;
|
||||
std::string previous_caption;
|
||||
};
|
||||
|
||||
/* -------------------- Options Buttons -------------------- */
|
||||
|
||||
struct FullscreenButton : public BoolOptionButton {
|
||||
FullscreenButton();
|
||||
};
|
||||
|
||||
|
||||
class StereoButton : public ValueButton {
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
public:
|
||||
StereoButton();
|
||||
};
|
||||
|
||||
|
||||
class SoundSetButton : public ValueButton {
|
||||
public:
|
||||
SoundSetButton();
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
};
|
||||
|
||||
class LanguageButton : public ValueButton {
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
bool inInit;
|
||||
ActionListener *myListener;
|
||||
public:
|
||||
// second user action listener: first one is misused by ValueButton
|
||||
LanguageButton (ActionListener *al = 0);
|
||||
|
||||
};
|
||||
|
||||
class GammaButton : public ValueButton {
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
public:
|
||||
GammaButton ();
|
||||
|
||||
};
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void ShowOptionsMenu(ecl::Surface *background);
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
109
project/jni/application/enigma/src/gui/ScreenshotViewer.cpp
Normal file
109
project/jni/application/enigma/src/gui/ScreenshotViewer.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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/ScreenshotViewer.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
static const char *helptext[] = {
|
||||
N_("Escape:"), N_("Back"),
|
||||
"F1:", N_("Show this help"),
|
||||
N_("Page Up:"), N_("Show previous screenshot"),
|
||||
N_("Page Down:"), N_("Show next screenshot"),
|
||||
0
|
||||
};
|
||||
|
||||
ScreenshotViewer::ScreenshotViewer(lev::Proxy *aLevel) :
|
||||
levelProxy (aLevel), shotNumber (0) {
|
||||
}
|
||||
|
||||
ScreenshotViewer::~ScreenshotViewer() {
|
||||
}
|
||||
|
||||
bool ScreenshotViewer::on_event (const SDL_Event &e) {
|
||||
switch (e.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (e.button.button == SDL_BUTTON_RIGHT) {
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
SDLKey keysym = e.key.keysym.sym;
|
||||
switch (keysym) {
|
||||
case SDLK_PAGEUP:
|
||||
if (shotNumber > 0 )
|
||||
--shotNumber;
|
||||
invalidate_all();
|
||||
return true;
|
||||
case SDLK_PAGEDOWN:
|
||||
shotNumber++;
|
||||
invalidate_all();
|
||||
return true;
|
||||
// eat up widget activation keys - we have no widgets
|
||||
case SDLK_DOWN:
|
||||
case SDLK_UP:
|
||||
case SDLK_RIGHT:
|
||||
case SDLK_LEFT:
|
||||
return true;
|
||||
case SDLK_F1:
|
||||
displayHelp(helptext, 200);
|
||||
invalidate_all();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScreenshotViewer::draw_background (ecl::GC &gc) {
|
||||
std::string filename = "screenshots/" +
|
||||
levelProxy->getLocalSubstitutionLevelPath() +
|
||||
(shotNumber > 0 ? ecl::strf("#%d", shotNumber) : "") + ".png";
|
||||
std::string fullPath;
|
||||
if (app.resourceFS->findFile(filename, fullPath)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
ecl::Surface * image = ecl::LoadImage(fullPath.c_str());
|
||||
if (image->width() == vminfo->width && image->height() == vminfo->height) {
|
||||
blit(gc, 0,0, image);
|
||||
} else {
|
||||
ecl::Surface * imageZoomed = image->zoom(vminfo->width, vminfo->height);
|
||||
blit(gc, 0,0, imageZoomed);
|
||||
delete imageZoomed;
|
||||
}
|
||||
delete image;
|
||||
} else {
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
Font *f = enigma::GetFont("menufont");
|
||||
f->render (gc, 30, 60, _("No screenshot available:"));
|
||||
f->render (gc, 30, 100, filename.c_str());
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
49
project/jni/application/enigma/src/gui/ScreenshotViewer.hh
Normal file
49
project/jni/application/enigma/src/gui/ScreenshotViewer.hh
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GUI_SCREENSHOTVIEWER_HH_INCLUDED
|
||||
#define GUI_SCREENSHOTVIEWER_HH_INCLUDED
|
||||
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/**
|
||||
* TODO delete CTRL-D with confirmation panel - rename of following shots?
|
||||
* TODO shift up, down for reorder/rename of shots
|
||||
*/
|
||||
class ScreenshotViewer : public gui::Menu {
|
||||
public:
|
||||
ScreenshotViewer (lev::Proxy *aLevel);
|
||||
~ScreenshotViewer ();
|
||||
|
||||
// Widget interface
|
||||
virtual bool on_event (const SDL_Event &e);
|
||||
protected:
|
||||
// Menu interface.
|
||||
virtual void draw_background (ecl::GC &gc);
|
||||
private:
|
||||
lev::Proxy *levelProxy;
|
||||
std::string basePath;
|
||||
int shotNumber;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
91
project/jni/application/enigma/src/gui/SearchMenu.cpp
Normal file
91
project/jni/application/enigma/src/gui/SearchMenu.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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/SearchMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "errors.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
SearchMenu::SearchMenu() : didSearch (false) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
ecl::Font *menufont = enigma::GetFont("menufont");
|
||||
|
||||
Label * shallowTitle = new Label(N_("Shallow Search:"), HALIGN_LEFT);
|
||||
// TRANSLATORS: the translation can have double size of the english text
|
||||
std::string helpText = _("case independent search in title, author, filename");
|
||||
std::string workString = helpText;
|
||||
std::string::size_type breakPos = breakString(menufont, workString,
|
||||
" ", 380);
|
||||
Label * shallowHelp1 = new UntranslatedLabel(workString.substr(0,breakPos), HALIGN_LEFT);
|
||||
Label * shallowHelp2 = new UntranslatedLabel(workString.substr(breakPos), HALIGN_LEFT);
|
||||
shallowSearch = new TextField("", this);
|
||||
|
||||
this->add(shallowTitle, Rect(vminfo.width/2 - 190, vminfo.height/2 - 100, 380, 35));
|
||||
this->add(shallowHelp1, Rect(vminfo.width/2 - 190, vminfo.height/2 - 40, 380, 25));
|
||||
this->add(shallowHelp2, Rect(vminfo.width/2 - 190, vminfo.height/2 - 10, 380, 25));
|
||||
this->add(shallowSearch, Rect(vminfo.width/2 - 190, vminfo.height/2 + 55, 380, 35));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
Label * dummy1 = new Label();
|
||||
Label * dummy2 = new Label();
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_search = new StaticTextButton(N_("Search"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(dummy1);
|
||||
commandHList->add_back(dummy2);
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_search);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
}
|
||||
|
||||
bool SearchMenu::isSearchQuit() {
|
||||
return didSearch;
|
||||
}
|
||||
|
||||
void SearchMenu::on_action(Widget *w) {
|
||||
if (w == but_search ||
|
||||
(w == shallowSearch && shallowSearch->wasLastActionReturn())) {
|
||||
lev::Index::setCurrentIndex(lev::Proxy::search(shallowSearch->getText()));
|
||||
didSearch = true;
|
||||
Menu::quit();
|
||||
} else if (w == but_ignore) {
|
||||
Menu::quit();
|
||||
}
|
||||
}
|
||||
|
||||
void SearchMenu::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Search Menu"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
43
project/jni/application/enigma/src/gui/SearchMenu.hh
Normal file
43
project/jni/application/enigma/src/gui/SearchMenu.hh
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_SEARCHMENU_HH_INCLUDED
|
||||
#define GUI_SEARCHMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class SearchMenu : public gui::Menu {
|
||||
public:
|
||||
SearchMenu ();
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
bool isSearchQuit();
|
||||
|
||||
private:
|
||||
TextField *shallowSearch;
|
||||
Widget *but_ignore;
|
||||
Widget *but_search;
|
||||
bool didSearch;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
281
project/jni/application/enigma/src/gui/TextField.cpp
Normal file
281
project/jni/application/enigma/src/gui/TextField.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2005 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 "main.hh"
|
||||
#include "gui/widgets.hh"
|
||||
#include "gui/TextField.hh"
|
||||
#include "ecl_utf.hh"
|
||||
#include "enigma.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "options.hh"
|
||||
#include "nls.hh"
|
||||
#include "ecl.hh"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace enigma::gui;
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
#define SCREEN ecl::Screen::get_instance()
|
||||
|
||||
ecl::Font *TextField::menufont = 0;
|
||||
|
||||
TextField::TextField(const std::string &t, ActionListener *al) : cursorTime(0),
|
||||
showCursor(true), isLastActionReturn (false), invalidChars(""),
|
||||
isLimitedToValidChars(false), maxChars(-1) {
|
||||
if (menufont == 0) {
|
||||
menufont = enigma::GetFont("menufont");
|
||||
}
|
||||
set_listener(al);
|
||||
textPreCursor = t;
|
||||
ecl::utf8CharSizes(textPreCursor, charSizesPreCursor);
|
||||
textPostCursor= "";
|
||||
}
|
||||
|
||||
void TextField::set_text(const std::string &t) {
|
||||
textPreCursor = t;
|
||||
charSizesPreCursor.clear();
|
||||
ecl::utf8CharSizes(textPreCursor, charSizesPreCursor);
|
||||
textPostCursor= "";
|
||||
charSizesPostCursor.clear();
|
||||
}
|
||||
|
||||
std::string TextField::getText() {
|
||||
string total = textPreCursor;
|
||||
total += textPostCursor;
|
||||
return total;
|
||||
}
|
||||
|
||||
void TextField::setInvalidChars(std::string forbiddenChars) {
|
||||
invalidChars = forbiddenChars;
|
||||
}
|
||||
|
||||
void TextField::setMaxChars(int max) {
|
||||
maxChars = max;
|
||||
}
|
||||
bool TextField::wasLastActionReturn() {
|
||||
return isLastActionReturn;
|
||||
}
|
||||
|
||||
void TextField::tick (double dtime) {
|
||||
cursorTime += dtime;
|
||||
if (cursorTime > 0.5) {
|
||||
cursorTime = 0.0;
|
||||
showCursor = !showCursor;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void TextField::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
Button::draw(gc,r);
|
||||
Font *f = menufont;
|
||||
int h = f->get_height();
|
||||
int w_pre = f->get_width(textPreCursor.c_str());
|
||||
int w_post = f->get_width(textPostCursor.c_str());
|
||||
int w_cursor = m_activep ? 1 : 0;
|
||||
int x = get_x() + (get_w()- w_pre - w_post - w_cursor )/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
|
||||
// cursor always visible
|
||||
if (x + w_pre < get_x() + 5)
|
||||
// cursor would be left of textfield - shift centered text right
|
||||
x = get_x() + 5 - w_pre;
|
||||
|
||||
if (x + w_pre > get_x() + get_w() - 5)
|
||||
// cursor would be right of textfiled - shift centered text left
|
||||
x = get_x() + get_w() - 5 - w_pre;
|
||||
|
||||
f->render (gc, x, y, textPreCursor.c_str());
|
||||
|
||||
x += w_pre;
|
||||
if (m_activep) {
|
||||
if (showCursor) {
|
||||
set_color(gc, 200,200,200);
|
||||
vline(gc, x, y, h);
|
||||
}
|
||||
x += w_cursor;
|
||||
}
|
||||
|
||||
f->render (gc, x, y, textPostCursor.c_str());
|
||||
|
||||
}
|
||||
|
||||
bool TextField::on_event(const SDL_Event &e) {
|
||||
bool handeled = false;
|
||||
bool modified = false;
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
// set cursor
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_RETURN:
|
||||
handeled = true;
|
||||
isLastActionReturn = true;
|
||||
invoke_listener();
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
if(textPostCursor.size() > 0) {
|
||||
int size = charSizesPostCursor.back();
|
||||
charSizesPostCursor.pop_back();
|
||||
charSizesPreCursor.push_back(size);
|
||||
textPreCursor.append(textPostCursor, 0, size);
|
||||
textPostCursor.erase(0, size);
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
if(textPreCursor.size() > 0) {
|
||||
int size = charSizesPreCursor.back();
|
||||
charSizesPreCursor.pop_back();
|
||||
charSizesPostCursor.push_back(size);
|
||||
textPostCursor.insert(0, textPreCursor.substr(textPreCursor.size() - size));
|
||||
textPreCursor.erase(textPreCursor.size() - size);
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_INSERT:
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_HOME:
|
||||
if(textPreCursor.size() > 0) {
|
||||
int i;
|
||||
int preChars = charSizesPreCursor.size();
|
||||
for (i = 0; i < preChars; i++) {
|
||||
int size = charSizesPreCursor.back();
|
||||
charSizesPreCursor.pop_back();
|
||||
charSizesPostCursor.push_back(size);
|
||||
}
|
||||
textPostCursor.insert(0, textPreCursor);
|
||||
textPreCursor.clear();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_END:
|
||||
if(textPostCursor.size() > 0) {
|
||||
int size;
|
||||
int i;
|
||||
int postChars = charSizesPostCursor.size();
|
||||
for (i = 0; i < postChars; i++) {
|
||||
size = charSizesPostCursor.back();
|
||||
charSizesPostCursor.pop_back();
|
||||
charSizesPreCursor.push_back(size);
|
||||
}
|
||||
textPreCursor.append(textPostCursor);
|
||||
textPostCursor.clear();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_DELETE:
|
||||
if(textPostCursor.size() > 0) {
|
||||
int size = charSizesPostCursor.back();
|
||||
textPostCursor.erase(0, size);
|
||||
charSizesPostCursor.pop_back();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
modified = true;
|
||||
break;
|
||||
case SDLK_BACKSPACE:
|
||||
if(textPreCursor.size() > 0) {
|
||||
int size = charSizesPreCursor.back();
|
||||
textPreCursor.erase(textPreCursor.size() - size);
|
||||
charSizesPreCursor.pop_back();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
modified = true;
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
case SDLK_DOWN:
|
||||
case SDLK_UP:
|
||||
// menu active widget movements
|
||||
break;
|
||||
default:
|
||||
// get char
|
||||
if (e.key.keysym.unicode != 0 ) {
|
||||
UTF16 realChar;
|
||||
if (e.key.keysym.unicode >= 0x20 &&
|
||||
(e.key.keysym.unicode < 0x80 || // key pad
|
||||
e.key.keysym.sym < 0x80)) { // windows umlaute
|
||||
// the unicode is correct in these cases
|
||||
realChar = e.key.keysym.unicode;
|
||||
}
|
||||
else if (e.key.keysym.unicode >= 0x80 &&
|
||||
e.key.keysym.sym < 0x100) {
|
||||
// Linux: bad unicode but sym is ISO-8859-1
|
||||
|
||||
// incomplete workaround - runs only for some lower
|
||||
// case umlauts
|
||||
// we would need to handle shift key in language
|
||||
// dependent manner -- or fix SDL Linux
|
||||
realChar = e.key.keysym.sym;
|
||||
}
|
||||
else {
|
||||
// chars like ctrl-a - ctrl-z
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
break;
|
||||
}
|
||||
if ((maxChars >= 0 && (charSizesPreCursor.size() + charSizesPostCursor.size()) >= maxChars) ||
|
||||
realChar < 0x100 && invalidChars.find((char)realChar) != std::string::npos) {
|
||||
// string too long or invalid char
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
break;
|
||||
}
|
||||
unsigned char utf8Char[4];
|
||||
UTF16 const * utf16Ptr = (UTF16 *)&realChar;
|
||||
UTF8 * utf8Ptr = utf8Char;
|
||||
ConversionResult result;
|
||||
result = ConvertUTF16toUTF8 (&utf16Ptr, utf16Ptr + 1,
|
||||
&utf8Ptr, utf8Char + 4, strictConversion);
|
||||
*utf8Ptr = 0;
|
||||
textPreCursor += (const char *)utf8Char;
|
||||
charSizesPreCursor.push_back(utf8Ptr - utf8Char);
|
||||
|
||||
invalidate();
|
||||
handeled = true;
|
||||
modified = true;
|
||||
break;
|
||||
}
|
||||
if (e.key.keysym.sym < 300 || e.key.keysym.sym > 314 ){
|
||||
// chars like PageUp, F1 but not key state modifier
|
||||
// like shift, alt,...
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (modified) {
|
||||
isLastActionReturn = false;
|
||||
invoke_listener();
|
||||
}
|
||||
return handeled;
|
||||
}
|
||||
|
||||
96
project/jni/application/enigma/src/gui/TextField.hh
Normal file
96
project/jni/application/enigma/src/gui/TextField.hh
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2005 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GUI_TF_HH_INCLUDED
|
||||
#define GUI_TF_HH_INCLUDED
|
||||
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/**
|
||||
* Gui widget for simple text insertion. Cursor keys, backspace and delete,
|
||||
* home and end are supported. As a widget it handels utf-8 strings. But
|
||||
* in contrast to other widget there is of course no gettext l10n translation.
|
||||
* This widget is designed to be part of a menu.
|
||||
* <par>
|
||||
* ToDo: supply full Linux umlaut support;
|
||||
* add hook for external or subclass char insertion validation
|
||||
* (NumberField, ...);
|
||||
* move mouse cursor out of Textfield without deselection
|
||||
*/
|
||||
class TextField : public Button {
|
||||
public:
|
||||
/**
|
||||
* Creates a boarderd text input field.
|
||||
* @param t preset utf-8 input string
|
||||
* @param al currently unused
|
||||
*/
|
||||
TextField(const std::string &t = "", ActionListener *al=0);
|
||||
|
||||
/**
|
||||
* resets the input string.
|
||||
* @param t new utf-8 input string
|
||||
*/
|
||||
void set_text(const std::string &t);
|
||||
|
||||
/**
|
||||
* returns the inserted text
|
||||
* @return the utf-8 coded string
|
||||
*/
|
||||
std::string getText();
|
||||
|
||||
void setInvalidChars(std::string forbiddenChars); // currently limited to 1st coding page
|
||||
void setMaxChars(int max);
|
||||
bool wasLastActionReturn();
|
||||
|
||||
// Widget interface.
|
||||
virtual void tick (double dtime);
|
||||
virtual bool on_event(const SDL_Event &/*e*/);
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
|
||||
protected:
|
||||
double cursorTime;
|
||||
bool showCursor;
|
||||
|
||||
private:
|
||||
std::string textPreCursor;
|
||||
std::string textPostCursor;
|
||||
/**
|
||||
* a byte vector describing for each utf-8 character the number of
|
||||
* occupied bytes in the string.
|
||||
*/
|
||||
std::vector<unsigned char> charSizesPreCursor;
|
||||
|
||||
/**
|
||||
* a byte vector describing for each utf-8 character the number of
|
||||
* occupied bytes in the string. This vector is in reverse order to
|
||||
* the string itself!!
|
||||
*/
|
||||
std::vector<unsigned char> charSizesPostCursor;
|
||||
bool isLimitedToValidChars;
|
||||
std::string validChars;
|
||||
std::string invalidChars;
|
||||
int maxChars;
|
||||
bool isLastActionReturn;
|
||||
static ecl::Font *menufont;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
943
project/jni/application/enigma/src/gui/widgets.cpp
Normal file
943
project/jni/application/enigma/src/gui/widgets.cpp
Normal file
@@ -0,0 +1,943 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* 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/widgets.hh"
|
||||
#include "enigma.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "options.hh"
|
||||
#include "nls.hh"
|
||||
#include "ecl.hh"
|
||||
#include "ecl_font.hh"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <climits>
|
||||
|
||||
using namespace enigma::gui;
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
#define SCREEN ecl::Screen::get_instance()
|
||||
|
||||
/* -------------------- Widget -------------------- */
|
||||
|
||||
Widget::Widget(Container *parent)
|
||||
: area(), m_parent(parent), m_listener(0)
|
||||
{}
|
||||
|
||||
void Widget::invalidate() {
|
||||
if (m_parent)
|
||||
m_parent->invalidate_area(get_area());
|
||||
}
|
||||
void Widget::invalidate_area(const ecl::Rect& r) {
|
||||
if (m_parent)
|
||||
m_parent->invalidate_area(r);
|
||||
}
|
||||
|
||||
void Widget::reconfigure()
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->reconfigure_child(this);
|
||||
}
|
||||
|
||||
void Widget::invoke_listener() {
|
||||
if (m_listener)
|
||||
m_listener->on_action(this);
|
||||
}
|
||||
|
||||
void Widget::move(int x, int y) {
|
||||
area.x = x; area.y = y;
|
||||
}
|
||||
|
||||
void Widget::resize (int w, int h) {
|
||||
area.w = w; area.h = h;
|
||||
}
|
||||
|
||||
bool Widget::on_event(const SDL_Event &e) {
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
modifierKeys = e.key.keysym.mod;
|
||||
mouseButton = SDL_BUTTON_LEFT;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
modifierKeys = SDL_GetModState();
|
||||
mouseButton = e.button.button;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------- Image -------------------- */
|
||||
|
||||
void Image::draw (ecl::GC &gc, const ecl::Rect &/*r*/) {
|
||||
// if (ecl::Surface *s = enigma::GetImage(imgname.c_str()))
|
||||
// blit(gc, get_x(), get_y(), s);
|
||||
if (ecl::Surface *s = enigma::GetImage(imgname.c_str())) {
|
||||
int w=s->width();
|
||||
int h=s->height();
|
||||
int x = get_x() + (get_w()-w)/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
blit(gc, x, y, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- AreaManager -------------------- */
|
||||
|
||||
AreaManager::AreaManager(Container *c)
|
||||
: top_container(c)
|
||||
{
|
||||
assert(top_container->get_parent() == 0); // otherwise it's not the top_container
|
||||
}
|
||||
|
||||
void AreaManager::invalidate_area(const ecl::Rect &r) {
|
||||
dirtyrects.add(r);
|
||||
}
|
||||
|
||||
void AreaManager::invalidate_all() {
|
||||
dirtyrects.clear();
|
||||
dirtyrects.push_back(SCREEN->size());
|
||||
}
|
||||
|
||||
void AreaManager::refresh() {
|
||||
if (!dirtyrects.empty()) {
|
||||
video::HideMouse();
|
||||
GC gc(SCREEN->get_surface());
|
||||
for (RectList::iterator i = dirtyrects.begin(); i!=dirtyrects.end(); ++i) {
|
||||
top_container->draw(gc, *i);
|
||||
SCREEN->update_rect(*i);
|
||||
}
|
||||
video::ShowMouse();
|
||||
dirtyrects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- Container -------------------- */
|
||||
|
||||
Container::Container()
|
||||
: managed_by(0)
|
||||
{
|
||||
}
|
||||
Container::~Container() {
|
||||
clear();
|
||||
delete managed_by;
|
||||
}
|
||||
|
||||
AreaManager *Container::getAreaManager() {
|
||||
if (Container *p = get_parent()) {
|
||||
assert(!managed_by);
|
||||
return p->getAreaManager();
|
||||
}
|
||||
|
||||
if (!managed_by) {
|
||||
managed_by = new AreaManager(this);
|
||||
}
|
||||
return managed_by;
|
||||
}
|
||||
|
||||
void Container::invalidate_area(const ecl::Rect &r) { getAreaManager()->invalidate_area(r); }
|
||||
void Container::invalidate_all() { getAreaManager()->invalidate_all(); }
|
||||
void Container::refresh() { getAreaManager()->refresh(); }
|
||||
|
||||
void Container::clear() {
|
||||
delete_sequence(m_widgets.begin(), m_widgets.end());
|
||||
m_widgets.clear();
|
||||
}
|
||||
|
||||
void Container::add_child (Widget *w) {
|
||||
if (w && w != this) {
|
||||
m_widgets.push_back(w);
|
||||
w->set_parent(this);
|
||||
// w->move (get_x() + w->get_x(),
|
||||
// get_y() + w->get_y());
|
||||
}
|
||||
}
|
||||
|
||||
void Container::remove_child (Widget *w) {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
if (*it == w) {
|
||||
m_widgets.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Container::exchange_child (Widget *oldChild, Widget *newChild) {
|
||||
for (int i = 0; i < m_widgets.size(); i++) {
|
||||
if (m_widgets[i] == oldChild) {
|
||||
m_widgets[i] = newChild;
|
||||
newChild->set_parent(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Container::draw (ecl::GC& gc, const ecl::Rect &r) {
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
Rect rr = intersect(r, w->get_area());
|
||||
clip(gc, rr);
|
||||
w->draw(gc,rr);
|
||||
}
|
||||
}
|
||||
|
||||
void Container::draw_all() {
|
||||
invalidate_all();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void Container::reconfigure_child (Widget *)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Widget * Container::find_widget(int x, int y) {
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
if (w->get_area().contains(x,y)) {
|
||||
Container *c = dynamic_cast<Container *> (w);
|
||||
if (c) {
|
||||
w = c->find_widget (x, y);
|
||||
return w ? w : c;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Widget * Container::find_adjacent_widget(Widget *from, int x, int y) {
|
||||
// valid values for x/y : 1/0, -1/0, 0/1, 0/-1
|
||||
assert(from && x>=-1 && x<=1 && y>=-1 && y<=1 && abs(x+y) == 1);
|
||||
|
||||
if (!from) return 0;
|
||||
|
||||
int best_distance = INT_MAX;
|
||||
Widget *best_widget = 0;
|
||||
ecl::Rect farea = from->get_area();
|
||||
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
ecl::Rect warea = w->get_area();
|
||||
bool adjacent = true;
|
||||
int distance = 0;
|
||||
|
||||
if (x) { // check for y-overlap
|
||||
if (farea.y>(warea.y+warea.h-1) || warea.y>(farea.y+farea.h-1)) {
|
||||
adjacent = false;
|
||||
}
|
||||
else {
|
||||
distance = (warea.x-farea.x)*x;
|
||||
}
|
||||
}
|
||||
else { // check for x-overlap
|
||||
if (farea.x>(warea.x+warea.h-1) || warea.x>(farea.x+farea.h-1)) {
|
||||
adjacent = false;
|
||||
}
|
||||
else {
|
||||
distance = (warea.y-farea.y)*y;
|
||||
}
|
||||
}
|
||||
|
||||
if (adjacent && distance>0 && distance<best_distance) {
|
||||
best_distance = distance;
|
||||
best_widget = w;
|
||||
}
|
||||
}
|
||||
|
||||
return best_widget;
|
||||
}
|
||||
|
||||
void Container::move (int x, int y) {
|
||||
Rect a = get_area();
|
||||
a.x = x;
|
||||
a.y = y;
|
||||
this->set_area (a);
|
||||
|
||||
int dx = x-get_x();
|
||||
int dy = y-get_y();
|
||||
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
w->move(dx + w->get_x(), dy+w->get_y());
|
||||
}
|
||||
}
|
||||
|
||||
ecl::Rect Container::boundingbox() {
|
||||
if (!m_widgets.empty()) {
|
||||
iterator i=begin();
|
||||
Rect bbox=(*i)->get_area();
|
||||
for (++i; i!=end(); ++i)
|
||||
bbox = ecl::boundingbox(bbox, (*i)->get_area());
|
||||
return bbox;
|
||||
} else
|
||||
return get_area();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- List -------------------- */
|
||||
|
||||
List::List (int spacing)
|
||||
: m_spacing(spacing),
|
||||
has_default_size (false),
|
||||
defaultw (0),
|
||||
defaulth (0),
|
||||
m_halign (HALIGN_LEFT),
|
||||
m_valign (VALIGN_TOP)
|
||||
{}
|
||||
|
||||
void List::remove_child (Widget *w) {
|
||||
Container::remove_child(w);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::exchange_child(Widget *oldChild, Widget *newChild) {
|
||||
Container::exchange_child(oldChild, newChild);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::set_spacing (int pixels)
|
||||
{
|
||||
m_spacing = pixels;
|
||||
}
|
||||
|
||||
int List::get_spacing () const
|
||||
{
|
||||
return m_spacing;
|
||||
}
|
||||
|
||||
int List::calc_minimum_height() const
|
||||
{
|
||||
int sum=0;
|
||||
const WidgetList &wl = m_widgets;
|
||||
if (!wl.empty()) {
|
||||
sum = (wl.size() - 1) * m_spacing;
|
||||
for (WidgetList::const_iterator i=wl.begin(); i!=wl.end(); ++i) {
|
||||
int nw, nh;
|
||||
get_size (*i, nw, nh);
|
||||
sum += nh;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int List::calc_minimum_width () const
|
||||
{
|
||||
int sum=0;
|
||||
const WidgetList &wl = m_widgets;
|
||||
if (!wl.empty()) {
|
||||
sum = (wl.size() - 1) * m_spacing;
|
||||
for (WidgetList::const_iterator i=wl.begin(); i!=wl.end(); ++i) {
|
||||
int nw, nh;
|
||||
get_size (*i, nw, nh);
|
||||
sum += nw;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void List::set_default_size (int w, int h)
|
||||
{
|
||||
has_default_size = true;
|
||||
defaultw = w;
|
||||
defaulth = h;
|
||||
}
|
||||
|
||||
|
||||
void List::get_size (const Widget *widget, int &w, int &h) const
|
||||
{
|
||||
if (has_default_size)
|
||||
w = defaultw, h = defaulth;
|
||||
else
|
||||
widget->naturalsize (w, h);
|
||||
}
|
||||
|
||||
void List::resize (int w, int h)
|
||||
{
|
||||
Container::resize (w, h);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::move (int x, int y)
|
||||
{
|
||||
Container::move (x, y);
|
||||
// recalc();
|
||||
}
|
||||
|
||||
void List::reconfigure_child (Widget *w)
|
||||
{
|
||||
Container::reconfigure_child (w);
|
||||
recalc();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void List::add_back (Widget *w, ExpansionMode m)
|
||||
{
|
||||
add_child (w);
|
||||
m_expansionmodes.push_back (m);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::set_alignment (HAlignment halign, VAlignment valign)
|
||||
{
|
||||
if (halign != m_halign || valign != m_valign) {
|
||||
m_halign = halign;
|
||||
m_valign = valign;
|
||||
recalc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- HList -------------------- */
|
||||
|
||||
void HList::recalc()
|
||||
{
|
||||
int targetw = this->get_w(); // The available space
|
||||
int naturalw= calc_minimum_width();
|
||||
int excessw = targetw - naturalw;
|
||||
|
||||
int num_expand = std::count (m_expansionmodes.begin(),
|
||||
m_expansionmodes.end(),
|
||||
List::EXPAND);
|
||||
|
||||
WidgetList::iterator i = m_widgets.begin(),
|
||||
end = m_widgets.end();
|
||||
int x = get_x(), y = get_y();
|
||||
size_t j = 0;
|
||||
|
||||
if (num_expand == 0 && excessw > 0) {
|
||||
switch (m_halign) {
|
||||
case HALIGN_CENTER:
|
||||
x += excessw / 2;
|
||||
excessw = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i != end; ++i, ++j) {
|
||||
int w, h;
|
||||
List::get_size (*i, w, h);
|
||||
|
||||
if (excessw > 0 && m_expansionmodes[j] == List::EXPAND) {
|
||||
w += excessw / num_expand;
|
||||
excessw -= excessw / num_expand;
|
||||
num_expand -= 1;
|
||||
}
|
||||
(*i)->move (x, y);
|
||||
(*i)->resize (w, get_h());
|
||||
x += w + get_spacing();
|
||||
}
|
||||
}
|
||||
|
||||
bool HList::fits() {
|
||||
int targetw = this->get_w(); // The available space
|
||||
int naturalw= calc_minimum_width();
|
||||
return targetw >= naturalw;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- VList -------------------- */
|
||||
|
||||
void VList::recalc()
|
||||
{
|
||||
int targeth = this->get_h(); // The available space
|
||||
int naturalh= calc_minimum_height();
|
||||
int excessh = targeth - naturalh;
|
||||
|
||||
int num_expand = std::count (m_expansionmodes.begin(),
|
||||
m_expansionmodes.end(),
|
||||
List::EXPAND);
|
||||
|
||||
WidgetList::iterator i = m_widgets.begin(),
|
||||
end = m_widgets.end();
|
||||
int x = get_x(), y = get_y();
|
||||
size_t j = 0;
|
||||
|
||||
if (num_expand == 0 && excessh > 0) {
|
||||
switch (m_valign) {
|
||||
case VALIGN_CENTER:
|
||||
y += excessh / 2;
|
||||
excessh = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i != end; ++i, ++j) {
|
||||
int w, h;
|
||||
List::get_size (*i, w, h);
|
||||
|
||||
if (excessh > 0 && m_expansionmodes[j] == List::EXPAND) {
|
||||
h += excessh / num_expand;
|
||||
excessh -= excessh / num_expand;
|
||||
num_expand -= 1;
|
||||
}
|
||||
(*i)->move (x, y);
|
||||
(*i)->resize (get_w(), h);
|
||||
y += h + get_spacing();
|
||||
}
|
||||
}
|
||||
|
||||
bool VList::fits() {
|
||||
int targeth = this->get_h(); // The available space
|
||||
int naturalh= calc_minimum_height();
|
||||
return targeth >= naturalh;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Label -------------------- */
|
||||
|
||||
Label::Label (const std::string &text,
|
||||
HAlignment halign,
|
||||
VAlignment valign)
|
||||
: m_text (text),
|
||||
m_font(enigma::GetFont("menufont")),
|
||||
m_halign(halign),
|
||||
m_valign(valign)
|
||||
{}
|
||||
|
||||
|
||||
void Label::set_text (const std::string &text) {
|
||||
if (text != m_text) {
|
||||
m_text = text;
|
||||
reconfigure();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
string Label::get_text() const {
|
||||
return _(m_text.c_str());
|
||||
}
|
||||
|
||||
string Label::getText() const {
|
||||
return m_text;
|
||||
}
|
||||
|
||||
void Label::set_font (ecl::Font *font) {
|
||||
if (m_font != font) {
|
||||
m_font = font;
|
||||
reconfigure();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
bool Label::text_fits(double area_fraction) {
|
||||
int w, h;
|
||||
naturalsize (w, h);
|
||||
return w <= get_w()*area_fraction;
|
||||
}
|
||||
|
||||
void Label::draw (ecl::GC &gc, const ecl::Rect &)
|
||||
{
|
||||
Font *f = m_font;
|
||||
int w, h;
|
||||
naturalsize (w, h);
|
||||
|
||||
int x = get_x(), y=get_y();
|
||||
switch (m_halign) {
|
||||
case HALIGN_LEFT: break;
|
||||
case HALIGN_RIGHT: x += get_w() - w; break;
|
||||
case HALIGN_CENTER: x += (get_w()-w)/2; break;
|
||||
}
|
||||
switch (m_valign) {
|
||||
case VALIGN_TOP: break;
|
||||
case VALIGN_BOTTOM: y += get_h() - h; break;
|
||||
case VALIGN_CENTER: y += (get_h()-h)/2; break;
|
||||
}
|
||||
// translate if not an empty string
|
||||
f->render (gc, x, y, m_text == "" ? "" : get_text().c_str());
|
||||
}
|
||||
|
||||
void Label::set_alignment (HAlignment halign, VAlignment valign) {
|
||||
if (halign != m_halign || valign != m_valign) {
|
||||
m_halign = halign;
|
||||
m_valign = valign;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void Label::naturalsize (int &w, int &h) const
|
||||
{
|
||||
h = m_font->get_height();
|
||||
// width of translation if not an empty string
|
||||
w = m_font->get_width (m_text == "" ? "" : get_text().c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- UntranslatedLabel -------------------- */
|
||||
|
||||
UntranslatedLabel::UntranslatedLabel (const std::string &text,
|
||||
HAlignment halign, VAlignment valign) : Label(text, halign, valign) {
|
||||
}
|
||||
|
||||
string UntranslatedLabel::get_text() const {
|
||||
return Label::m_text;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Button -------------------- */
|
||||
|
||||
Button::Button() : m_activep (false), highlight (false) {
|
||||
}
|
||||
|
||||
void Button::activate()
|
||||
{
|
||||
sound::EmitSoundEvent ("menuswitch");
|
||||
m_activep = true;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Button::deactivate() {
|
||||
m_activep = false;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Button::setHighlight(bool shouldHighlight) {
|
||||
highlight = shouldHighlight;
|
||||
invalidate();
|
||||
}
|
||||
bool Button::isHighlight() {
|
||||
return highlight;
|
||||
}
|
||||
|
||||
void Button::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
const int borderw = 4;
|
||||
|
||||
ecl::Surface *s = enigma::GetImage (m_activep ? "buttonhl" : "button");
|
||||
|
||||
if (s) { // Ugly, but hey, it works
|
||||
Rect srcrect (0,0,borderw, borderw);
|
||||
Rect area = get_area();
|
||||
|
||||
// background
|
||||
if (highlight)
|
||||
set_color (gc, 70, 70, 70);
|
||||
else
|
||||
set_color (gc, 0,0,0);
|
||||
box (gc, smaller(area, borderw));
|
||||
|
||||
set_color (gc, 0,0,0);
|
||||
// corners
|
||||
blit (gc, area.x, area.y, s, srcrect);
|
||||
srcrect.x += s->width()-borderw;
|
||||
blit (gc, area.x+area.w-borderw, area.y, s, srcrect);
|
||||
srcrect.x = 0;
|
||||
srcrect.y += s->height()-borderw;
|
||||
blit (gc, area.x, area.y+area.h-borderw, s, srcrect);
|
||||
srcrect.x += s->width()-borderw;
|
||||
blit (gc, area.x+area.w-borderw, area.y+area.h-borderw, s, srcrect);
|
||||
|
||||
// horizontal borders
|
||||
{
|
||||
int tilew = s->width() - 2*borderw;
|
||||
int ntiles = (area.w - 2*borderw) / tilew;
|
||||
int x = area.x + borderw;
|
||||
for (int i=0; i<ntiles; ++i) {
|
||||
blit (gc, x, area.y, s, Rect (borderw, 0, tilew, borderw));
|
||||
blit (gc, x, area.y+area.h-borderw, s,
|
||||
Rect (borderw, s->height()-borderw, tilew, borderw));
|
||||
x += tilew;
|
||||
}
|
||||
int restw = (area.w - 2*borderw) - tilew*ntiles;
|
||||
blit (gc, x, area.y, s, Rect (borderw, 0, restw, borderw));
|
||||
blit (gc, x, area.y+area.h-borderw, s,
|
||||
Rect (borderw, s->height()-borderw, restw, borderw));
|
||||
}
|
||||
// vertical borders
|
||||
{
|
||||
int tileh = s->height() - 2*borderw;
|
||||
int ntiles = (area.h - 2*borderw) / tileh;
|
||||
int y = area.y + borderw;
|
||||
for (int i=0; i<ntiles; ++i) {
|
||||
blit (gc, area.x, y, s, Rect (0, borderw, borderw, tileh));
|
||||
blit (gc, area.x+area.w-borderw, y, s,
|
||||
Rect (s->width()-borderw, borderw, borderw, tileh));
|
||||
y += tileh;
|
||||
}
|
||||
int resth = (area.h - 2*borderw) - tileh*ntiles;
|
||||
blit (gc, area.x, y, s, Rect (0, borderw, borderw, resth));
|
||||
blit (gc, area.x+area.w-borderw, y, s,
|
||||
Rect (s->width()-borderw, borderw, borderw, resth));
|
||||
}
|
||||
}
|
||||
else {
|
||||
set_color (gc, 0,0,0);
|
||||
box (gc, r);
|
||||
set_color (gc, 160,160,160);
|
||||
frame (gc, r);
|
||||
frame (gc, smaller(r, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- PushButton -------------------- */
|
||||
|
||||
PushButton::PushButton() : m_pressedp (false) {
|
||||
}
|
||||
|
||||
bool PushButton::on_event(const SDL_Event &e) {
|
||||
Widget::on_event(e);
|
||||
bool was_pressed = m_pressedp;
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
if (e.key.keysym.sym != SDLK_RETURN &&
|
||||
e.key.keysym.sym != SDLK_SPACE) break;
|
||||
// fall-through
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
m_pressedp = true;
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
if (e.key.keysym.sym != SDLK_RETURN &&
|
||||
e.key.keysym.sym != SDLK_SPACE &&
|
||||
e.key.keysym.sym != SDLK_PAGEDOWN &&
|
||||
e.key.keysym.sym != SDLK_PAGEUP) break;
|
||||
lastUpSym = e.key.keysym.sym;
|
||||
lastUpBotton = 0;
|
||||
m_pressedp = false;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
lastUpSym = SDLK_UNKNOWN;
|
||||
lastUpBotton = e.button.button;
|
||||
m_pressedp = false;
|
||||
break;
|
||||
}
|
||||
|
||||
bool changed = (was_pressed != m_pressedp);
|
||||
if (changed) {
|
||||
invalidate();
|
||||
if (!m_pressedp) {
|
||||
if (soundOk())
|
||||
sound::EmitSoundEvent("menuok");
|
||||
invoke_listener();
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void PushButton::deactivate() {
|
||||
m_pressedp = false;
|
||||
lastUpSym = SDLK_UNKNOWN;
|
||||
lastUpBotton = 0;
|
||||
invalidate();
|
||||
Button::deactivate();
|
||||
}
|
||||
|
||||
SDLKey PushButton::getLastUpSym() {
|
||||
return lastUpSym;
|
||||
}
|
||||
|
||||
Uint8 PushButton::getLastUpButton() {
|
||||
return lastUpBotton;
|
||||
}
|
||||
|
||||
bool PushButton::soundOk() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------- TextButton -------------------- */
|
||||
|
||||
ecl::Font *TextButton::menufont = 0;
|
||||
ecl::Font *TextButton::menufont_pressed = 0;
|
||||
|
||||
TextButton::TextButton(ActionListener *al) {
|
||||
if (menufont == 0) {
|
||||
menufont = enigma::GetFont("menufont");
|
||||
menufont_pressed = enigma::GetFont("menufontsel");
|
||||
}
|
||||
set_listener(al);
|
||||
}
|
||||
|
||||
void TextButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
Button::draw(gc,r);
|
||||
Font *f = is_pressed() ? menufont_pressed : menufont;
|
||||
string text = get_text();
|
||||
int h = f->get_height();
|
||||
int w = f->get_width(text.c_str());
|
||||
int x = get_x() + (get_w()-w)/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
|
||||
f->render (gc, x, y, text.c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- StaticTextButton -------------------- */
|
||||
|
||||
StaticTextButton::StaticTextButton(const string &t, ActionListener *al)
|
||||
: TextButton(al),
|
||||
text(t)
|
||||
{
|
||||
}
|
||||
|
||||
void StaticTextButton::set_text(const std::string &t) {
|
||||
if (t != text) {
|
||||
text = t;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
string StaticTextButton::get_text() const {
|
||||
return _(text.c_str()); // translate
|
||||
}
|
||||
|
||||
/* -------------------- UntranslatedStaticTextButton -------------------- */
|
||||
|
||||
UntranslatedStaticTextButton::UntranslatedStaticTextButton(const string &t,
|
||||
ActionListener *al)
|
||||
: StaticTextButton(t, al)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
string UntranslatedStaticTextButton::get_text() const {
|
||||
return StaticTextButton::text;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Buttons for Options -------------------- */
|
||||
|
||||
BoolOptionButton::BoolOptionButton(const char *option_name,
|
||||
const string& true_text, const string& false_text,
|
||||
ActionListener *al)
|
||||
: TextButton(al),
|
||||
optionName(option_name),
|
||||
trueText(true_text),
|
||||
falseText(false_text)
|
||||
{
|
||||
}
|
||||
|
||||
bool BoolOptionButton::toggle() {
|
||||
bool newval = !enigma_options::GetBool(optionName);
|
||||
enigma_options::SetOption(optionName, newval);
|
||||
invalidate();
|
||||
return newval;
|
||||
}
|
||||
|
||||
void BoolOptionButton::on_action(Widget *) {
|
||||
toggle();
|
||||
}
|
||||
|
||||
string BoolOptionButton::get_text() const {
|
||||
return enigma_options::GetBool(optionName) ? _(trueText.c_str()) : _(falseText.c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- ValueButton -------------------- */
|
||||
|
||||
ValueButton::ValueButton(int min_value_, int max_value_)
|
||||
: TextButton(this),
|
||||
min_value(min_value_),
|
||||
max_value(max_value_)
|
||||
{
|
||||
}
|
||||
|
||||
void ValueButton::setMaxValue(int max) {
|
||||
max_value = max;
|
||||
}
|
||||
|
||||
void ValueButton::init() {
|
||||
update_value(-1, get_value()); // fixes wrong values (e.g. from .enimarc)
|
||||
}
|
||||
|
||||
bool ValueButton::inc_value(int offset) {
|
||||
int old_value = get_value();
|
||||
return update_value(old_value, old_value+offset);
|
||||
}
|
||||
|
||||
string ValueButton::get_text() const {
|
||||
return get_text(get_value());
|
||||
}
|
||||
|
||||
bool ValueButton::update_value(int old_value, int new_value) {
|
||||
new_value = Clamp(new_value, min_value, max_value);
|
||||
if (new_value != old_value) {
|
||||
set_value(new_value);
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ValueButton::on_action(Widget *) {
|
||||
int incr = 1;
|
||||
bool stop = false;
|
||||
if (getLastUpSym() == SDLK_PAGEDOWN || getLastUpButton() == SDL_BUTTON_RIGHT ||
|
||||
getLastUpButton() == 5) { // wheel down
|
||||
incr = -1;
|
||||
}
|
||||
if (getLastUpSym() == SDLK_PAGEDOWN || getLastUpSym() == SDLK_PAGEUP ||
|
||||
getLastUpButton() == SDL_BUTTON_RIGHT ||
|
||||
getLastUpButton() == 4 || getLastUpButton() == 5) {
|
||||
stop = true;
|
||||
}
|
||||
if (inc_value(incr)) {
|
||||
sound::EmitSoundEvent("menuswitch");
|
||||
} else {
|
||||
if (stop) {
|
||||
sound::EmitSoundEvent("menustop");
|
||||
} else {
|
||||
sound::EmitSoundEvent("menuswitch");
|
||||
if (incr == 1)
|
||||
update_value(get_value(), min_value);
|
||||
else
|
||||
update_value(get_value(), max_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ValueButton::soundOk() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- ImageButton -------------------- */
|
||||
|
||||
ImageButton::ImageButton(const string &unselected,
|
||||
const string &selected,
|
||||
ActionListener *al)
|
||||
: fname_sel(selected), fname_unsel(unselected)
|
||||
{
|
||||
set_listener(al);
|
||||
}
|
||||
|
||||
void ImageButton::set_images(const string &unselected, const string &selected) {
|
||||
fname_sel = selected;
|
||||
fname_unsel = unselected;
|
||||
}
|
||||
|
||||
void ImageButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
Button::draw(gc, r);
|
||||
string &fname = is_pressed() ? fname_sel : fname_unsel;
|
||||
|
||||
if (Surface *s = enigma::GetImage(fname.c_str())) {
|
||||
int w=s->width();
|
||||
int h=s->height();
|
||||
int x = get_x() + (get_w()-w)/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
blit(gc, x, y, s);
|
||||
}
|
||||
}
|
||||
465
project/jni/application/enigma/src/gui/widgets.hh
Normal file
465
project/jni/application/enigma/src/gui/widgets.hh
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003 Daniel Heck
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef WIDGETS_HH_INCLUDED
|
||||
#define WIDGETS_HH_INCLUDED
|
||||
|
||||
#include "ecl_fwd.hh"
|
||||
#include "ecl_geom.hh"
|
||||
#include "SDL.h"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
|
||||
/* -------------------- Alignment -------------------- */
|
||||
|
||||
enum HAlignment {
|
||||
HALIGN_LEFT,
|
||||
HALIGN_CENTER,
|
||||
HALIGN_RIGHT
|
||||
};
|
||||
|
||||
enum VAlignment {
|
||||
VALIGN_TOP,
|
||||
VALIGN_CENTER,
|
||||
VALIGN_BOTTOM
|
||||
};
|
||||
|
||||
/* -------------------- Events & Event Handlers -------------------- */
|
||||
class Widget;
|
||||
|
||||
class ActionListener {
|
||||
public:
|
||||
virtual ~ActionListener() {}
|
||||
virtual void on_action(Widget *) {};
|
||||
};
|
||||
|
||||
/* -------------------- GUI Widgets -------------------- */
|
||||
|
||||
class Container;
|
||||
|
||||
class Widget : public ActionListener {
|
||||
public:
|
||||
|
||||
/* ---------- Widget interface ---------- */
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r) = 0;
|
||||
virtual void activate() {}
|
||||
virtual void deactivate() {}
|
||||
|
||||
virtual void realize (const ecl::Rect &r) {
|
||||
set_area (r);
|
||||
}
|
||||
|
||||
virtual bool on_event(const SDL_Event &/*e*/);
|
||||
Uint8 lastMouseButton() {return mouseButton;}
|
||||
SDLMod lastModifierKeys() { return modifierKeys; }
|
||||
|
||||
|
||||
virtual void move (int x, int y);
|
||||
virtual void resize (int w, int h);
|
||||
|
||||
virtual void naturalsize (int &w, int &h) const {
|
||||
w = h = 5;
|
||||
}
|
||||
|
||||
/* ---------- Accessors ---------- */
|
||||
void set_size(int w, int h) {area.w = w; area.h = h;}
|
||||
|
||||
ecl::Rect get_area() const { return area; }
|
||||
void set_area(const ecl::Rect &r) { area = r; }
|
||||
int get_x() const { return area.x; }
|
||||
int get_y() const { return area.y; }
|
||||
int get_w() const { return area.w; }
|
||||
int get_h() const { return area.h; }
|
||||
|
||||
void set_parent(Container *parent) { m_parent = parent; }
|
||||
Container *get_parent () const { return m_parent; }
|
||||
|
||||
void set_listener(ActionListener *al) {
|
||||
m_listener = al;
|
||||
}
|
||||
|
||||
void invalidate();
|
||||
virtual void tick (double /*dtime*/) {}
|
||||
|
||||
protected:
|
||||
Widget(Container *parent=0);
|
||||
|
||||
/* ---------- Functions ---------- */
|
||||
void reconfigure();
|
||||
void invalidate_area(const ecl::Rect &r);
|
||||
void invoke_listener();
|
||||
|
||||
private:
|
||||
ecl::Rect area;
|
||||
Container *m_parent;
|
||||
ActionListener *m_listener;
|
||||
SDLMod modifierKeys;
|
||||
Uint8 mouseButton;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* -------------------- EmptyWidget -------------------- */
|
||||
class EmptyWidget : public Widget {
|
||||
public:
|
||||
EmptyWidget () : Widget ()
|
||||
{}
|
||||
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r)
|
||||
{}
|
||||
|
||||
virtual void naturalsize (int &w, int &h) const {
|
||||
w = h = 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
/* -------------------- AreaManager -------------------- */
|
||||
|
||||
class AreaManaged {
|
||||
public:
|
||||
virtual ~AreaManaged() {}
|
||||
|
||||
virtual void invalidate_area(const ecl::Rect &r) = 0;
|
||||
virtual void invalidate_all() = 0;
|
||||
virtual void refresh() = 0;
|
||||
};
|
||||
|
||||
// The AreaManager perform refreshes of invalidated regions.
|
||||
// It gets attached to the top-level Container during the first invalidation
|
||||
// or refresh request.
|
||||
class AreaManager : public AreaManaged {
|
||||
public:
|
||||
AreaManager(Container *managed);
|
||||
|
||||
void invalidate_area(const ecl::Rect &r);
|
||||
void invalidate_all();
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
ecl::RectList dirtyrects;
|
||||
Container *top_container;
|
||||
};
|
||||
|
||||
/* -------------------- Container -------------------- */
|
||||
|
||||
class Container : public Widget, public AreaManaged {
|
||||
public:
|
||||
Container();
|
||||
~Container();
|
||||
|
||||
void add_child (Widget *w);
|
||||
virtual void remove_child (Widget *w);
|
||||
virtual void exchange_child (Widget *oldChild, Widget *newChild);
|
||||
virtual void reconfigure_child (Widget *w);
|
||||
|
||||
Widget *find_widget(int x, int y);
|
||||
Widget *find_adjacent_widget(Widget *from, int x, int y);
|
||||
|
||||
void clear();
|
||||
void draw_all();
|
||||
|
||||
// Widget interface.
|
||||
void draw (ecl::GC& gc, const ecl::Rect &r);
|
||||
void move (int x, int y);
|
||||
|
||||
// AreaManaged interface.
|
||||
void invalidate_area(const ecl::Rect &r);
|
||||
void invalidate_all();
|
||||
void refresh();
|
||||
|
||||
protected:
|
||||
typedef std::vector<Widget *> WidgetList;
|
||||
typedef WidgetList::iterator iterator;
|
||||
|
||||
iterator begin() { return m_widgets.begin(); }
|
||||
iterator end() { return m_widgets.end(); }
|
||||
WidgetList m_widgets;
|
||||
|
||||
private:
|
||||
ecl::Rect boundingbox();
|
||||
|
||||
AreaManager *getAreaManager();
|
||||
AreaManager *managed_by;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- List, HList, VList -------------------- */
|
||||
|
||||
class List : public Container {
|
||||
public:
|
||||
void set_spacing (int pixels);
|
||||
|
||||
enum ExpansionMode {
|
||||
EXPAND,
|
||||
TIGHT
|
||||
};
|
||||
|
||||
void add_back (Widget *w, ExpansionMode m = List::TIGHT);
|
||||
virtual void remove_child (Widget *w);
|
||||
virtual void exchange_child (Widget *oldChild, Widget *newChild);
|
||||
|
||||
void set_default_size (int w, int h);
|
||||
void set_alignment (HAlignment halign, VAlignment valign);
|
||||
virtual bool fits() = 0;
|
||||
|
||||
protected:
|
||||
List(int spacing=5);
|
||||
|
||||
int calc_minimum_height () const;
|
||||
int calc_minimum_width () const;
|
||||
|
||||
int get_spacing () const;
|
||||
|
||||
void get_size (const Widget *widget, int &w, int &h) const;
|
||||
|
||||
// ---------- Widget interface ----------
|
||||
virtual void move (int x, int y);
|
||||
virtual void resize(int w, int h);
|
||||
|
||||
// ---------- List interface ----------
|
||||
virtual void recalc() = 0;
|
||||
|
||||
// ---------- Container interface ----------
|
||||
virtual void reconfigure_child (Widget *w);
|
||||
|
||||
|
||||
protected:
|
||||
std::vector<ExpansionMode> m_expansionmodes;
|
||||
|
||||
private:
|
||||
int m_spacing; // # of pixels between container items
|
||||
bool has_default_size;
|
||||
int defaultw, defaulth;
|
||||
protected:
|
||||
HAlignment m_halign;
|
||||
VAlignment m_valign;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class HList : public List {
|
||||
public:
|
||||
HList() : List() {}
|
||||
virtual bool fits();
|
||||
|
||||
private:
|
||||
// List interface
|
||||
virtual void recalc();
|
||||
};
|
||||
|
||||
class VList : public List {
|
||||
public:
|
||||
VList() : List() {}
|
||||
virtual bool fits();
|
||||
|
||||
private:
|
||||
// List interface
|
||||
virtual void recalc();
|
||||
|
||||
};
|
||||
|
||||
/* -------------------- Image -------------------- */
|
||||
|
||||
class Image : public Widget {
|
||||
public:
|
||||
Image (const std::string &iname) : imgname(iname) {}
|
||||
void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
std::string imgname;
|
||||
};
|
||||
|
||||
/* -------------------- Label -------------------- */
|
||||
|
||||
class Label : public Widget {
|
||||
public:
|
||||
Label (const std::string &text="",
|
||||
HAlignment halign=HALIGN_CENTER,
|
||||
VAlignment valign=VALIGN_CENTER);
|
||||
|
||||
// Widget interface
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
virtual void naturalsize (int &w, int &h) const;
|
||||
|
||||
// Methods
|
||||
void set_text (const std::string &text);
|
||||
virtual std::string get_text() const; // translated
|
||||
std::string getText() const;
|
||||
void set_font (ecl::Font *font);
|
||||
void set_alignment (HAlignment halign, VAlignment valign=VALIGN_CENTER);
|
||||
bool text_fits(double area_fraction = 1.0);
|
||||
protected:
|
||||
// Variables.
|
||||
std::string m_text;
|
||||
ecl::Font *m_font;
|
||||
HAlignment m_halign;
|
||||
VAlignment m_valign;
|
||||
};
|
||||
|
||||
/* -------------------- UntranslatedLabel -------------------- */
|
||||
|
||||
class UntranslatedLabel : public Label {
|
||||
public:
|
||||
UntranslatedLabel(const std::string &text="",
|
||||
HAlignment halign=HALIGN_CENTER,
|
||||
VAlignment valign=VALIGN_CENTER);
|
||||
|
||||
// TextButton interface.
|
||||
virtual std::string get_text() const;
|
||||
};
|
||||
|
||||
/* -------------------- Button -------------------- */
|
||||
|
||||
class Button : public Widget {
|
||||
public:
|
||||
void setHighlight(bool shouldHighlight);
|
||||
bool isHighlight();
|
||||
protected:
|
||||
Button();
|
||||
|
||||
// Widget interface.
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
void activate();
|
||||
void deactivate();
|
||||
bool m_activep;
|
||||
bool highlight;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- PushButton -------------------- */
|
||||
|
||||
class PushButton : public Button {
|
||||
public:
|
||||
PushButton();
|
||||
|
||||
bool is_pressed() { return m_pressedp; }
|
||||
|
||||
protected:
|
||||
bool on_event(const SDL_Event &e);
|
||||
void deactivate();
|
||||
SDLKey getLastUpSym();
|
||||
Uint8 getLastUpButton();
|
||||
virtual bool soundOk();
|
||||
private:
|
||||
bool m_pressedp;
|
||||
SDLKey lastUpSym;
|
||||
Uint8 lastUpBotton;
|
||||
};
|
||||
|
||||
/* -------------------- TextButton -------------------- */
|
||||
|
||||
class TextButton : public PushButton {
|
||||
public:
|
||||
TextButton(ActionListener *al=0);
|
||||
virtual std::string get_text() const = 0;
|
||||
|
||||
private:
|
||||
// Widget interface.
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
|
||||
// Variables.
|
||||
static ecl::Font *menufont, *menufont_pressed;
|
||||
};
|
||||
|
||||
/* -------------------- StaticTextButton -------------------- */
|
||||
|
||||
class StaticTextButton : public TextButton {
|
||||
public:
|
||||
StaticTextButton(const std::string &t, ActionListener *al=0);
|
||||
virtual void set_text(const std::string &t);
|
||||
|
||||
// TextButton interface.
|
||||
std::string get_text() const;
|
||||
|
||||
protected:
|
||||
// Variables.
|
||||
std::string text;
|
||||
};
|
||||
|
||||
/* -------------------- UntranslatedStaticTextButton -------------------- */
|
||||
|
||||
class UntranslatedStaticTextButton : public StaticTextButton {
|
||||
public:
|
||||
UntranslatedStaticTextButton(const std::string &t, ActionListener *al=0);
|
||||
|
||||
// TextButton interface.
|
||||
std::string get_text() const;
|
||||
};
|
||||
|
||||
/* -------------------- BoolOptionButton -------------------- */
|
||||
class BoolOptionButton : public TextButton {
|
||||
public:
|
||||
BoolOptionButton(const char *option_name,
|
||||
const std::string& true_text,
|
||||
const std::string& false_text,
|
||||
ActionListener *al = 0);
|
||||
|
||||
bool toggle(); // returns new value
|
||||
void on_action(Widget *);
|
||||
|
||||
// TextButton interface.
|
||||
std::string get_text() const;
|
||||
|
||||
private:
|
||||
const char *optionName;
|
||||
std::string trueText;
|
||||
std::string falseText;
|
||||
};
|
||||
|
||||
/* -------------------- ValueButton -------------------- */
|
||||
class ValueButton: public TextButton {
|
||||
public:
|
||||
ValueButton(int min_value_, int max_value_);
|
||||
|
||||
virtual int get_value() const = 0;
|
||||
virtual void set_value(int value) = 0;
|
||||
void setMaxValue(int max);
|
||||
|
||||
bool inc_value(int offset);
|
||||
|
||||
// TextButton interface.
|
||||
virtual std::string get_text() const;
|
||||
|
||||
// Widget interface.
|
||||
virtual void on_action(Widget *w);
|
||||
protected:
|
||||
void init(); // called in ctor of derived
|
||||
virtual bool soundOk();
|
||||
private:
|
||||
int min_value;
|
||||
int max_value;
|
||||
|
||||
bool update_value(int old_value, int new_value);
|
||||
virtual std::string get_text(int value) const = 0;
|
||||
};
|
||||
|
||||
/* -------------------- ImageButton -------------------- */
|
||||
|
||||
class ImageButton : public PushButton {
|
||||
public:
|
||||
ImageButton(const std::string &unselected,
|
||||
const std::string &selected,
|
||||
ActionListener *al = 0);
|
||||
void set_images(const std::string &unselected, const std::string &selected);
|
||||
// Widget interface.
|
||||
virtual void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
std::string fname_sel, fname_unsel;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
Reference in New Issue
Block a user