252 lines
7.0 KiB
C++
252 lines
7.0 KiB
C++
/*
|
|
* 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>
|
|
|
|
#ifdef ANDROID
|
|
#include <SDL/SDL_mixer.h>
|
|
#endif
|
|
|
|
using namespace ecl;
|
|
using namespace std;
|
|
|
|
#define SCREEN ecl::Screen::get_instance()
|
|
|
|
namespace enigma { namespace gui {
|
|
|
|
#ifdef ANDROID
|
|
static bool playingMenuMusic = false;
|
|
|
|
static void appPutToBackgroundCallbackMenu(void) {
|
|
playingMenuMusic = false;
|
|
|
|
if(Mix_PlayingMusic()) {
|
|
playingMenuMusic = true;
|
|
Mix_PauseMusic();
|
|
}
|
|
}
|
|
|
|
static void appRestoredCallbackMenu(void) {
|
|
if(playingMenuMusic) {
|
|
playingMenuMusic = false;
|
|
Mix_ResumeMusic();
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/* -------------------- 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();
|
|
#ifdef ANDROID
|
|
int repaintCounter = 0;
|
|
playingMenuMusic = false;
|
|
SDL_ANDROID_SetApplicationPutToBackgroundCallback(appPutToBackgroundCallbackMenu, appRestoredCallbackMenu);
|
|
#endif
|
|
|
|
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);
|
|
#ifdef ANDROID
|
|
// repaint, needed if the app was restored
|
|
if(repaintCounter++ > 20) {
|
|
invalidate_all(); repaintCounter = 0;
|
|
}
|
|
#endif
|
|
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
|