Page MenuHomePhabricator (Chris)

No OneTemporary

Size
127 KB
Referenced Files
None
Subscribers
None
diff --git a/util/input/allegro/allegro-joystick.cpp b/util/input/allegro/allegro-joystick.cpp
index a4c07cc8..0a888b80 100644
--- a/util/input/allegro/allegro-joystick.cpp
+++ b/util/input/allegro/allegro-joystick.cpp
@@ -1,62 +1,71 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
#include "allegro-joystick.h"
+#include <string>
+
+using std::string;
+
void AllegroJoystick::poll(){
::poll_joystick();
}
/*
JoystickInput AllegroJoystick::readAll(){
JoystickInput input;
JOYSTICK_INFO * info = &joy[0];
switch(info->num_buttons > 4 ? 4 : info->num_buttons){
case 4: input.button4 = info->button[3].b;
case 3: input.button3 = info->button[2].b;
case 2: input.button2 = info->button[1].b;
case 1: input.button1 = info->button[0].b;
case 0: {
break;
}
}
for (int stick = 0; stick < info->num_sticks; stick++){
JOYSTICK_STICK_INFO * this_stick = &info->stick[stick];
if (this_stick->num_axis > 0){
int position = this_stick->axis[0].pos;
if (position < 0){
input.left = true;
} else if (position > 0){
input.right = true;
}
}
if (this_stick->num_axis > 1){
int position = this_stick->axis[1].pos;
if (position < 0){
input.up = true;
} else if (position > 0){
input.down = true;
}
}
}
return input;
}
*/
AllegroJoystick::~AllegroJoystick(){
}
AllegroJoystick::AllegroJoystick(){
}
int AllegroJoystick::getDeviceId() const {
return 0;
}
+string AllegroJoystick::getName() const {
+ /* FIXME */
+ return "unknown";
+}
+
int Joystick::numberOfJoysticks(){
return ::num_joysticks;
}
#endif
diff --git a/util/input/allegro/allegro-joystick.h b/util/input/allegro/allegro-joystick.h
index d0fcc463..4d385c24 100644
--- a/util/input/allegro/allegro-joystick.h
+++ b/util/input/allegro/allegro-joystick.h
@@ -1,18 +1,20 @@
#ifndef _paintown_allegro_joystick_h
#define _paintown_allegro_joystick_h
#include "../joystick.h"
+#include <string>
class AllegroJoystick: public Joystick {
public:
virtual void poll();
virtual int getDeviceId() const;
+ virtual std::string getName() const;
virtual ~AllegroJoystick();
friend class Joystick;
protected:
AllegroJoystick();
};
#endif
diff --git a/util/input/input-manager.cpp b/util/input/input-manager.cpp
index 5cf12924..a46d0f3d 100644
--- a/util/input/input-manager.cpp
+++ b/util/input/input-manager.cpp
@@ -1,145 +1,153 @@
#include "input-manager.h"
#include "configuration.h"
#include "joystick.h"
#include "util/events.h"
#include "globals.h"
#include "util/debug.h"
#include <stdlib.h>
#include <vector>
using namespace std;
InputManager * InputManager::manager = 0;
InputManager::InputManager():
capture(0){
manager = this;
if (Configuration::isJoystickEnabled()){
installJoysticks();
}
}
void InputManager::installJoysticks(){
joysticks.clear();
for (int i = 0; i < Joystick::numberOfJoysticks(); i++){
joysticks[i] = Joystick::create(i);
}
}
+
+const std::map<int, Util::ReferenceCount<Joystick> > & InputManager::getJoysticks(){
+ if (manager != NULL){
+ return manager->joysticks;
+ }
+ Global::debug(0) << "*BUG* Input manager not set up" << endl;
+ exit(0);
+}
#ifdef PS3
#include <io/pad.h>
extern "C" int SDL_JoystickInit();
extern "C" int SDL_JoystickQuit();
#endif
static bool needJoystickUpdate(){
#ifdef PS3
padInfo pad;
if (ioPadGetInfo(&pad) == 0){
/* re-initialize the joystick stuff if we have a different
* number of joysticks according to lv2
*/
if (pad.connected != (unsigned) SDL_NumJoysticks()){
SDL_JoystickQuit();
SDL_JoystickInit();
return true;
}
}
#endif
return false;
}
void InputManager::checkJoysticks(){
if (needJoystickUpdate()){
installJoysticks();
}
}
InputManager::~InputManager(){
}
void InputManager::deferResizeEvents(bool defer){
if (manager != NULL){
manager->eventManager.deferResizeEvents(defer);
}
}
bool InputManager::anyInput(){
if (manager == 0){
Global::debug(0) << "*BUG* Input manager not set up" << endl;
exit(0);
}
return manager->_anyInput();
}
bool InputManager::_anyInput(){
if (keyboard.keypressed()){
return true;
}
for (map<int, Util::ReferenceCount<Joystick> >::iterator it = joysticks.begin(); it != joysticks.end(); it++){
Util::ReferenceCount<Joystick> joystick = it->second;
if (joystick != NULL){
return joystick->pressed();
}
}
return false;
}
void InputManager::waitForClear(){
manager->keyboard.clear();
while (anyInput()){
poll();
Util::rest(1);
}
}
void InputManager::waitForKeys(int key1, int key2, const InputSource & source){
InputMap<int> wait;
wait.set(key1, 0, false, 1);
wait.set(key2, 0, false, 1);
InputManager::waitForRelease(wait, source, 1);
InputManager::waitForPress(wait, source, 1);
InputManager::waitForRelease(wait, source, 1);
}
void InputManager::waitForKeys(int key, const InputSource & source){
InputMap<int> wait;
wait.set(key, 0, false, 1);
InputManager::waitForRelease(wait, source, 1);
InputManager::waitForPress(wait, source, 1);
InputManager::waitForRelease(wait, source, 1);
}
void InputManager::poll(){
if (manager == 0){
Global::debug(0) << "*BUG* Input manager not set up" << endl;
exit(0);
}
return manager->_poll();
}
int InputManager::readKey(){
return manager->_readKey();
}
int InputManager::_readKey(){
std::vector<int> keys;
do{
keyboard.readKeys(keys);
if (keys.size() == 0){
Util::rest(1);
poll();
}
} while (keys.size() == 0);
return keys.front();
}
void InputManager::_poll(){
#ifdef PS3
checkJoysticks();
#endif
eventManager.run(keyboard, joysticks);
}
diff --git a/util/input/input-manager.h b/util/input/input-manager.h
index 4994add9..e3860a07 100644
--- a/util/input/input-manager.h
+++ b/util/input/input-manager.h
@@ -1,311 +1,313 @@
#ifndef _paintown_input_manager
#define _paintown_input_manager
#include <vector>
#include <algorithm>
#include "input.h"
#include "input-map.h"
#include "input-source.h"
#include "util/funcs.h"
#include "util/pointer.h"
#include "util/events.h"
#include "keyboard.h"
#include "joystick.h"
#include "util/exceptions/exception.h"
class Configuration;
class InputSource;
template <class Output>
class InputHandler{
public:
InputHandler(){
}
virtual ~InputHandler(){
}
virtual void press(const Output & out, Keyboard::unicode_t unicode) = 0;
virtual void release(const Output & out, Keyboard::unicode_t unicode) = 0;
};
/* handles keyboard/joystick/whatever input during the game */
class InputManager{
public:
/* main has one instance of this and thats it.
* should the janitor have the reference instead?
*/
friend int paintown_main(int, char**);
friend int main(int, char **);
/* returns true if any input device is activated (keys pressed, joystick button */
static bool anyInput();
// static std::vector<Input::PaintownInput> getInput(const Configuration & configuration, const int facing);
static void poll();
/*
static void enableBufferInput();
static void disableBufferInput();
*/
static void waitForKeys(int key1, int key2, const InputSource & source);
static void waitForKeys(int key1, const InputSource & source);
static int readKey();
static void waitForClear();
static void deferResizeEvents(bool defer);
+
+ static const std::map<int, Util::ReferenceCount<Joystick> > & getJoysticks();
/*
template <class X>
static void observeKeyboard(InputMap<X> & input){
manager->keyboard.addObserver(InputMap<X>::observeKey, &input);
}
template <class X>
static void unObserveKeyboard(InputMap<X> & input){
manager->keyboard.removeObserver(InputMap<X>::observeKey, &input);
}
*/
static std::vector<Keyboard::unicode_t> readText(){
return manager->keyboard.readText();
}
template <typename X>
static std::vector<Keyboard::unicode_t> readText(InputMap<X> & input, typename InputMap<X>::Output & output){
return manager->_readText(input, output);
}
#if 0
template <typename X>
static typename InputMap<X>::Output getMap(InputMap<X> & input){
if (manager){
return manager->_getMap(input);
}
/* just crash hard.. who cares */
throw Exception::Base(__FILE__, __LINE__);
/* make the compiler happy about returning something */
return *(typename InputMap<X>::Output*)1;
}
#endif
template <typename X>
static typename std::vector<typename InputMap<X>::InputEvent> getEvents(InputMap<X> & input, const InputSource & source){
return manager->_getEvents(input, source);
}
template <typename X>
static void handleEvents(InputMap<X> & input, const InputSource & source, InputHandler<X> & handler){
typename std::vector<typename InputMap<X>::InputEvent> events = getEvents(input, source);
for (typename std::vector<typename InputMap<X>::InputEvent>::iterator it = events.begin(); it != events.end(); it++){
const typename InputMap<X>::InputEvent & event = *it;
if (event.enabled){
handler.press(event.out, event.unicode);
} else {
handler.release(event.out, event.unicode);
}
}
}
template <typename X>
static bool pressed(InputMap<X> & input, const InputSource & source, X out){
if (manager){
return manager->_pressed(input, source, out);
}
return false;
}
/* wait for a key to be released
* really this waits for all inputs that would result in `out'
* being generated to stop.
*/
template <typename X>
static void waitForRelease(InputMap<X> & input, const InputSource & source, X out){
while (InputManager::pressed(input, source, out)){
Util::rest(1);
InputManager::poll();
}
}
template <typename X>
static void waitForPress(InputMap<X> & input, const InputSource & source, X out){
while (!InputManager::pressed(input, source, out)){
Util::rest(1);
InputManager::poll();
}
}
template <typename X>
static void captureInput(InputMap<X> & input){
manager->_captureInput(input);
}
template <typename X>
static void releaseInput(InputMap<X> & input){
manager->_releaseInput(input);
}
protected:
InputManager();
virtual ~InputManager();
virtual bool _anyInput();
virtual int _readKey();
// virtual std::vector<Input::PaintownInput> _getInput(const Configuration & configuration, const int facing);
template <typename X>
void _captureInput(InputMap<X> & input){
capture = (void*) &input;
}
template <typename X>
void _releaseInput(InputMap<X> & input){
if (capture == (void*) &input){
capture = 0;
}
}
template <typename X>
std::vector<Keyboard::unicode_t> _readText(InputMap<X> & input, typename InputMap<X>::Output & output){
std::vector<Keyboard::unicode_t> text;
std::vector<Keyboard::KeyData> all = keyboard.readData();
for (std::vector<Keyboard::KeyData>::iterator it = all.begin(); it != all.end(); it++){
const Keyboard::KeyData & data = *it;
KeyState<X> * state = input.getState(data.key);
if (state != NULL && output[state->out]){
text.push_back(data.unicode);
}
}
return text;
}
void removeDuplicates(std::vector<int> & storage){
std::vector<int> output;
int last = -1;
for (std::vector<int>::iterator it = storage.begin(); it != storage.end(); it++){
if (*it != last){
output.push_back(*it);
last = *it;
}
}
storage = output;
}
template <typename X>
typename std::vector<typename InputMap<X>::InputEvent> _getEvents(InputMap<X> & input, const InputSource & source){
/* FIXME: get events from the source */
std::vector<typename InputMap<X>::InputEvent> events;
if (capture != NULL && capture != &input){
return events;
}
if (source.useKeyboard()){
const std::vector<typename Keyboard::KeyData> & buffer = keyboard.getBufferedKeys();
for (std::vector<Keyboard::KeyData>::const_iterator it = buffer.begin(); it != buffer.end(); it++){
const Keyboard::KeyData & data = *it;
Util::ReferenceCount<KeyState<X> > state = input.getState(data.key);
if (state != NULL){
events.push_back(typename InputMap<X>::InputEvent(state->out, data.unicode, data.enabled));
}
}
}
if (source.getJoystick() >= 0 && (unsigned) source.getJoystick() < joysticks.size()){
Util::ReferenceCount<Joystick> joystick = joysticks[source.getJoystick()];
if (joystick != NULL){
const std::vector<typename Joystick::Event> & joystickEvents = joystick->getEvents();
for (std::vector<Joystick::Event>::const_iterator it = joystickEvents.begin(); it != joystickEvents.end(); it++){
Joystick::Event event = *it;
Util::ReferenceCount<JoystickState<X> > state = input.getJoystickState(event.key);
if (state != NULL){
events.push_back(typename InputMap<X>::InputEvent(state->out, -1, event.enabled));
}
}
}
}
return events;
}
#if 0
template <typename X>
typename InputMap<X>::Output _getMap(InputMap<X> & input){
typename InputMap<X>::Output output;
if (capture != 0 && capture != &input){
return output;
}
std::vector<int> all_keys;
keyboard.readKeys(all_keys);
keyboard.readBufferedKeys(all_keys);
// all_keys.insert(all_keys.end(), bufferedKeys.begin(), bufferedKeys.end());
// all_keys.insert(all_keys.end(), keyboard.currentKeys().begin(), keyboard.currentKeys.end());
std::sort(all_keys.begin(), all_keys.end());
removeDuplicates(all_keys);
// std::unique(all_keys.begin(), all_keys.end());
// bufferedKeys.clear();
input.read(all_keys, &output);
/*
if (joystick != NULL){
JoystickInput all_joystick = joystick->readAll();
input.read(all_joystick, &output);
}
*/
/* just bumps an internal counter */
input.update();
return output;
}
#endif
template <typename X>
bool _pressed(InputMap<X> & input, const InputSource & source, X result){
/* FIXME: use the input source, luke */
if (capture != 0 && capture != &input){
return false;
}
std::vector<int> all_keys;
keyboard.readKeys(all_keys);
// all_keys.insert(all_keys.end(), bufferedKeys.begin(), bufferedKeys.end());
std::sort(all_keys.begin(), all_keys.end());
removeDuplicates(all_keys);
// bufferedKeys.clear();
bool out = false;
out = input.pressed(all_keys, result);
/*
if (joystick != NULL){
JoystickInput all_joystick = joystick->readAll();
out |= input.pressed(all_joystick, result);
}
*/
return out;
}
virtual void _poll();
protected:
void installJoysticks();
void checkJoysticks();
private:
static InputManager * manager;
void * capture;
std::map<int, Util::ReferenceCount<Joystick> > joysticks;
Keyboard keyboard;
Util::EventManager eventManager;
// std::vector<int> bufferedKeys;
// bool bufferKeys;
};
#endif
diff --git a/util/input/joystick.cpp b/util/input/joystick.cpp
index 9bc29fa3..e928c5ca 100644
--- a/util/input/joystick.cpp
+++ b/util/input/joystick.cpp
@@ -1,99 +1,100 @@
#include <stdlib.h>
#include "joystick.h"
/*
#ifdef LINUX
#include "linux_joystick.h"
#endif
*/
#ifdef USE_ALLEGRO
#include "allegro/allegro-joystick.h"
#endif
#ifdef USE_SDL
#ifdef WII
#include "wii/joystick.h"
#include "sdl/joystick.h"
#elif MINPSPW
#include "psp/joystick.h"
#else
#include "sdl/joystick.h"
#endif
#endif
Joystick * Joystick::create(int i){
#ifdef USE_ALLEGRO
return new AllegroJoystick();
#endif
#ifdef USE_SDL
#ifdef WII
return new SDLJoystick(i);
// return new WiiJoystick();
#elif MINPSPW
return new PSPJoystick();
#else
return new SDLJoystick(i);
#endif
#endif
+ /* TODO: support allegro5 joystick */
/*
#ifdef LINUX
return new LinuxJoystick();
#endif
return NULL;
*/
return NULL;
}
Joystick::Joystick(){
}
Joystick::~Joystick(){
}
const char * Joystick::keyToName(Key key){
switch (key){
case Invalid: return "Invalid";
case Up: return "Up";
case Down: return "Down";
case Left: return "Left";
case Right: return "Right";
case Button1: return "Button1";
case Button2: return "Button2";
case Button3: return "Button3";
case Button4: return "Button4";
case Button5: return "Button5";
case Button6: return "Button6";
case Start: return "Start";
case Quit: return "Quit";
}
return "Unknown";
}
bool Joystick::pressed() const {
return events.size() > 0;
}
void Joystick::pressButton(int button){
}
void Joystick::releaseButton(int button){
}
void Joystick::axisMotion(int axis, int motion){
}
void Joystick::hatMotion(int motion){
}
void Joystick::addListener(JoystickListener * listener){
listeners.insert(listener);
}
void Joystick::removeListener(JoystickListener * listener){
listeners.erase(listener);
}
std::set<JoystickListener*> Joystick::listeners;
std::set<JoystickListener*> Joystick::getListeners(){
return listeners;
}
diff --git a/util/input/joystick.h b/util/input/joystick.h
index 6675edda..17b54d9b 100644
--- a/util/input/joystick.h
+++ b/util/input/joystick.h
@@ -1,134 +1,137 @@
#ifndef _paintown_joystick_h
#define _paintown_joystick_h
#include <vector>
#include <set>
+#include <string>
struct JoystickInput{
JoystickInput():
left(false),
right(false),
up(false),
down(false),
button1(false),
button2(false),
button3(false),
button4(false),
button5(false),
button6(false),
quit(false),
start(false){
}
JoystickInput(const JoystickInput & copy):
left(copy.left),
right(copy.right),
up(copy.up),
down(copy.down),
button1(copy.button1),
button2(copy.button2),
button3(copy.button3),
button4(copy.button4),
button5(copy.button5),
button6(copy.button6),
quit(copy.quit),
start(copy.start){
}
/* true if something is pressed */
bool pressed(){
return left || right || up || down ||
button1 || button2 || button3 || button4 ||
button5 || button6 ||
quit || start;
}
bool left;
bool right;
bool up;
bool down;
bool button1;
bool button2;
bool button3;
bool button4;
bool button5;
bool button6;
bool quit;
bool start;
};
/* Callback for joystick actions like button presses, axis motions, etc.
*/
class Joystick;
class JoystickListener{
public:
JoystickListener();
virtual ~JoystickListener();
virtual void pressButton(Joystick * from, int button) = 0;
virtual void releaseButton(Joystick * from, int button) = 0;
virtual void axisMotion(Joystick * from, int axis, int motion) = 0;
virtual void hatMotion(Joystick * from, int motion) = 0;
};
class Joystick{
public:
virtual void poll() = 0;
// virtual JoystickInput readAll() = 0;
virtual bool pressed() const;
virtual ~Joystick();
virtual int getDeviceId() const = 0;
virtual void pressButton(int button);
virtual void releaseButton(int button);
virtual void axisMotion(int axis, int motion);
virtual void hatMotion(int motion);
+ virtual std::string getName() const = 0;
+
/* create the ith joystick */
static Joystick * create(int i);
static int numberOfJoysticks();
enum Key{
Invalid = -1,
Up = 0,
Down,
Left,
Right,
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Quit,
Start
};
struct Event{
Event(Key key, bool enabled):
key(key), enabled(enabled){
}
Key key;
bool enabled;
};
virtual inline const std::vector<Event> & getEvents() const {
return events;
}
static const char * keyToName(Key key);
static void addListener(JoystickListener * listener);
static void removeListener(JoystickListener * listener);
protected:
static std::set<JoystickListener*> getListeners();
static std::set<JoystickListener*> listeners;
std::vector<Event> events;
Joystick();
};
#endif
diff --git a/util/input/sdl/joystick.cpp b/util/input/sdl/joystick.cpp
index 3a30af83..d20fc36c 100644
--- a/util/input/sdl/joystick.cpp
+++ b/util/input/sdl/joystick.cpp
@@ -1,760 +1,768 @@
#ifdef USE_SDL
#include <SDL.h>
#include "joystick.h"
#include "util/debug.h"
#include <string>
#include <vector>
#include <exception>
using std::string;
using std::vector;
class ButtonMapping{
public:
ButtonMapping(){
}
virtual ~ButtonMapping(){
}
virtual int toNative(int button) = 0;
virtual int fromNative(int button) = 0;
virtual Joystick::Key toKey(int button) = 0;
virtual void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events) = 0;
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events) = 0;
};
class DefaultButtonMapping: public ButtonMapping {
public:
int toNative(int button){
return button;
}
int fromNative(int button){
return button;
}
Joystick::Key toKey(int button){
switch (button){
case 0: return Joystick::Button1;
case 1: return Joystick::Button2;
case 2: return Joystick::Button3;
case 3: return Joystick::Button4;
case 4: return Joystick::Quit;
case 5: return Joystick::Button5;
case 6: return Joystick::Button6;
default: return Joystick::Invalid;
}
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: right = true; up = true; break;
case SDL_HAT_RIGHTDOWN: right = true; down = true; break;
case SDL_HAT_LEFTUP: left = true; up = true; break;
case SDL_HAT_LEFTDOWN: left = true; down = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
if (axis == 0){
if (motion < 0){
left = true;
} else if (motion > 0){
right = true;
}
} else if (axis == 1){
if (motion < 0){
up = true;
} else if (motion > 0){
down = true;
}
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
/* used when a ps3 controller is plugged into a usb port of a normal pc */
class Playstation3Controller: public ButtonMapping {
public:
enum Buttons{
Cross = 14,
Circle = 13,
Triangle = 12,
Square = 15,
Start = 3,
Select = 0,
Up = 4,
Left = 7,
Down = 6,
Right = 5,
Stick1 = 1,
Stick2 = 2,
L2 = 8,
L1 = 10,
R2 = 9,
R1 = 11,
/* the middle ps3 button */
Ps3 = 16
};
int toNative(int button){
switch (button){
case 0: return Square;
case 1: return Cross;
case 2: return Circle;
case 3: return Triangle;
case 4: return Start;
}
return button;
}
int fromNative(int button){
switch (button){
case Square: return 0;
case Cross: return 1;
case Circle: return 2;
case Triangle: return 3;
case Start: return Start;
default: return 5;
}
return button;
}
Joystick::Key toKey(int button){
switch (button){
case Square: return Joystick::Button1;
case Cross: return Joystick::Button2;
case Circle: return Joystick::Button3;
case Triangle: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
case Up: return Joystick::Up;
case Down: return Joystick::Down;
case Left: return Joystick::Left;
case Right: return Joystick::Right;
default: return Joystick::Invalid;
}
}
/* TODO */
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
}
};
class LogitechPrecision: public ButtonMapping {
public:
enum Buttons{
Button1 = 0,
Button2 = 1,
Button3 = 2,
Button4 = 3,
Start = 8,
Select = 9,
R2 = 7,
R1 = 5,
L2 = 6,
L1 = 4
};
int toNative(int button){
return -1;
}
int fromNative(int button){
return -1;
}
Joystick::Key toKey(int button){
switch (button){
case Button1: return Joystick::Button1;
case Button2: return Joystick::Button2;
case Button3: return Joystick::Button3;
case Button4: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
}
return Joystick::Invalid;
}
/* axis 1. negative up, positive down
* axis 0, negative left, positive right
*/
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
int tolerance = 10;
if (axis == 0){
if (motion == 0){
events.push_back(Joystick::Event(Joystick::Left, false));
events.push_back(Joystick::Event(Joystick::Right, false));
} else if (motion == -32768){
events.push_back(Joystick::Event(Joystick::Left, true));
} else if (motion == 32767){
events.push_back(Joystick::Event(Joystick::Right, true));
} else if (motion == 128){
events.push_back(Joystick::Event(Joystick::Up, false));
events.push_back(Joystick::Event(Joystick::Down, false));
} else if (motion == 1){
events.push_back(Joystick::Event(Joystick::Up, true));
} else if (motion == 255){
events.push_back(Joystick::Event(Joystick::Down, true));
}
/*
if (motion < -tolerance){
events.push_back(Joystick::Event(Joystick::Left, true));
} else if (motion > tolerance){
events.push_back(Joystick::Event(Joystick::Right, true));
} else {
/ * fake a release for left and right * /
events.push_back(Joystick::Event(Joystick::Left, false));
events.push_back(Joystick::Event(Joystick::Right, false));
}
*/
} else if (axis == 1){
if (motion < -tolerance){
events.push_back(Joystick::Event(Joystick::Up, true));
} else if (motion > tolerance){
events.push_back(Joystick::Event(Joystick::Down, true));
} else {
events.push_back(Joystick::Event(Joystick::Up, false));
events.push_back(Joystick::Event(Joystick::Down, false));
}
}
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
}
};
/* used for the ps3 controller with psl1ght's SDL version */
class Ps3Controller: public ButtonMapping {
public:
enum Buttons{
Left = 0,
Down = 1,
Right = 2,
Up = 3,
Select = 7,
Start = 4,
Square = 8,
Cross = 9,
Circle = 10,
Triangle = 11,
L1 = 13,
R1 = 12,
L2 = 15,
R2 = 14,
L3 = 6,
R3 = 5
};
int toNative(int button){
switch (button){
case 0: return Square;
case 1: return Cross;
case 2: return Circle;
case 3: return Triangle;
case 4: return Start;
}
return button;
}
int fromNative(int button){
switch (button){
case Square: return 0;
case Cross: return 1;
case Circle: return 2;
case Triangle: return 3;
case Start: return Start;
default: return 5;
}
return button;
}
Joystick::Key toKey(int button){
switch (button){
case Square: return Joystick::Button1;
case Cross: return Joystick::Button2;
case Circle: return Joystick::Button3;
case Triangle: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
case Up: return Joystick::Up;
case Down: return Joystick::Down;
case Left: return Joystick::Left;
case Right: return Joystick::Right;
default: return Joystick::Invalid;
}
}
/* TODO */
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
}
};
class XBox360Controller: public ButtonMapping {
public:
enum Buttons{
A = 0,
B = 1,
X = 2,
Y = 3,
L1 = 4,
R1 = 5,
Start = 6,
Xbox = 7,
L3 = 8,
R3 = 9,
Select = 10
};
int toNative(int button){
return 0;
}
int fromNative(int button){
return 0;
}
Joystick::Key toKey(int button){
switch (button){
case A: return Joystick::Button1;
case B: return Joystick::Button2;
case X: return Joystick::Button3;
case Y: return Joystick::Button4;
case L1: return Joystick::Button5;
case R1: return Joystick::Button6;
case Start: return Joystick::Start;
case Select: return Joystick::Quit;
}
return Joystick::Invalid;
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
/* axis 6 and 7 are the hats. sdl passes them as hat events */
#if 0
if (axis == 6){
if (motion < 0){
events.push_back(Joystick::Event(Joystick::Left, true));
} else if (motion > 0){
events.push_back(Joystick::Event(Joystick::Right, true));
} else if (motion == 0){
/* fake a release for left and right */
events.push_back(Joystick::Event(Joystick::Left, false));
events.push_back(Joystick::Event(Joystick::Right, false));
}
} else if (axis == 7){
if (motion < 0){
events.push_back(Joystick::Event(Joystick::Up, true));
} else if (motion > 0){
events.push_back(Joystick::Event(Joystick::Down, true));
} else if (motion == 0){
events.push_back(Joystick::Event(Joystick::Up, false));
events.push_back(Joystick::Event(Joystick::Down, false));
}
}
#endif
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: right = true; up = true; break;
case SDL_HAT_RIGHTDOWN: right = true; down = true; break;
case SDL_HAT_LEFTUP: left = true; up = true; break;
case SDL_HAT_LEFTDOWN: left = true; down = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
class Wiimote: public ButtonMapping {
public:
enum Buttons{
A = 0,
B = 1,
Button1 = 2,
Button2 = 3,
Minus = 4,
Plus = 5,
Home = 6
};
int toNative(int button){
return 0;
}
int fromNative(int button){
return 0;
}
/* FIXME: need a start key */
Joystick::Key toKey(int button){
switch (button){
case A: return Joystick::Button1;
case B: return Joystick::Button2;
case Button1: return Joystick::Button3;
case Button2: return Joystick::Button4;
case Minus: return Joystick::Button5;
case Plus: return Joystick::Button6;
case Home: return Joystick::Quit;
}
return Joystick::Invalid;
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
/* rotate all the directions 90 degrees */
bool up = false; // right
bool down = false; // left
bool left = false; // up
bool right = false; // down
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: up = true; right = true; break;
case SDL_HAT_RIGHTDOWN: down = true; right = true; break;
case SDL_HAT_LEFTUP: up = true; left = true; break;
case SDL_HAT_LEFTDOWN: down = true; left = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
class GamecubePad: public ButtonMapping {
public:
enum Buttons{
A = 0,
B = 1,
X = 2,
Y = 3,
Z = 4,
Start = 7
};
int toNative(int button){
return 0;
}
int fromNative(int button){
return 0;
}
Joystick::Key toKey(int button){
switch (button){
case A: return Joystick::Button1;
case B: return Joystick::Button2;
case X: return Joystick::Button3;
case Y: return Joystick::Button4;
case Z: return Joystick::Button5;
case Start: return Joystick::Start;
}
return Joystick::Invalid;
}
void axisMotionEvents(int axis, int motion, vector<Joystick::Event> & events){
// printf("axis %d motion %d\n", axis, motion);
}
virtual void hatMotionEvents(int motion, vector<Joystick::Event> & events){
bool up = false;
bool down = false;
bool left = false;
bool right = false;
switch (motion){
case SDL_HAT_CENTERED: break;
case SDL_HAT_UP: up = true; break;
case SDL_HAT_RIGHT: right = true; break;
case SDL_HAT_DOWN: down = true; break;
case SDL_HAT_LEFT: left = true; break;
case SDL_HAT_RIGHTUP: right = true; up = true; break;
case SDL_HAT_RIGHTDOWN: right = true; down = true; break;
case SDL_HAT_LEFTUP: left = true; up = true; break;
case SDL_HAT_LEFTDOWN: left = true; down = true; break;
}
events.push_back(Joystick::Event(Joystick::Left, left));
events.push_back(Joystick::Event(Joystick::Right, right));
events.push_back(Joystick::Event(Joystick::Down, down));
events.push_back(Joystick::Event(Joystick::Up, up));
}
};
ButtonMapping * makeButtonMapping(string name){
#ifdef PS3
return new Ps3Controller();
#endif
if (name == "Sony PLAYSTATION(R)3 Controller"){
return new Playstation3Controller();
}
if (name.find("Logitech(R) Precision(TM) Gamepad") != string::npos){
return new LogitechPrecision();
}
if (name == "Microsoft X-Box 360 pad"){
return new XBox360Controller();
}
if (name.find("Wiimote") != string::npos){
return new Wiimote();
}
if (name.find("Gamecube") != string::npos){
return new GamecubePad();
}
return new DefaultButtonMapping();
}
void SDLJoystick::poll(){
events.clear();
}
static bool read_button(SDL_Joystick * joystick, int button){
return SDL_JoystickGetButton(joystick, button);
}
/*
JoystickInput SDLJoystick::readAll(){
JoystickInput input;
return input;
if (joystick){
int buttons = SDL_JoystickNumButtons(joystick);
switch (buttons > 5 ? 5 : buttons){
case 5: input.quit = read_button(joystick, buttonMapping->toNative(4));
case 4: input.button4 = read_button(joystick, buttonMapping->toNative(3));
case 3: input.button3 = read_button(joystick, buttonMapping->toNative(2));
case 2: input.button2 = read_button(joystick, buttonMapping->toNative(1));
case 1: input.button1 = read_button(joystick, buttonMapping->toNative(0));
case 0: {
break;
}
}
}
int axis = SDL_JoystickNumAxes(joystick);
if (axis > 0){
int position = SDL_JoystickGetAxis(joystick, 0);
if (position < 0){
input.left = true;
} else if (position > 0){
input.right = true;
}
}
if (axis > 1){
int position = SDL_JoystickGetAxis(joystick, 1);
if (position < 0){
input.up = true;
} else if (position > 0){
input.down = true;
}
}
int hats = SDL_JoystickNumHats(joystick);
if (hats > 0){
int hat = SDL_JoystickGetHat(joystick, 0);
if ((hat & SDL_HAT_UP) == SDL_HAT_UP){
input.up = true;
}
if ((hat & SDL_HAT_DOWN) == SDL_HAT_DOWN){
input.down = true;
}
if ((hat & SDL_HAT_LEFT) == SDL_HAT_LEFT){
input.left = true;
}
if ((hat & SDL_HAT_RIGHT) == SDL_HAT_RIGHT){
input.right = true;
}
if ((hat & SDL_HAT_RIGHTUP) == SDL_HAT_RIGHTUP){
input.right = true;
input.up = true;
}
if ((hat & SDL_HAT_RIGHTDOWN) == SDL_HAT_RIGHTDOWN){
input.right = true;
input.down = true;
}
if ((hat & SDL_HAT_LEFTDOWN) == SDL_HAT_LEFTDOWN){
input.left = true;
input.down = true;
}
if ((hat & SDL_HAT_LEFTUP) == SDL_HAT_LEFTUP){
input.left = true;
input.up = true;
}
}
return input;
}
*/
SDLJoystick::~SDLJoystick(){
if (joystick){
SDL_JoystickClose(joystick);
}
}
#if 0
#include <io/pad.h>
#include <fstream>
void hack(){
padInfo padinfo;
int ok = ioPadGetInfo(&padinfo);
if (ok == 0){
std::ofstream out("/dev_hdd0/tmp/p.txt");
out << "PS3 Pad Info" << std::endl;
out << " max " << padinfo.max << std::endl;
out << " connected " << padinfo.connected << std::endl;
out << " status 0 " << (int) padinfo.status[0] << std::endl;
out << " status 1 " << (int) padinfo.status[1] << std::endl;
out << " status 2 " << (int) padinfo.status[2] << std::endl;
out << " status 3 " << (int) padinfo.status[3] << std::endl;
out << " status 4 " << (int) padinfo.status[4] << std::endl;
out.close();
} else {
Global::debug(0) << "Could not get pad info" << std::endl;
}
}
#endif
SDLJoystick::SDLJoystick(int id):
joystick(NULL){
if (SDL_NumJoysticks() > id){
joystick = SDL_JoystickOpen(id);
if (joystick == NULL){
Global::debug(0) << "Could not open joystick at index " << id << std::endl;
} else {
Global::debug(1) << "Opened joystick '" << SDL_JoystickName(id) << "'" << std::endl;
}
// printf("Opened joystick '%s'\n", SDL_JoystickName(4));
buttonMapping = makeButtonMapping(SDL_JoystickName(id));
}
}
void SDLJoystick::pressButton(int button){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->pressButton(this, button);
}
// Global::debug(0) << "Pressed button " << button << std::endl;
if (joystick){
Key event = buttonMapping->toKey(button);
if (event != Invalid){
events.push_back(Event(event, true));
}
}
}
void SDLJoystick::releaseButton(int button){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->releaseButton(this, button);
}
if (joystick){
Key event = buttonMapping->toKey(button);
if (event != Invalid){
events.push_back(Event(event, false));
}
}
}
void SDLJoystick::hatMotion(int motion){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->hatMotion(this, motion);
}
// Global::debug(0) << "Hat motion " << motion << std::endl;
if (joystick){
buttonMapping->hatMotionEvents(motion, events);
}
}
void SDLJoystick::axisMotion(int axis, int motion){
std::set<JoystickListener*> listeners = getListeners();
for (std::set<JoystickListener*>::iterator it = listeners.begin(); it != listeners.end(); it++){
(*it)->axisMotion(this, axis, motion);
}
// Global::debug(0) << "Axis motion on " << axis << " motion " << motion << std::endl;
if (joystick){
buttonMapping->axisMotionEvents(axis, motion, events);
/*
Event move = buttonMapping->axisMotionToEvent(axis, motion);
if (move.key != Invalid){
events.push_back(move);
}
*/
}
}
+string SDLJoystick::getName() const {
+ if (joystick){
+ return SDL_JoystickName(getDeviceId());
+ }
+
+ return "";
+}
+
int SDLJoystick::getDeviceId() const {
if (joystick){
return SDL_JoystickIndex(joystick);
}
return -1;
}
int Joystick::numberOfJoysticks(){
return SDL_NumJoysticks();
}
#endif
diff --git a/util/input/sdl/joystick.h b/util/input/sdl/joystick.h
index f20267e3..058f7cd5 100644
--- a/util/input/sdl/joystick.h
+++ b/util/input/sdl/joystick.h
@@ -1,37 +1,38 @@
#ifndef _paintown_sdl_joystick_h
#define _paintown_sdl_joystick_h
#ifdef USE_SDL
#include <SDL.h>
#include "../joystick.h"
#include "util/pointer.h"
class ButtonMapping;
class SDLJoystick: public Joystick {
public:
virtual void poll();
// virtual JoystickInput readAll();
virtual int getDeviceId() const;
virtual void pressButton(int button);
virtual void releaseButton(int button);
virtual void axisMotion(int axis, int motion);
virtual void hatMotion(int motion);
+ std::string getName() const;
virtual ~SDLJoystick();
friend class Joystick;
protected:
/* convert buttons between what paintown wants and what sdl wants */
int to_native_button(int button);
int from_native_button(int button);
SDLJoystick(int i);
SDL_Joystick * joystick;
Util::ReferenceCount<ButtonMapping> buttonMapping;
};
#endif
#endif
diff --git a/util/menu/menu_option.h b/util/menu/menu_option.h
index a848d7cd..176b51b3 100644
--- a/util/menu/menu_option.h
+++ b/util/menu/menu_option.h
@@ -1,97 +1,99 @@
#ifndef _paintown_menu_option_h
#define _paintown_menu_option_h
#include <string>
#include <vector>
#include "util/gui/box.h"
#include "util/load_exception.h"
#include "util/language-string.h"
#include "util/gui/context-box.h"
#include "util/gui/scroll-list.h"
class Bitmap;
class Token;
namespace Menu {
class Context;
}
class MenuOption: public Gui::ContextItem {
public:
/* called when the menu containing this option is displayed to the user.
* default behavior is to do nothing.
*/
virtual void open();
/* called when the menu containing this option returns.
* default behavior is to do nothing.
*/
virtual void close();
- // Do logic before run part
+ /* Logic is executed every tick by the menu so you can do cool effects.
+ */
virtual void logic() = 0;
+ /* Run is executed when the user selects this option */
// Finally it has been selected, this is what shall run
// endGame will be set true if it is a terminating option
virtual void run(const Menu::Context &) = 0;
// This is to pass paramaters to an option ie a bar or something
// return true to pause key input
virtual bool leftKey();
virtual bool rightKey();
enum state{
Selected = 0,
Deselected,
Run
};
enum OptionType{
Event = 0,
Option,
AdjustableOption
};
MenuOption(const Gui::ContextBox & parent, const Token *token);
/*
template <typename T>
Util::ReferenceCount<Gui::ScrollItem> getAsScrollItem(const Gui::ContextBox & parent){
Util::ReferenceCount<T> item = new T(this->getName(), parent);
return item.template convert<Gui::ScrollItem>();
}
*/
virtual ~MenuOption();
protected:
private:
state currentState;
OptionType mType;
LanguageString text;
LanguageString infoText;
bool runnable;
public:
inline void setState(const state s) { currentState = s; }
inline state getState() const { return currentState; }
inline void setType(const OptionType t) { mType = t; }
inline OptionType getType() const { return mType; }
inline void setInfoText(const LanguageString &t) { infoText = t; }
inline std::string getInfoText(){ return infoText.get(); }
inline void setRunnable(const bool r) { runnable = r; }
inline bool isRunnable() const { return runnable; }
public:
const std::string getName() const;
void addInfo(const Token *);
void addName(const Token *);
protected:
void readName(const Token * token, const std::string & matchType = "_/name");
void readInfo(const Token * token);
};
#endif
diff --git a/util/menu/options.cpp b/util/menu/options.cpp
index 953a171e..4b377426 100644
--- a/util/menu/options.cpp
+++ b/util/menu/options.cpp
@@ -1,2571 +1,2624 @@
#include "util/bitmap.h"
#include "util/stretch-bitmap.h"
#include "util/trans-bitmap.h"
#include "options.h"
#include "util/token.h"
#include "util/input/input-source.h"
#include "util/parameter.h"
#include "util/tokenreader.h"
#include "menu.h"
#include "configuration.h"
#include "menu-exception.h"
#include "util/init.h"
#include "util/events.h"
#include "optionfactory.h"
#include "util/music.h"
#include "util/input/keyboard.h"
#include "util/funcs.h"
#include "util/file-system.h"
#include "factory/font_factory.h"
+/* FIXME: its probably bad to depend on the top-level globals. Most of globals.h/cpp should
+ * be moved to the utils directory.
+ */
#include "globals.h"
#include "util/exceptions/shutdown_exception.h"
#include "util/exceptions/exception.h"
#include "util/font.h"
#include "util/gui/box.h"
#include "util/thread.h"
#include "util/loading.h"
#include "util/fire.h"
#include "util/input/input-map.h"
#include "util/input/input-manager.h"
#include <sstream>
#include <algorithm>
#include <time.h>
#include <math.h>
using namespace std;
using namespace Gui;
/* true if the arguments passed in match todays date.
* pass 0 for any argument that you don't care about (it will match any date)
*/
static bool todaysDate(int month, int day, int year){
int currentMonth;
int currentDay;
int currentYear;
time_t result = time(NULL);
struct tm * local = localtime(&result);
return (month == 0 || month == (local->tm_mon + 1)) &&
(day == 0 || day == local->tm_mday) &&
(year == 0 || year == local->tm_year + 1900);
}
static bool jonBirthday(){
return todaysDate(3, 25, 0);
}
static bool miguelBirthday(){
return todaysDate(8, 11, 0);
}
OptionCredits::Block::Block(const std::string & title):
title(title),
titleColorOverride(false),
titleColor(Graphics::makeColor(0,255,255)),
colorOverride(false),
color(Graphics::makeColor(255,255,255)),
spacing(0){
}
OptionCredits::Block::Block(const Token * token):
titleColorOverride(false),
titleColor(Graphics::makeColor(0,255,255)),
colorOverride(false),
color(Graphics::makeColor(255,255,255)),
topWidth(0),
topHeight(0),
bottomWidth(0),
bottomHeight(0),
spacing(0){
if ( *token != "block" ){
throw LoadException(__FILE__, __LINE__, "Not a credit block");
}
TokenView view = token->view();
while (view.hasMore()){
std::string match;
try{
const Token * tok;
view >> tok;
if ( *tok == "title" ) {
tok->view() >> title;
} else if (*tok == "credit"){
std::string credit;
tok->view() >> credit;
credits.push_back(credit);
} else if ( *tok == "titlecolor" ) {
try{
int r,b,g;
tok->view() >> r >> g >> b;
titleColor = Graphics::makeColor( r, g, b );
titleColorOverride = true;
} catch (const TokenException & ex){
}
} else if ( *tok == "color" ) {
try{
int r,b,g;
tok->view() >> r >> g >> b;
color = Graphics::makeColor( r, g, b );
colorOverride = true;
} catch (const TokenException & ex){
}
} else if ( *tok == "animation" ) {
TokenView animView = tok->view();
while (animView.hasMore()){
const Token * animTok;
animView >> animTok;
if (*animTok == "top"){
tok->match("_/width", topWidth);
tok->match("_/height", topHeight);
topAnimation = Util::ReferenceCount<Gui::Animation>(new Animation(tok));
} else if (*animTok == "bottom"){
tok->match("_/width", bottomWidth);
tok->match("_/height", bottomHeight);
bottomAnimation = Util::ReferenceCount<Gui::Animation>(new Animation(tok));
}
}
} else if (*tok == "spacing"){
tok->view() >> spacing;
} else {
Global::debug( 3 ) <<"Unhandled Credit Block attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Credit Block parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
OptionCredits::Block::Block(const OptionCredits::Block & copy):
title(copy.title),
credits(copy.credits),
titleColorOverride(copy.titleColorOverride),
titleColor(copy.titleColor),
colorOverride(copy.colorOverride),
color(copy.color),
topAnimation(copy.topAnimation),
topWidth(copy.topWidth),
topHeight(copy.topHeight),
bottomAnimation(copy.bottomAnimation),
bottomWidth(copy.bottomWidth),
bottomHeight(copy.bottomHeight),
spacing(copy.spacing){
}
OptionCredits::Block::~Block(){
}
const OptionCredits::Block & OptionCredits::Block::operator=(const OptionCredits::Block & copy){
title = copy.title;
credits = copy.credits;
titleColor = copy.titleColor;
titleColorOverride = copy.titleColorOverride;
color = copy.color;
colorOverride = copy.colorOverride;
topAnimation = copy.topAnimation;
topWidth =copy.topWidth;
topHeight = copy.topHeight;
bottomAnimation = copy.bottomAnimation;
bottomWidth = copy.bottomWidth;
bottomHeight = copy.bottomHeight;
spacing = copy.spacing;
return *this;
}
void OptionCredits::Block::addCredit(const std::string & credit){
credits.push_back(credit);
}
void OptionCredits::Block::act(){
// Top animation
if (topAnimation != NULL){
topAnimation->act();
}
// Bottom animation
if (bottomAnimation != NULL){
bottomAnimation->act();
}
}
int OptionCredits::Block::print(int x, int y, Graphics::Color defaultTitleColor, Graphics::Color defaultColor, const Font & font, const Graphics::Bitmap & work, const Justification & justification) const {
int currentY = y;
// Top animation
if (topAnimation != NULL){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = topWidth/2;
break;
case Right:
xmod = topWidth;
break;
}
// FIXME temporary solution
const Graphics::Bitmap & temp = Graphics::Bitmap::temporaryBitmap(topWidth, topHeight);
//topAnimation->draw(x - xmod, y, topWidth, topHeight, work);
topAnimation->draw(0, 0, topWidth, topHeight, temp);
temp.translucent().draw(x-xmod, y, work);
currentY+=topHeight;
}
if (!title.empty()){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = font.textLength(title.c_str())/2;
break;
case Right:
xmod = font.textLength(title.c_str());
break;
}
font.printf(x - xmod, currentY, (titleColorOverride ? titleColor : defaultTitleColor), work, title, 0);
currentY += font.getHeight();
}
for (std::vector<std::string>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const std::string & credit = *i;
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = font.textLength(credit.c_str())/2;
break;
case Right:
xmod = font.textLength(credit.c_str());
break;
}
font.printf(x - xmod, currentY, (colorOverride ? color : defaultColor), work, credit, 0);
currentY += font.getHeight();
}
// Bottom animation
if (bottomAnimation != NULL){
int xmod = 0;
switch (justification){
default:
case Left:
xmod = 0;
break;
case Center:
xmod = bottomWidth/2;
break;
case Right:
xmod = bottomWidth;
break;
}
// FIXME temporary solution
const Graphics::Bitmap & temp = Graphics::Bitmap::temporaryBitmap(topWidth, topHeight);
//bottomAnimation->draw(x - xmod, y, bottomWidth, bottomHeight, work);
bottomAnimation->draw(0, 0, bottomWidth, bottomHeight, temp);
temp.translucent().draw(x-xmod, y, work);
currentY+=bottomHeight;
}
currentY += font.getHeight() + spacing;
return currentY;
}
const int OptionCredits::Block::size(const Font & font) const{
// Counts title and space in between
int total = 0;
if (topAnimation != NULL){
total += topHeight;
}
if (!title.empty()){
total+= font.getHeight();
}
total += credits.size() * font.getHeight();
if (bottomAnimation != NULL){
total += bottomHeight;
}
total += font.getHeight();
total += spacing;
return total;
}
OptionCredits::Sequence::Sequence(const Token * token):
type(Primary),
x(0),
y(0),
startx(0),
endx(0),
starty(0),
endy(0),
ticks(0),
duration(250),
speed(0),
alpha(0),
alphaMultiplier(0),
justification(Block::Center),
current(0),
done(false),
creditLength(0){
if ( *token != "sequence" ){
throw LoadException(__FILE__, __LINE__, "Not a credit sequence");
}
TokenView view = token->view();
while (view.hasMore()){
std::string match;
try{
const Token * tok;
view >> tok;
if (*tok == "type"){
std::string sequenceType;
tok->view() >> sequenceType;
if (sequenceType == "roll"){
type = Roll;
} else if (sequenceType == "primary"){
type = Primary;
}
} else if (*tok == "start-x"){
tok->view() >> startx;
} else if (*tok == "end-x"){
tok->view() >> endx;
} else if (*tok == "start-y"){
tok->view() >> starty;
} else if (*tok == "end-y"){
tok->view() >> endy;
} else if (*tok == "duration"){
tok->view() >> duration;
} else if (*tok == "speed"){
tok->view() >> speed;
} else if (*tok == "alpha-multiplier"){
tok->view() >> alphaMultiplier;
} else if ( *tok == "justification" ) {
std::string justify;
tok->view() >> justify;
if (justify == "left"){
justification = Block::Left;
} else if (justify == "center"){
justification = Block::Center;
} else if (justify == "right"){
justification = Block::Right;
}
} else if (*tok == "block"){
credits.push_back(Block(tok));
} else {
Global::debug( 3 ) <<"Unhandled Credit Sequence attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Credit Sequence parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
// Initial
reset();
for (std::vector<OptionCredits::Block>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const OptionCredits::Block & block = *i;
creditLength += block.size(Menu::menuFontParameter.current()->get());
}
}
OptionCredits::Sequence::Sequence(const Sequence & copy):
type(copy.type),
x(copy.x),
y(copy.y),
startx(copy.startx),
endx(copy.endx),
starty(copy.starty),
endy(copy.endy),
ticks(copy.ticks),
duration(copy.duration),
speed(copy.speed),
alpha(copy.alpha),
alphaMultiplier(copy.alphaMultiplier),
justification(copy.justification),
credits(copy.credits),
current(copy.current),
done(false),
creditLength(copy.creditLength){
}
OptionCredits::Sequence::~Sequence(){
}
const OptionCredits::Sequence & OptionCredits::Sequence::operator=(const OptionCredits::Sequence & copy){
type = copy.type;
x = copy.x;
y = copy.y;
startx = copy.startx;
endx = copy.endx;
starty = copy.starty;
endy = copy.endy;
ticks = copy.ticks;
duration = copy.duration;
speed = copy.speed;
alpha = copy.alpha;
alphaMultiplier = copy.alphaMultiplier;
justification = copy.justification;
credits = copy.credits;
current = copy.current;
done = false;
creditLength = copy.creditLength;
return *this;
}
static int alphaClamp(int x, double multiplier){
int clamp = x * multiplier;
if (clamp < 0){
clamp = 0;
} else if (clamp > 255){
clamp = 255;
}
return clamp;
}
void OptionCredits::Sequence::act(){
if (!done && !credits.empty()){
if (type == Roll){
y += speed;
if (starty > endy){
if ((y + (creditLength * 1.1)) < endy){
done = true;
}
} else if (starty < endy){
if ((y * 1.1) > endy){
done = true;
}
}
} else if (type == Primary){
credits[current].act();
if (startx != endx){
x += speed;
if (startx > endx){
const double midpoint = (startx+endx)/2;
const int mid = x > midpoint ? startx -x : x - endx;
alpha = alphaClamp(mid, alphaMultiplier);
if (x < endx){
next();
}
} else if (startx < endx){
const double midpoint = (startx+endx)/2;
const int mid = x < midpoint ? x - startx : endx - x;
alpha = alphaClamp(mid, alphaMultiplier);
//Global::debug(0) << "alpha: " << alpha << " midpoint: " << midpoint << " mid: " << mid << std::endl;
if (x > endx){
next();
}
}
} else {
const double midpoint = duration/2;
const int mid = ticks < midpoint ? ticks : duration - ticks;
alpha = alphaClamp(mid, alphaMultiplier);
ticks++;
if (ticks >= duration){
ticks = 0;
next();
}
}
}
}
}
void OptionCredits::Sequence::draw(Graphics::Color title, Graphics::Color color, const Graphics::Bitmap & work){
if (!done && !credits.empty()){
if (type == Roll){
int rollY = (int) y;
for (std::vector<OptionCredits::Block>::const_iterator i = credits.begin(); i != credits.end(); ++i){
const OptionCredits::Block & block = *i;
rollY = block.print(x, rollY, title, color, Menu::menuFontParameter.current()->get(), work, justification);
}
} else if (type == Primary){
Graphics::Bitmap::transBlender(0, 0, 0, alpha);
credits[current].print(x, y, title, color, Menu::menuFontParameter.current()->get(), work.translucent(), justification);
}
}
}
void OptionCredits::Sequence::reset(){
done = false;
current = 0;
ticks = 0;
if (!credits.empty()){
if (type == Roll){
x = startx;
y = starty;
} else if (type == Primary){
x = startx;
y = starty - (credits[current].size(Menu::menuFontParameter.current()->get())/2);
}
}
}
void OptionCredits::Sequence::next(){
if (type == Primary){
if (current < credits.size()){
current++;
if (current == credits.size()){
done = true;
} else {
x = startx;
y = starty - (credits[current].size(Menu::menuFontParameter.current()->get())/2);
}
}
}
}
static std::string defaultPositions(){
const int width = Configuration::getScreenWidth();
const int height = Configuration::getScreenHeight();
std::ostringstream out;
out << "(start-x " << width/2.3 << ") (end-x " << width/1.8 << ") (start-y " << height/2 << ") ";
//out << "(start-x " << width/2 << ") (end-x " << width/2 << ") (start-y " << height/2 << ") (duration 250) ";
return out.str();
}
OptionCredits::OptionCredits(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token),
creditsContext(new Menu::Context()),
music(""),
color(Graphics::makeColor(255,255,255)),
title(Graphics::makeColor(0,255,255)),
clearColor(Graphics::makeColor(0,0,0)){
std::string defaultSequence = "(sequence (type primary) (speed 0.3) (alpha-multiplier 20) (justification center) " + defaultPositions();
/* Always */
if (jonBirthday()){
defaultSequence += "(block (title \"Happy birthday, Jon!\"))";
}
if (miguelBirthday()){
defaultSequence += "(block (title \"Happy birthday, Jon!\"))";
}
defaultSequence += "(block (animation (top) (width 350) (height 65) (image 0 \"sprites/paintown.png\") (frame (image 0) (time -1))) (credit \"Version " + Global::getVersionString() + "\"))";
defaultSequence += "(block (title \"Programming\") (credit \"Jon Rafkind\") (credit \"Miguel Gavidia\"))";
defaultSequence += "(block (title \"Level design\") (credit \"Jon Rafkind\") (credit \"Miguel Gavidia\"))";
defaultSequence += "(block (title \"Contact\") (credit \"Website: http://paintown.org\") (credit \"Email: jon@rafkind.com\")))";
TokenReader reader;
Sequence sequence(reader.readTokenFromString(defaultSequence));
sequences.push_back(sequence);
//Global::debug(0) << defaultSequence << std::endl;
if ( *token != "credits" ){
throw LoadException(__FILE__, __LINE__, "Not a credit menu");
}
readName(token);
TokenView view = token->view();
// NOTE Use this to handle legacy additional blocks for the time being
Block legacyAdditional("");
bool additionalTitle = true;
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "music" ) {
/* Set music for credits */
tok->view() >> music;
} else if ( *tok == "background" ) {
/* Create an image and push it back on to vector */
std::string temp;
tok->view() >> temp;
creditsContext->addBackground(temp);
} else if ( *tok == "anim" || *tok == "animation" ){
creditsContext->addBackground(tok);
} else if ( *tok == "additional" ) {
std::string str;
TokenView additionalView = tok->view();
while (additionalView.hasMore()){
additionalView >> str;
if (additionalTitle){
legacyAdditional = Block(str);
additionalTitle = false;
} else {
legacyAdditional.addCredit(str);
}
}
} else if (*tok == "sequence"){
sequences.push_back(OptionCredits::Sequence(tok));
} else if ( *tok == "titlecolor" ) {
int r,b,g;
tok->view() >> r >> g >> b;
title = Graphics::makeColor( r, g, b );
} else if ( *tok == "color" ) {
int r,b,g;
tok->view() >> r >> g >> b;
color = Graphics::makeColor( r, g, b );
} else if ( *tok == "clear-color" ) {
int r,b,g;
tok->view() >> r >> g >> b;
clearColor = Graphics::makeColor( r, g, b );
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
if (!legacyAdditional.empty()){
//creditsRoll.push_back(legacyAdditional);
}
input.set(Keyboard::Key_ESC, 0, true, Exit);
input.set(Joystick::Button2, 0, true, Exit);
}
OptionCredits::~OptionCredits(){
}
void OptionCredits::logic(){
}
class CreditsLogicDraw : public Util::Logic, public Util::Draw{
public:
CreditsLogicDraw(std::vector<OptionCredits::Sequence> & sequences, Graphics::Color clearColor, Graphics::Color title, Graphics::Color color, const Font & font, InputMap<OptionCredits::CreditKey> & input, Menu::Context & context):
sequences(sequences),
clearColor(clearColor),
title(title),
color(color),
font(font),
input(input),
quit(false),
context(context),
current(0){
}
std::vector<OptionCredits::Sequence> & sequences;
Graphics::Color clearColor, title, color;
const Font & font;
InputMap<OptionCredits::CreditKey> & input;
bool quit;
Menu::Context & context;
unsigned int current;
void run(){
vector<InputMap<OptionCredits::CreditKey>::InputEvent> out = InputManager::getEvents(input, InputSource());
for (vector<InputMap<OptionCredits::CreditKey>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<OptionCredits::CreditKey>::InputEvent & event = *it;
if (event.enabled){
if (event.out == OptionCredits::Exit){
quit = true;
context.finish();
}
}
}
sequences[current].act();
if (sequences[current].isDone()){
sequences[current].reset();
current++;
if (current >= sequences.size()){
current = 0;
}
}
context.act();
}
bool done(){
return quit;
}
double ticks(double system){
return system * Global::ticksPerSecond(90);
}
void draw(const Graphics::Bitmap & buffer){
/* FIXME: hard coded resolution */
Graphics::StretchedBitmap work(640, 480, buffer, Graphics::qualityFilterName(Configuration::getQualityFilter()));
work.fill(clearColor);
work.start();
//background.Blit(work);
context.render(NULL, work);
sequences[current].draw(title, color, work);
work.finish();
buffer.BlitToScreen();
}
};
void OptionCredits::run(const Menu::Context & context){
Menu::Context localContext(context, *creditsContext);
localContext.initialize();
if (!music.empty()){
if (Music::loadSong(Storage::instance().find(Filesystem::RelativePath(music)).path())){
Music::pause();
Music::play();
}
}
const Font & vFont = Menu::menuFontParameter.current()->get();
CreditsLogicDraw loop(sequences, clearColor, title, color, vFont, input, localContext);
Util::standardLoop(loop, loop);
InputManager::waitForRelease(input, InputSource(), Exit);
throw Menu::Reload(__FILE__, __LINE__);
}
OptionDummy::OptionDummy(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
if ( *token != "dummy" ){
throw LoadException(__FILE__, __LINE__, "Not dummy option");
}
readName(token);
if (getText().empty()){
this->setText("Dummy");
}
setRunnable(false);
}
OptionDummy::OptionDummy(const Gui::ContextBox & parent, const std::string &name):
MenuOption(parent, 0){
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name given to dummy");
}
this->setText(name);
setRunnable(false);
}
OptionDummy::~OptionDummy(){
}
void OptionDummy::logic(){
}
void OptionDummy::run(const Menu::Context & context){
}
OptionFullscreen::OptionFullscreen(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "fullscreen" )
throw LoadException(__FILE__, __LINE__, "Not fullscreen option");
readName(token);
}
OptionFullscreen::~OptionFullscreen()
{
// Nothing
}
std::string OptionFullscreen::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << (Configuration::getFullscreen() ? "Yes" : "No");
return out.str();
}
void OptionFullscreen::logic(){;
}
static void changeScreenMode(){
Configuration::setFullscreen(!Configuration::getFullscreen());
int gfx = (Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED);
Graphics::setGraphicsMode(gfx, Global::getScreenWidth(), Global::getScreenHeight());
}
void OptionFullscreen::run(const Menu::Context & context){
changeScreenMode();
}
bool OptionFullscreen::leftKey(){
changeScreenMode();
return true;
}
bool OptionFullscreen::rightKey(){
changeScreenMode();
return true;
}
OptionFps::OptionFps(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
setRunnable(false);
}
void OptionFps::logic(){
}
void OptionFps::run(const Menu::Context & context){
}
std::string OptionFps::getText() const {
ostringstream out;
out << "Frames per second: " << Global::TICS_PER_SECOND;
return out.str();
}
bool OptionFps::leftKey(){
Global::setTicksPerSecond(Global::TICS_PER_SECOND - 1);
Configuration::setFps(Global::TICS_PER_SECOND);
return true;
}
bool OptionFps::rightKey(){
Global::setTicksPerSecond(Global::TICS_PER_SECOND + 1);
Configuration::setFps(Global::TICS_PER_SECOND);
return true;
}
OptionFps::~OptionFps(){
}
OptionQualityFilter::OptionQualityFilter(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
setRunnable(false);
}
std::string OptionQualityFilter::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getQualityFilter();
return out.str();
}
void OptionQualityFilter::logic(){
}
bool OptionQualityFilter::leftKey(){
string quality = Configuration::getQualityFilter();
if (quality == "none"){
quality = "hqx";
} else if (quality == "hqx"){
quality = "xbr";
} else if (quality == "xbr"){
quality = "none";
}
Configuration::setQualityFilter(quality);
return true;
}
bool OptionQualityFilter::rightKey(){
string quality = Configuration::getQualityFilter();
if (quality == "none"){
quality = "xbr";
} else if (quality == "hqx"){
quality = "none";
} else if (quality == "xbr"){
quality = "hqx";
}
Configuration::setQualityFilter(quality);
return true;
}
void OptionQualityFilter::run(const Menu::Context & context){
}
OptionQualityFilter::~OptionQualityFilter(){
}
OptionInvincible::OptionInvincible(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "invincible" )
throw LoadException(__FILE__, __LINE__, "Not invincible option");
readName(token);
}
OptionInvincible::~OptionInvincible()
{
// Nothing
}
std::string OptionInvincible::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << (Configuration::getInvincible() ? "Yes" : "No");
return out.str();
}
void OptionInvincible::logic(){
}
void OptionInvincible::run(const Menu::Context & context){
}
bool OptionInvincible::leftKey(){
Configuration::setInvincible(!Configuration::getInvincible());
return true;
}
bool OptionInvincible::rightKey(){
Configuration::setInvincible(!Configuration::getInvincible());
return true;
}
#if 0
static OptionJoystick::JoystickType convertToKey(const std::string &k){
std::string temp = k;
for(unsigned int i=0;i<temp.length();i++){
temp[i] = tolower(temp[i]);
}
if (temp == "up") return OptionJoystick::Up;
if (temp == "down") return OptionJoystick::Down;
if (temp == "left") return OptionJoystick::Left;
/*
if (temp == "right") return OptionJoystick::Right;
if (temp == "jump") return OptionJoystick::Jump;
if (temp == "attack1") return OptionJoystick::Attack1;
if (temp == "attack2") return OptionJoystick::Attack2;
if (temp == "attack3") return OptionJoystick::Attack3;
if (temp == "attack4") return OptionJoystick::Attack4;
if (temp == "attack5") return OptionJoystick::Attack5;
if (temp == "attack6") return OptionJoystick::Attack6;
return OptionJoystick::Invalidkey;
}
static Configuration::JoystickInput getKey(int player, OptionJoystick::JoystickType k){
switch(k){
case OptionJoystick::Up:
return Joystick::Up;
case OptionJoystick::Down:
return Joystick::Down;
case OptionJoystick::Left:
return Joystick::Left;
case OptionJoystick::Right:
return Joystick::Right;
case OptionJoystick::Jump:
return Joystick::Button4;
case OptionJoystick::Attack1:
return Joystick::Button1;
case OptionJoystick::Attack2:
return Joystick::Button2;
case OptionJoystick::Attack3:
return Joystick::Button3;
case OptionJoystick::Attack4:
return Joystick::Button4;
case OptionJoystick::Attack5:
return Joystick::Button5;
case OptionJoystick::Attack6:
return Joystick::Button6;
default:
break;
}
return Joystick::Up;
}
static void setKey(int player, OptionJoystick::JoystickType k, Configuration::JoystickInput key){
/*
switch(k){
case OptionJoystick::Up:
Configuration::setJoystickUp(player, key);
break;
case OptionJoystick::Down:
Configuration::setJoystickDown(player, key);
break;
case OptionJoystick::Left:
Configuration::setJoystickLeft(player, key);
break;
case OptionJoystick::Right:
Configuration::setJoystickRight(player, key);
break;
case OptionJoystick::Jump:
Configuration::setJoystickJump(player, key);
break;
case OptionJoystick::Attack1:
Configuration::setJoystickAttack1(player, key);
break;
case OptionJoystick::Attack2:
Configuration::setJoystickAttack2(player, key);
break;
case OptionJoystick::Attack3:
Configuration::setJoystickAttack3(player, key);
break;
case OptionJoystick::Attack4:
Configuration::setJoystickAttack4(player, key);
break;
case OptionJoystick::Attack5:
Configuration::setJoystickAttack5(player, key);
break;
case OptionJoystick::Attack6:
Configuration::setJoystickAttack6(player, key);
break;
default:
break;
}
*/
}
static Configuration::JoystickInput readJoystick(){
vector<Joystick::Key> keys;
keys.push_back(Joystick::Up);
keys.push_back(Joystick::Down);
keys.push_back(Joystick::Left);
keys.push_back(Joystick::Right);
keys.push_back(Joystick::Button1);
keys.push_back(Joystick::Button2);
keys.push_back(Joystick::Button3);
keys.push_back(Joystick::Button4);
keys.push_back(Joystick::Button5);
keys.push_back(Joystick::Button6);
InputMap<Joystick::Key> input;
for (vector<Joystick::Key>::iterator it = keys.begin(); it != keys.end(); it++){
input.set(*it, 0, true, *it);
}
input.set(Keyboard::Key_ESC, 0, true, Joystick::Invalid);
while (true){
InputManager::poll();
vector<InputMap<Joystick::Key>::InputEvent> out = InputManager::getEvents(input, InputSource());
for (vector<InputMap<Joystick::Key>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
const InputMap<Joystick::Key>::InputEvent & event = *it;
if (event.enabled){
Global::debug(1) << "Press: " << event.out << std::endl;
if (event.out == Joystick::Invalid){
InputManager::waitForRelease(input, InputSource(), Joystick::Invalid);
throw Exception::Return(__FILE__, __LINE__);
}
return event.out;
}
}
Util::rest(1);
}
/* control probably shouldn't get here.. */
return Joystick::Up;
}
OptionJoystick::OptionJoystick(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
player(-1),
type(Invalidkey),
keyCode(0){
if (*token != "joystick"){
throw LoadException(__FILE__, __LINE__, "Not joystick option");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "name" ){
tok->view() >> name;
} else if ( *tok == "player" ) {
tok->view() >> player;
} else if ( *tok == "type" ) {
std::string temp;
tok->view() >> temp;
type = convertToKey(temp);
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name set, this option should have a name!");
}
if (type == Invalidkey){
throw LoadException(__FILE__, __LINE__, "Invalid joystick button, should be up, down, left, right, up, down, jump, attack1-6!");
}
if (player == -1){
throw LoadException(__FILE__, __LINE__, "Player not specified in joystick configuration");
}
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
}
OptionJoystick::~OptionJoystick(){
// Nothing
}
void OptionJoystick::logic(){
/*
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Joystick::keyToName(getKey(player,type)));
setText(std::string(temp));
*/
}
void OptionJoystick::run(const Menu::Context & context){
/*
//int x, y, width, height;
const Font & vFont = Menu::menuFontParameter.current()->get();
const char * message = "Press a joystick button!";
const int width = vFont.textLength(message) + 10;
const int height = vFont.getHeight() + 10;
// const int x = (getParent()->getWork()->getWidth()/2) - (width/2);
// const int y = (getParent()->getWork()->getHeight()/2) - (height/2);
const int x = Menu::Menu::Width / 2 - width/2;
const int y = Menu::Menu::Height / 2 - height/2;
Box dialog;
dialog.location.setPosition(Gui::AbsolutePoint(0,0));
dialog.location.setDimensions(vFont.textLength(message) + 10, vFont.getHeight() + 10);
dialog.transforms.setRadius(0);
dialog.colors.body = Graphics::makeColor(0,0,0);
dialog.colors.bodyAlpha = 200;
dialog.colors.border = Graphics::makeColor(255,255,255);
dialog.colors.borderAlpha = 255;
Graphics::Bitmap temp = Graphics::Bitmap::temporaryBitmap(width,height);
dialog.render(temp, vFont);
vFont.printf( 5, 5, Graphics::makeColor(255,255,255), temp, message, -1);
temp.BlitToScreen(x,y);
setKey(player, type, readJoystick());
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
*/
Graphics::Bitmap temp(Menu::Menu::Width, Menu::Menu::Height);
// Menu::Context tempContext = context;
Menu::Context tempContext(context);
tempContext.initialize();
Menu::InfoBox keyDialog;
// keyDialog.setFont(tempContext.getFont());
//keyDialog.location.set(-1,-1,1,1);
const int width = temp.getWidth();
const int height = temp.getHeight();
const Font & font = Menu::menuFontParameter.current()->get();
const int radius = 15;
keyDialog.setText("Press a joystick button!");
keyDialog.initialize(font);
keyDialog.location.setDimensions(font.textLength("Press a joystick button!") + radius, font.getHeight() + radius);
keyDialog.location.setCenterPosition(Gui::RelativePoint(0, 0));
// keyDialog.location.setPosition(Gui::AbsolutePoint((width/2)-(keyDialog.location.getWidth()/2), (height/2)-(keyDialog.location.getHeight()/2)));
// keyDialog.location.setPosition2(Gui::AbsolutePoint((
keyDialog.transforms.setRadius(radius);
keyDialog.colors.body = Graphics::makeColor(0,0,0);
keyDialog.colors.bodyAlpha = 180;
keyDialog.colors.border = Graphics::makeColor(255,255,255);
keyDialog.colors.borderAlpha = 255;
keyDialog.open();
InputManager::waitForClear();
while (!InputManager::anyInput() && keyDialog.isActive()){
InputManager::poll();
keyDialog.act(font);
/*
if (keyDialog.isActive()){
InputManager::poll();
}
*/
tempContext.act();
tempContext.render(0, temp);
keyDialog.render(temp, font);
temp.BlitToScreen();
}
tempContext.finish();
setKey(player, type, readJoystick());
InputManager::waitForClear();
ostringstream out;
out << name << ": " << Joystick::keyToName(getKey(player, type));
setText(out.str());
/*
Keyboard key;
keyCode = readKey(key);
setKey(player,type, keyCode);
*/
}
#endif
static OptionKey::keyType convertToKeyboardKey(const std::string &k){
std::string temp = k;
for(unsigned int i=0;i<temp.length();i++){
temp[i] = tolower(temp[i]);
}
if (temp == "up") return OptionKey::up;
if (temp == "down") return OptionKey::down;
if (temp == "left") return OptionKey::left;
if (temp == "right") return OptionKey::right;
if (temp == "jump") return OptionKey::jump;
if (temp == "attack1") return OptionKey::attack1;
if (temp == "attack2") return OptionKey::attack2;
if (temp == "attack3") return OptionKey::attack3;
if (temp == "attack4") return OptionKey::attack4;
if (temp == "attack5") return OptionKey::attack5;
if (temp == "attack6") return OptionKey::attack6;
return OptionKey::invalidkey;
}
static int getKey(int player, OptionKey::keyType k){
switch(k){
case OptionKey::up:
return Configuration::getUp(player);
break;
case OptionKey::down:
return Configuration::getDown(player);
break;
case OptionKey::left:
return Configuration::getLeft(player);
break;
case OptionKey::right:
return Configuration::getRight(player);
break;
case OptionKey::jump:
return Configuration::getJump(player);
break;
case OptionKey::attack1:
return Configuration::getAttack1(player);
break;
case OptionKey::attack2:
return Configuration::getAttack2(player);
break;
case OptionKey::attack3:
return Configuration::getAttack3(player);
break;
case OptionKey::attack4:
return Configuration::getAttack4(player);
case OptionKey::attack5:
return Configuration::getAttack5(player);
case OptionKey::attack6:
return Configuration::getAttack6(player);
default:
break;
}
return 0;
}
static void setKey(int player, OptionKey::keyType k, int key){
switch(k){
case OptionKey::up:
Configuration::setUp(player, key);
break;
case OptionKey::down:
Configuration::setDown(player, key);
break;
case OptionKey::left:
Configuration::setLeft(player, key);
break;
case OptionKey::right:
Configuration::setRight(player, key);
break;
case OptionKey::jump:
Configuration::setJump(player, key);
break;
case OptionKey::attack1:
Configuration::setAttack1(player, key);
break;
case OptionKey::attack2:
Configuration::setAttack2(player, key);
break;
case OptionKey::attack3:
Configuration::setAttack3(player, key);
break;
case OptionKey::attack4:
Configuration::setAttack4(player, key);
break;
case OptionKey::attack5:
Configuration::setAttack5(player, key);
break;
case OptionKey::attack6:
Configuration::setAttack6(player, key);
break;
default:
break;
}
}
/*
static int readKey( Keyboard & key ){
int k = key.readKey();
key.wait();
return k;
}
*/
OptionKey::OptionKey(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
player(-1),
type(invalidkey),
keyCode(0){
if ( *token != "key" )
throw LoadException(__FILE__, __LINE__, "Not key option");
TokenView view = token->view();
while (view.hasMore()) {
try {
const Token * tok;
view >> tok;
if ( *tok == "name" ) {
tok->view() >> name;
} else if ( *tok == "player" ) {
tok->view() >> player;
} else if ( *tok == "type" ) {
std::string temp;
tok->view() >> temp;
type = convertToKeyboardKey(temp);
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
} catch ( const TokenException & ex ){
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
if(name.empty())throw LoadException(__FILE__, __LINE__, "No name set, this option should have a name!");
if(type == invalidkey)throw LoadException(__FILE__, __LINE__, "Invalid key, should be up, down, left, right, up, down, jump, attack1-6!");
if(player == -1)throw LoadException(__FILE__, __LINE__, "Player not specified in key configuration");
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
setText(std::string(temp));
}
OptionKey::~OptionKey(){
// Nothing
}
void OptionKey::logic(){
char temp[255];
sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
setText(std::string(temp));
}
void OptionKey::run(const Menu::Context & context){
// Do dialog
//Box::messageDialog(Menu::Menu::Width, Menu::Menu::Height, "Press a Key!",2);
/*
Keyboard key;
key.wait();
*/
Graphics::Bitmap temp(Menu::Menu::Width, Menu::Menu::Height);
// Menu::Context tempContext = context;
Menu::Context tempContext(context);
tempContext.initialize();
Menu::InfoBox keyDialog;
// keyDialog.setFont(tempContext.getFont());
//keyDialog.location.set(-1,-1,1,1);
const int width = temp.getWidth();
const int height = temp.getHeight();
const Font & font = Menu::menuFontParameter.current()->get();
const int radius = 15;
keyDialog.setText("Press a Key!");
keyDialog.initialize(font);
keyDialog.location.setDimensions(font.textLength("Press a Key!") + radius, font.getHeight() + radius);
keyDialog.location.setCenterPosition(Gui::RelativePoint(0, 0));
// keyDialog.location.setPosition(Gui::AbsolutePoint((width/2)-(keyDialog.location.getWidth()/2), (height/2)-(keyDialog.location.getHeight()/2)));
// keyDialog.location.setPosition2(Gui::AbsolutePoint((
keyDialog.transforms.setRadius(radius);
keyDialog.colors.body = Graphics::makeColor(0,0,0);
keyDialog.colors.bodyAlpha = 180;
keyDialog.colors.border = Graphics::makeColor(255,255,255);
keyDialog.colors.borderAlpha = 255;
keyDialog.open();
InputManager::waitForClear();
while (!InputManager::anyInput() && keyDialog.isActive()){
InputManager::poll();
keyDialog.act(font);
/*
if (keyDialog.isActive()){
InputManager::poll();
}
*/
tempContext.act();
tempContext.render(0, temp);
keyDialog.render(temp, font);
temp.BlitToScreen();
}
tempContext.finish();
keyCode = InputManager::readKey();
setKey(player,type, keyCode);
InputManager::waitForClear();
}
OptionLevel::OptionLevel(const Gui::ContextBox & parent, const Token *token, int * set, int value):
MenuOption(parent, token),
set(set),
value(value){
// Nothing
}
OptionLevel::~OptionLevel(){
}
void OptionLevel::logic(){
}
void OptionLevel::run(const Menu::Context & context){
*set = value;
throw Menu::MenuException(__FILE__, __LINE__);
}
OptionLives::OptionLives(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "lives" ){
throw LoadException(__FILE__, __LINE__, "Not lives option" );
}
readName(token);
}
OptionLives::~OptionLives(){
}
std::string OptionLives::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getLives();
return out.str();
}
void OptionLives::logic(){
}
void OptionLives::run(const Menu::Context & context){
}
bool OptionLives::leftKey(){
Configuration::setLives(Configuration::getLives() - 1);
if ( Configuration::getLives() < 1 ){
Configuration::setLives(1);
}
return false;
}
bool OptionLives::rightKey(){
Configuration::setLives( Configuration::getLives() + 1 );
return false;
}
OptionMenu::OptionMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory):
MenuOption(parent, token),
menu(0){
if (*token != "menu"){
throw LoadException(__FILE__, __LINE__, "Not a menu");
}
if (token->numTokens() == 1){
std::string temp;
token->view() >> temp;
menu = new Menu::Menu(Storage::instance().find(Filesystem::RelativePath(temp)), factory);
} else {
menu = new Menu::Menu(token, factory);
}
this->setText(menu->getName());
this->setInfoText(menu->getInfo());
// Lets check if this menu is going bye bye
//if ( menu->checkRemoval() ) setForRemoval(true);
}
OptionMenu::~OptionMenu(){
// Delete our menu
if (menu){
delete menu;
}
}
void OptionMenu::logic(){
// Nothing
}
void OptionMenu::run(const Menu::Context & context){
// Do our new menu
try{
menu->run(context);
} catch (const Exception::Return ignore){
throw Menu::Reload(__FILE__, __LINE__);
}
}
OptionNpcBuddies::OptionNpcBuddies(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "npc" ){
throw LoadException(__FILE__, __LINE__, "Not npc option" );
}
readName(token);
}
OptionNpcBuddies::~OptionNpcBuddies(){
// Nothing
}
std::string OptionNpcBuddies::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getNpcBuddies();
return out.str();
}
void OptionNpcBuddies::logic(){
}
void OptionNpcBuddies::run(const Menu::Context & context){
}
bool OptionNpcBuddies::leftKey(){
Configuration::setNpcBuddies(Configuration::getNpcBuddies() - 1);
if ( Configuration::getNpcBuddies() < 1 ){
Configuration::setNpcBuddies(1);
}
return false;
}
bool OptionNpcBuddies::rightKey(){
Configuration::setNpcBuddies( Configuration::getNpcBuddies() + 1 );
rblue = rgreen = 0;
return false;
}
OptionPlayMode::OptionPlayMode(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "play-mode" ){
throw LoadException(__FILE__, __LINE__, "Not a play-mode");
}
readName(token);
}
OptionPlayMode::~OptionPlayMode(){
// Nothing
}
std::string OptionPlayMode::getText() const {
ostringstream out;
out << MenuOption::getText() << ": ";
/* TODO: language translations of these */
if (Configuration::getPlayMode() == Configuration::FreeForAll){
out << "Free for all";
} else if (Configuration::getPlayMode() == Configuration::Cooperative){
out << "Cooperative";
}
return out.str();
}
void OptionPlayMode::logic(){
}
void OptionPlayMode::run(const Menu::Context & context){
}
void OptionPlayMode::changeMode(){
if (Configuration::getPlayMode() == Configuration::FreeForAll){
Configuration::setPlayMode(Configuration::Cooperative);
} else if (Configuration::getPlayMode() == Configuration::Cooperative){
Configuration::setPlayMode(Configuration::FreeForAll);
}
}
bool OptionPlayMode::leftKey(){
changeMode();
lblue = lgreen = 0;
return true;
}
bool OptionPlayMode::rightKey(){
changeMode();
rblue = rgreen = 0;
return true;
}
OptionReturn::OptionReturn(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
if (*token != "return"){
throw LoadException(__FILE__, __LINE__, "Not a return option");
}
readName(token);
}
void OptionReturn::logic(){
}
/* maybe this option is misnamed, but its supposed to quit the current game
* and go back to the main menu
*/
void OptionReturn::run(const Menu::Context & context){
throw Exception::Quit(__FILE__, __LINE__);
}
OptionReturn::~OptionReturn(){
}
OptionContinue::OptionContinue(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
if (*token != "continue"){
throw LoadException(__FILE__, __LINE__, "Not a continue option");
}
readName(token);
}
void OptionContinue::logic(){
}
void OptionContinue::run(const Menu::Context & context){
throw Exception::Return(__FILE__, __LINE__);
}
OptionContinue::~OptionContinue(){
}
OptionQuit::OptionQuit(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
if ( *token != "quit" ){
throw LoadException(__FILE__, __LINE__, "Not quit option");
}
readName(token);
}
OptionQuit::OptionQuit(const Gui::ContextBox & parent, const std::string &name):
MenuOption(parent, 0){
if (name.empty()){
throw LoadException(__FILE__, __LINE__, "No name given to quit");
}
this->setText(name);
}
OptionQuit::~OptionQuit(){
}
void OptionQuit::logic(){
}
void OptionQuit::run(const Menu::Context & context){
throw ShutdownException();
}
#if defined(WINDOWS) && defined(doesnt_work_yet)
#include <windows.h>
#include <stdio.h>
/* contributed by Roy Underthump from allegro.cc */
static vector<ScreenSize> getScreenResolutions(){
HWND hwnd;
HDC hdc;
// int iPixelFormat;
int descerr;
int retval;
DEVMODE d;
PIXELFORMATDESCRIPTOR pfd;
hwnd = GetDesktopWindow();
hdc = GetDC(hwnd);
vector<ScreenSize> modes;
for (int i = 0;; i++){
retval = EnumDisplaySettings(0,i,&d);
if (!retval){
break;
}
descerr = DescribePixelFormat(hdc, i+1, sizeof(pfd), &pfd);
if(!descerr){
continue;
}
/*
printf("\n#%d bpp %d width %d height %d colorbits %d fps %d",i,d.dmBitsPerPel,
d.dmPelsWidth, d.dmPelsHeight,pfd.cColorBits,d.dmDisplayFrequency);
if(pfd.dwFlags & PFD_SUPPORT_OPENGL)printf(" OGL OK");
*/
modes.push_back(ScreenSize(d.dmPelsWidth, d.dmPelsHeight));
}
if (modes.empty()){
modes.push_back(ScreenSize(640,480));
}
return modes;
}
#else
static vector<ScreenSize> getScreenResolutions(){
vector<ScreenSize> modes;
modes.push_back(ScreenSize(320, 240));
modes.push_back(ScreenSize(640, 480));
modes.push_back(ScreenSize(800, 600));
modes.push_back(ScreenSize(960, 720));
modes.push_back(ScreenSize(1024, 768));
modes.push_back(ScreenSize(1280, 960));
modes.push_back(ScreenSize(1600, 1200));
return modes;
}
#endif
static bool doSort(const ScreenSize & a, const ScreenSize & b){
return (a.w * a.h) < (b.w * b.h);
}
static vector<ScreenSize> sortResolutions(const vector<ScreenSize> & modes){
vector<ScreenSize> copy(modes);
std::sort(copy.begin(), copy.end(), doSort);
return copy;
}
OptionScreenSize::OptionScreenSize(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
Global::debug(1) << "Get screen resolution" << endl;
modes = sortResolutions(getScreenResolutions());
if (Global::getDebug() >= 1){
for (vector<ScreenSize>::iterator it = modes.begin(); it != modes.end(); it++){
Global::debug(1) << "Screen size: " << it->w << " x " << it->h << endl;
}
}
if ( *token != "screen-size" ){
throw LoadException(__FILE__, __LINE__, "Not a screen-size");
}
readName(token);
}
OptionScreenSize::~OptionScreenSize(){
// Nothing
}
void OptionScreenSize::logic(){
ostringstream temp;
temp << "Screen size: " << Configuration::getScreenWidth() << " x " << Configuration::getScreenHeight();
setText(temp.str());
}
void OptionScreenSize::run(const Menu::Context & context){
}
void OptionScreenSize::setMode(int width, int height){
if (width != Configuration::getScreenWidth() ||
height != Configuration::getScreenHeight()){
Global::debug(1) << "Changing mode to " << width << " x " << height << endl;
int gfx = Configuration::getFullscreen() ? Global::FULLSCREEN : Global::WINDOWED;
int ok = Graphics::setGraphicsMode(gfx, width, height);
if (ok == 0){
Global::debug(1) << "Success" << endl;
Configuration::setScreenWidth(width);
Configuration::setScreenHeight(height);
} else {
Global::debug(1) << "Fail" << endl;
int ok = Graphics::setGraphicsMode(gfx, Configuration::getScreenWidth(), Configuration::getScreenHeight());
Global::debug(1) << "Set mode back " << ok << endl;
}
}
}
/*
static int modes[][2] = {{640,480}, {800,600}, {1024,768}, {1280,1024}, {1600,1200}};
// static int max_modes = sizeof(modes) / sizeof(int[]);
static int max_modes = 5;
*/
int OptionScreenSize::findMode(int width, int height){
for (int mode = 0; mode < (int) modes.size(); mode++){
if (modes[mode].w == width && modes[mode].h == height){
return mode;
}
}
return -1;
}
bool OptionScreenSize::leftKey(){
int mode = findMode(Configuration::getScreenWidth(), Configuration::getScreenHeight());
if (mode >= 1 && mode < (int)modes.size()){
mode -= 1;
} else {
mode = 0;
}
setMode(modes[mode].w, modes[mode].h);
lblue = lgreen = 0;
return true;
}
bool OptionScreenSize::rightKey(){
int mode = findMode(Configuration::getScreenWidth(), Configuration::getScreenHeight());
if (mode >= 0 && mode < (int)modes.size() - 1){
mode += 1;
} else {
mode = 0;
}
setMode(modes[mode].w, modes[mode].h);
rblue = rgreen = 0;
return true;
}
static string joinPaths(const vector<Filesystem::AbsolutePath> & strings, const string & middle){
ostringstream out;
for (vector<Filesystem::AbsolutePath>::const_iterator it = strings.begin(); it != strings.end(); it++){
out << (*it).path() << middle;
}
return out.str();
}
static bool sortInfo(const Util::ReferenceCount<Menu::FontInfo> & info1,
const Util::ReferenceCount<Menu::FontInfo> & info2){
string name1 = Util::lowerCaseAll(info1->getName());
string name2 = Util::lowerCaseAll(info2->getName());
return name1 < name2;
}
static bool isWindows(){
#ifdef WINDOWS
return true;
#else
return false;
#endif
}
static bool isOSX(){
#ifdef MACOSX
return true;
#else
return false;
#endif
}
template <class X>
static vector<X> operator+(const vector<X> & v1, const vector<X> & v2){
vector<X> out;
for (typename vector<X>::const_iterator it = v1.begin(); it != v1.end(); it++){
out.push_back(*it);
}
for (typename vector<X>::const_iterator it = v2.begin(); it != v2.end(); it++){
out.push_back(*it);
}
return out;
}
static vector<Filesystem::AbsolutePath> findSystemFonts(){
if (isWindows()){
const char * windows = getenv("windir");
if (windows != NULL){
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath(string(windows) + "/fonts"), "*.ttf");
}
return vector<Filesystem::AbsolutePath>();
} else if (isOSX()){
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/Library/Fonts"), "*.ttf");
} else {
/* assume unix/linux conventions */
return Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/usr/share/fonts/truetype"), "*.ttf") +
Storage::instance().getFilesRecursive(Filesystem::AbsolutePath("/usr/local/share/fonts/truetype"), "*.ttf");
}
}
static vector<Util::ReferenceCount<Menu::FontInfo> > findFonts(){
vector<Util::ReferenceCount<Menu::FontInfo> > fonts;
try{
Filesystem::AbsolutePath fontsDirectory = Storage::instance().find(Filesystem::RelativePath("fonts"));
Global::debug(1, "fonts") << "Font directory " << fontsDirectory.path() << endl;
vector<Filesystem::AbsolutePath> ttfFonts = Storage::instance().getFiles(fontsDirectory, "*.ttf");
Global::debug(1, "fonts") << "Found ttf fonts " << joinPaths(ttfFonts, ", ") << endl;
vector<Filesystem::AbsolutePath> otfFonts = Storage::instance().getFiles(fontsDirectory, "*.otf");
Global::debug(1, "fonts") << "Found otf fonts " << joinPaths(otfFonts, ", ") << endl;
for (vector<Filesystem::AbsolutePath>::iterator it = ttfFonts.begin(); it != ttfFonts.end(); it++){
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::RelativeFontInfo(Storage::instance().cleanse(*it), Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
for (vector<Filesystem::AbsolutePath>::iterator it = otfFonts.begin(); it != otfFonts.end(); it++){
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::RelativeFontInfo(Storage::instance().cleanse(*it), Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
/* linux specific fonts */
vector<Filesystem::AbsolutePath> systemFonts = findSystemFonts();
for (vector<Filesystem::AbsolutePath>::iterator it = systemFonts.begin(); it != systemFonts.end(); it++){
Global::debug(1) << "Adding system font `" << (*it).path() << "'" << endl;
fonts.push_back(Util::ReferenceCount<Menu::FontInfo>(new Menu::AbsoluteFontInfo(*it, Configuration::getMenuFontWidth(), Configuration::getMenuFontHeight())));
}
sort(fonts.begin(), fonts.end(), sortInfo);
// DEFAULT (blank)
// fonts.insert(fonts.begin(), new Menu::DefaultFontInfo());
fonts.insert(fonts.begin(), Util::ReferenceCount<Menu::FontInfo>(NULL));
} catch (const Filesystem::NotFound & e){
throw LoadException(__FILE__, __LINE__, e, "Could not load font");
}
return fonts;
}
OptionSelectFont::OptionSelectFont(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
typeAdjust(fontName),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "font-select" ){
throw LoadException(__FILE__, __LINE__, "Not a font selector");
}
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
if ( *tok == "adjust" ){
std::string temp;
tok->view() >> temp;
if ( temp == "name" ) typeAdjust = fontName;
else if ( temp == "width" ) typeAdjust = fontWidth;
else if ( temp == "height" ) typeAdjust = fontHeight;
else throw LoadException(__FILE__, __LINE__, "Incorrect value \"" + temp + "\" in font-select");
} else {
Global::debug(3) << "Unhandled menu attribute: " << endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch ( const LoadException & ex ) {
// delete current;
throw ex;
}
}
}
void OptionSelectFont::open(){
// Find and set fonts now
if (typeAdjust == fontName){
fonts = findFonts();
}
}
void OptionSelectFont::close(){
if (typeAdjust == fontName){
/* the user probably loaded a bunch of different fonts that will
* never be used again, so clear the font cache
* TODO: dont clear the currently selected font
*/
FontFactory::clear();
}
}
OptionSelectFont::~OptionSelectFont(){
// Nothing
}
void OptionSelectFont::logic(){
/* FIXME Get current font and display info */
switch (typeAdjust){
case fontName:{
std::string name;
if (Configuration::hasMenuFont()){
name = Configuration::getMenuFont()->getName();
} else {
name = "Default";
}
setText("Current Font: " + name);
break;
}
case fontWidth:{
ostringstream temp;
temp << "Font Width: " << Configuration::getMenuFontWidth();
setText(temp.str());
break;
}
case fontHeight:{
ostringstream temp;
temp << "Font Height: " << Configuration::getMenuFontHeight();
setText(temp.str());
break;
}
default: break;
}
if (lblue < 255){
lblue += 5;
}
if (rblue < 255){
rblue += 5;
}
if (lgreen < 255){
lgreen += 5;
}
if (rgreen < 255){
rgreen += 5;
}
}
void OptionSelectFont::run(const Menu::Context & context){
// throw Menu::MenuException(__FILE__, __LINE__);
/* throw something to quit back to the previous menu */
}
bool OptionSelectFont::leftKey(){
switch (typeAdjust){
case fontName:
nextIndex(false);
break;
case fontWidth:
Configuration::setMenuFontWidth(Configuration::getMenuFontWidth() - 1);
break;
case fontHeight:
Configuration::setMenuFontHeight(Configuration::getMenuFontHeight() - 1);
break;
default:
break;
}
lblue = lgreen = 0;
return true;
}
bool OptionSelectFont::rightKey(){
switch (typeAdjust){
case fontName:
nextIndex(true);
break;
case fontWidth:
Configuration::setMenuFontWidth(Configuration::getMenuFontWidth() + 1);
break;
case fontHeight:
Configuration::setMenuFontHeight(Configuration::getMenuFontHeight() + 1);
break;
default:
break;
}
rblue = rgreen = 0;
return true;
}
static bool saneFont(const Util::ReferenceCount<Menu::FontInfo> & info){
class Context: public Loader::LoadingContext {
public:
Context(const Util::ReferenceCount<Menu::FontInfo> & info):
info(info),
isok(false){
}
bool ok(){
try{
const Font & font = info->get();
return font.textLength("A") != 0 &&
font.getHeight() != 0;
} catch (const Exception::Base & ignore){
return true;
}
}
virtual void load(){
isok = ok();
}
const Util::ReferenceCount<Menu::FontInfo> & info;
bool isok;
};
if (info == NULL){
return true;
}
Context context(info);
/* an empty Info object, we don't really care about it */
Loader::Info level;
Loader::loadScreen(context, level, Loader::SimpleCircle);
return context.isok;
}
void OptionSelectFont::nextIndex(bool forward){
if (fonts.size() == 0){
return;
}
int index = 0;
for (unsigned int i = 0 ; i < fonts.size() ; ++i){
if ((Configuration::getMenuFont() == NULL && fonts[i] == NULL) ||
((Configuration::getMenuFont() != NULL && fonts[i] != NULL) &&
(*Configuration::getMenuFont() == *fonts[i]))){
index = i;
}
}
if (forward){
index++;
if (index >= (int) fonts.size()){
index = 0;
}
} else {
index--;
if (index < 0){
index = (int)fonts.size()-1;
}
}
while (!saneFont(fonts[index])){
Global::debug(0) << "Warning: erasing font `" << fonts[index]->getName() << "'" << endl;
int where = 0;
vector<Util::ReferenceCount<Menu::FontInfo> >::iterator it;
for (it = fonts.begin(); it != fonts.end() && where != index; it++, where++){
}
fonts.erase(it);
if (index >= (int) fonts.size()){
index = fonts.size() - 1;
}
}
Configuration::setMenuFont(fonts[index]);
/* FIXME */
/*
if (fonts[index] == "Default"){
Configuration::setMenuFont("");
} else {
Configuration::setMenuFont(fonts[index]);
}
*/
}
OptionSpeed::OptionSpeed(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
name(""),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if ( *token != "speed" )
throw LoadException(__FILE__, __LINE__, "Not speed option");
readName(token);
}
OptionSpeed::~OptionSpeed(){
// Nothing
}
std::string OptionSpeed::getText() const {
ostringstream out;
out << MenuOption::getText() << ": " << Configuration::getGameSpeed();
return out.str();
}
void OptionSpeed::logic(){
/*
//ostringstream temp;
char temp[255];
sprintf( temp, "%s: %0.2f", name.c_str(), MenuGlobals::getGameSpeed() );
setText(std::string(temp));
*/
}
void OptionSpeed::run(const Menu::Context & context){
}
bool OptionSpeed::leftKey(){
Configuration::setGameSpeed(Configuration::getGameSpeed() - 0.05);
if (Configuration::getGameSpeed() < 0.1){
Configuration::setGameSpeed(0.1);
}
return false;
}
bool OptionSpeed::rightKey(){
Configuration::setGameSpeed(Configuration::getGameSpeed() + 0.05);
rblue = rgreen = 0;
return false;
}
OptionTabMenu::OptionTabMenu(const Gui::ContextBox & parent, const Token *token, const Menu::OptionFactory & factory):
MenuOption(parent, token),
menu(0){
if (token->numTokens() == 1){
std::string temp;
token->view() >> temp;
menu = new Menu::Menu(Storage::instance().find(Filesystem::RelativePath(temp)), factory, Menu::Menu::Tabbed);
} else {
menu = new Menu::Menu(token, factory, Menu::Menu::Tabbed);
}
// this->setText(menu->getName());
// token->print("Menu: ");
const Token * tok = token->findToken("_/name");
if (tok != NULL){
std::string name;
tok->view() >> name;
// Global::debug(0, "menu") << "Menu name: " << name << endl;
this->setText(name);
} else {
// No name?
throw LoadException(__FILE__, __LINE__, "Menu has no name");
}
}
OptionTabMenu::~OptionTabMenu(){
// Delete our menu
if (menu){
delete menu;
}
}
void OptionTabMenu::logic(){
// Nothing
}
void OptionTabMenu::run(const Menu::Context & context){
// Do our new menu
// menu->run(context);
try{
menu->run(context);
} catch (const Exception::Return ignore){
throw Menu::Reload(__FILE__, __LINE__);
}
}
OptionSound::OptionSound(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if (*token != "sound" ){
throw LoadException(__FILE__, __LINE__, "Not a sound option");
}
readName(token);
originalName = getName();
}
OptionSound::~OptionSound(){
}
void OptionSound::logic(){
ostringstream temp;
temp << originalName << ": " << Configuration::getSoundVolume();
setText(temp.str());
}
void OptionSound::run(const Menu::Context & context){
}
void OptionSound::changeSound(int much){
int volume = Configuration::getSoundVolume();
volume += much;
if (volume < 0){
volume = 0;
}
if (volume > 100){
volume = 100;
}
Configuration::setSoundVolume(volume);
}
bool OptionSound::leftKey(){
changeSound(-1);
lblue = lgreen = 0;
return true;
}
bool OptionSound::rightKey(){
changeSound(+1);
rblue = rgreen = 0;
return true;
}
OptionMusic::OptionMusic(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token),
lblue(255),
lgreen(255),
rblue(255),
rgreen(255){
setRunnable(false);
if (*token != "music" ){
throw LoadException(__FILE__, __LINE__, "Not a music option");
}
readName(token);
originalName = getName();
}
void OptionMusic::logic(){
ostringstream temp;
temp << originalName << ": " << Configuration::getMusicVolume();
setText(temp.str());
}
void OptionMusic::run(const Menu::Context & context){
}
void OptionMusic::changeMusic(int much){
int volume = Configuration::getMusicVolume();
volume += much;
if (volume < 0){
volume = 0;
}
if (volume > 100){
volume = 100;
}
Configuration::setMusicVolume(volume);
Music::setVolume((double) volume / 100.0);
}
bool OptionMusic::leftKey(){
changeMusic(-1);
lblue = lgreen = 0;
return true;
}
bool OptionMusic::rightKey(){
changeMusic(+1);
lblue = lgreen = 0;
return true;
}
OptionMusic::~OptionMusic(){
}
OptionLanguage::OptionLanguage(const Gui::ContextBox & parent, const Token * token):
MenuOption(parent, token){
readName(token);
#if 0
const Token * start = token->getRootParent();
vector<const Token*> tokens = start->findTokens("*/language");
vector<string> all;
for (vector<const Token*>::iterator it = tokens.begin(); it != tokens.end(); it++){
string language;
const Token * token = *it;
if (token->match("language", language)){
all.push_back(language);
}
}
sort(all.begin(), all.end());
unique_copy(all.begin(), all.end(), back_insert_iterator<vector<string> >(languages));
// Global::debug(0) << "Found " << languages.size() << " languages" << endl;
#endif
}
void OptionLanguage::run(const Menu::Context & context){
class LanguageOption: public MenuOption {
public:
LanguageOption(const Gui::ContextBox & parent, const string & language):
MenuOption(parent, NULL){
setText(language);
setInfoText(language);
}
virtual void logic(){
}
virtual void run(const ::Menu::Context & context){
Configuration::setLanguage(getText());
Configuration::saveConfiguration();
throw ::Menu::MenuException(__FILE__, __LINE__);
}
};
Menu::Menu temp;
- /* FIXME don't hardcode arial.ttf */
- Util::ReferenceCount<Menu::FontInfo> info(new Menu::RelativeFontInfo(Filesystem::RelativePath("fonts/arial.ttf"), 24, 24));
+ Util::ReferenceCount<Menu::FontInfo> info(new Menu::RelativeFontInfo(Global::DEFAULT_FONT, 24, 24));
temp.setFont(info);
const Gui::ContextBox & box = ((Menu::DefaultRenderer*) temp.getRenderer())->getBox();
vector<string> languages = context.getLanguages();
for (vector<string>::iterator it = languages.begin(); it != languages.end(); it++){
temp.addOption(new LanguageOption(box, *it));
}
try {
temp.run(context);
} catch (const Exception::Return & ignore){
} catch (const Menu::MenuException & ex){
}
throw Menu::Reload(__FILE__, __LINE__);
// throw Exception::Return(__FILE__, __LINE__);
}
void OptionLanguage::logic(){
}
OptionGibs::OptionGibs(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
setRunnable(false);
if (*token != "gibs" ){
throw LoadException(__FILE__, __LINE__, "Not a gibs option");
}
readName(token);
originalName = getName();
}
void OptionGibs::logic(){
ostringstream temp;
/* FIXME: we want to use Gib::GibProperty here but that would necessitate a
* dependancy on the Paintown engine.
*/
temp << originalName << ": " << Configuration::getProperty("paintown/gibs", 5);
setText(temp.str());
}
void OptionGibs::run(const Menu::Context & context){
}
void OptionGibs::changeGibs(int much){
int gibs = Configuration::getProperty("paintown/gibs", 5);
gibs += much;
if (gibs < 0){
gibs = 0;
}
if (gibs > 10){
gibs = 10;
}
Configuration::setProperty("paintown/gibs", gibs);
}
bool OptionGibs::leftKey(){
changeGibs(-1);
return true;
}
bool OptionGibs::rightKey(){
changeGibs(+1);
return true;
}
OptionGibs::~OptionGibs(){
}
OptionJoystick::OptionJoystick(const Gui::ContextBox & parent, const Token *token):
MenuOption(parent, token){
setRunnable(true);
if (*token != "joystick" ){
throw LoadException(__FILE__, __LINE__, "Not a joystick option");
}
readName(token);
}
void OptionJoystick::logic(){
}
+class JoystickLogicDraw: public Util::Logic, public Util::Draw {
+public:
+ JoystickLogicDraw():
+ quit(false){
+ }
+
+ bool quit;
+
+ virtual void run(){
+ }
+
+ bool done(){
+ return quit;
+ }
+
+ double ticks(double system){
+ return system * Global::ticksPerSecond(60);
+ }
+
+ void draw(const Graphics::Bitmap & buffer){
+ }
+};
+
void OptionJoystick::run(const Menu::Context & context){
+ Menu::Menu temp;
+ /*
+ Util::ReferenceCount<Menu::FontInfo> info(new Menu::RelativeFontInfo(Global::DEFAULT_FONT, 24, 24));
+ temp.setFont(info);
+ */
+
+ /* FIXME: getting the context box like this is annoying (due to the down cast) */
+ Gui::ContextBox & box = ((Menu::DefaultRenderer*) temp.getRenderer())->getBox();
+ box.setListType(ContextBox::Normal);
+
+ map<int, Util::ReferenceCount<Joystick> > joysticks = InputManager::getJoysticks();
+ for (map<int, Util::ReferenceCount<Joystick> >::iterator it = joysticks.begin(); it != joysticks.end(); it++){
+ ostringstream out;
+ out << "Joystick " << (it->first + 1);
+ OptionDummy * option = new OptionDummy(box, out.str());
+ option->setInfoText(it->second->getName());
+ temp.addOption(option);
+ }
+
+ if (joysticks.size() == 0){
+ temp.addOption(new OptionDummy(box, "No joysticks found!"));
+ }
+
+ try {
+ temp.run(context);
+ } catch (const Exception::Return & ignore){
+ } catch (const Menu::MenuException & ex){
+ }
}
OptionJoystick::~OptionJoystick(){
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jan 30, 2:57 PM (5 d, 9 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55420
Default Alt Text
(127 KB)

Event Timeline