Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
157 KB
Referenced Files
None
Subscribers
None
diff --git a/src/CreditsMenu.cpp b/src/CreditsMenu.cpp
new file mode 100644
index 0000000..434a08d
--- /dev/null
+++ b/src/CreditsMenu.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2011-2013 Me and My Shadow
+ *
+ * This file is part of Me and My Shadow.
+ *
+ * Me and My Shadow is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Me and My Shadow is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Functions.h"
+#include "GameState.h"
+#include "CreditsMenu.h"
+#include "ThemeManager.h"
+#include "GUITextArea.h"
+#include "InputManager.h"
+#include "MusicManager.h"
+#include <iostream>
+
+using namespace std;
+
+/////////////////////////CREDITS_MENU//////////////////////////////////
+
+Credits::Credits(ImageManager& imageManager,SDL_Renderer& renderer){
+ //Render the title.
+ title=textureFromText(renderer, *fontTitle,_("Credits"),objThemes.getTextColor(false));
+
+ //Vector that will hold every line of the credits.
+ vector<string> credits;
+
+ //Open the AUTHORS file and read every line.
+ {
+ ifstream fin((getDataPath()+"/../AUTHORS").c_str());
+ if(!fin.is_open()) {
+ cerr<<"ERROR: Unable to open the AUTHORS file."<<endl;
+ credits.push_back("ERROR: Unable to open the AUTHORS file.");
+ credits.push_back("");
+ }
+
+ //Loop the lines of the file.
+ string line;
+ while(getline(fin,line)){
+ credits.push_back(line);
+ }
+ }
+
+ //Enter a new line between the two files.
+ credits.push_back("");
+
+ //Open the Credits.text file and read every line.
+ {
+ ifstream fin((getDataPath()+"/Credits.txt").c_str());
+ if(!fin.is_open()) {
+ cerr<<"ERROR: Unable to open the Credits.txt file."<<endl;
+ credits.push_back("ERROR: Unable to open the Credits.txt file.");
+ credits.push_back("");
+ }
+
+ //Loop the lines of the file.
+ string line;
+ while(getline(fin,line)){
+ credits.push_back(line);
+
+ //NOTE: Some sections point to other credits files.
+ if(line=="music/") {
+ vector<string> musicCredits=getMusicManager()->createCredits();
+ credits.insert(credits.end(),musicCredits.begin(),musicCredits.end());
+ }
+ }
+ }
+
+ //Create the root element of the GUI.
+ if(GUIObjectRoot){
+ delete GUIObjectRoot;
+ GUIObjectRoot=NULL;
+ }
+ GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
+
+ //Create back button.
+ backButton=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,36,_("Back"),0,true,true,GUIGravityCenter);
+ backButton->name="cmdBack";
+ backButton->eventCallback=this;
+ GUIObjectRoot->addChild(backButton);
+
+ //Create a text area for credits.
+ textArea=new GUITextArea(imageManager,renderer,SCREEN_WIDTH*0.05,114,SCREEN_WIDTH*0.9,SCREEN_HEIGHT-200);
+ textArea->setFont(fontMono);
+ textArea->setStringArray(renderer, std::move(credits));
+ textArea->editable=false;
+ textArea->extractHyperlinks();
+ GUIObjectRoot->addChild(textArea);
+}
+
+Credits::~Credits(){
+ //Delete the GUI.
+ if(GUIObjectRoot){
+ delete GUIObjectRoot;
+ GUIObjectRoot=NULL;
+ }
+}
+
+void Credits::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
+ //Check what type of event it was.
+ if(eventType==GUIEventClick){
+ if(name=="cmdBack"){
+ //Goto the main menu.
+ setNextState(STATE_MENU);
+ }
+ }
+}
+
+void Credits::handleEvents(ImageManager&, SDL_Renderer&){
+ //Check if we need to quit, if so enter the exit state.
+ if(event.type==SDL_QUIT){
+ setNextState(STATE_EXIT);
+ }
+
+ //Check movement
+ if (inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
+ isKeyboardOnly = true;
+ textArea->scrollScrollbar(20, 0);
+ } else if (inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
+ isKeyboardOnly = true;
+ textArea->scrollScrollbar(-20, 0);
+ } else if (inputMgr.isKeyDownEvent(INPUTMGR_UP)){
+ isKeyboardOnly = true;
+ textArea->scrollScrollbar(0, -1);
+ } else if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN)){
+ isKeyboardOnly = true;
+ textArea->scrollScrollbar(0, 1);
+ }
+
+ //Check if the escape button is pressed, if so go back to the main menu.
+ if(inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
+ setNextState(STATE_MENU);
+ }
+}
+
+void Credits::logic(ImageManager&, SDL_Renderer&){}
+
+void Credits::render(ImageManager&,SDL_Renderer &renderer){
+ //Draw background.
+ objThemes.getBackground(true)->draw(renderer);
+ objThemes.getBackground(true)->updateAnimation();
+
+ //Now render the title.
+ drawTitleTexture(SCREEN_WIDTH, *title, renderer);
+
+ //NOTE: The rendering of the GUI is done in Main.
+}
+
+void Credits::resize(ImageManager&, SDL_Renderer&){
+ //Resize and position widgets.
+ GUIObjectRoot->width=SCREEN_WIDTH;
+ GUIObjectRoot->height=SCREEN_HEIGHT;
+
+ backButton->left=SCREEN_WIDTH/2;
+ backButton->top=SCREEN_HEIGHT-60;
+
+ textArea->left=SCREEN_WIDTH*0.05;
+ textArea->width=SCREEN_WIDTH*0.9;
+ textArea->height=SCREEN_HEIGHT-200;
+ textArea->resize();
+}
diff --git a/src/CreditsMenu.h b/src/CreditsMenu.h
new file mode 100644
index 0000000..6b17f9e
--- /dev/null
+++ b/src/CreditsMenu.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011-2013 Me and My Shadow
+ *
+ * This file is part of Me and My Shadow.
+ *
+ * Me and My Shadow is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Me and My Shadow is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CREDITS_MENU_H
+#define CREDITS_MENU_H
+
+#include <SDL.h>
+#include "GameState.h"
+
+//Included for the Credits menu.
+#include "Render.h"
+#include "GUIObject.h"
+#include "ImageManager.h"
+
+class GUITextArea;
+
+//The Credits menu.
+class Credits : public GameState, private GUIEventCallback{
+private:
+ //The title of the credits menu.
+ TexturePtr title;
+
+ //Widgets.
+ GUITextArea* textArea;
+ GUIObject* backButton;
+
+ //GUI events are handled here.
+ //name: The name of the element that invoked the event.
+ //obj: Pointer to the object that invoked the event.
+ //eventType: Integer containing the type of event.
+ void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
+
+public:
+ //Constructor.
+ Credits(ImageManager& imageManager, SDL_Renderer &renderer);
+ //Destructor.
+ ~Credits();
+
+ //Inherited from GameState.
+ void handleEvents(ImageManager&, SDL_Renderer&) override;
+ void logic(ImageManager&, SDL_Renderer&) override;
+ void render(ImageManager&, SDL_Renderer& renderer) override;
+ void resize(ImageManager &imageManager, SDL_Renderer& renderer) override;
+};
+
+#endif
diff --git a/src/Functions.cpp b/src/Functions.cpp
index 4533dc8..cbe9426 100644
--- a/src/Functions.cpp
+++ b/src/Functions.cpp
@@ -1,1799 +1,1801 @@
/*
* Copyright (C) 2011-2013 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <math.h>
#include <locale.h>
#include <algorithm>
#include <SDL.h>
#include <SDL_mixer.h>
#include <SDL_syswm.h>
#include <SDL_ttf.h>
#include <string>
#include "Globals.h"
#include "Functions.h"
#include "FileManager.h"
#include "GameObjects.h"
#include "LevelPack.h"
#include "TitleMenu.h"
+#include "OptionsMenu.h"
+#include "CreditsMenu.h"
#include "LevelEditSelect.h"
#include "LevelEditor.h"
#include "Game.h"
#include "LevelPlaySelect.h"
#include "Addons.h"
#include "InputManager.h"
#include "ImageManager.h"
#include "MusicManager.h"
#include "SoundManager.h"
#include "ScriptExecutor.h"
#include "LevelPackManager.h"
#include "ThemeManager.h"
#include "GUIListBox.h"
#include "GUIOverlay.h"
#include "StatisticsManager.h"
#include "StatisticsScreen.h"
#include "Cursors.h"
#include "ScriptAPI.h"
#include "libs/tinyformat/tinyformat.h"
#include "libs/tinygettext/tinygettext.hpp"
#include "libs/tinygettext/log.hpp"
#include "libs/findlocale/findlocale.h"
using namespace std;
#ifdef WIN32
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#else
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#endif
//Initialise the musicManager.
//The MusicManager is used to prevent loading music files multiple times and for playing/fading music.
MusicManager musicManager;
//Initialise the soundManager.
//The SoundManager is used to keep track of the sfx in the game.
SoundManager soundManager;
//Initialise the levelPackManager.
//The LevelPackManager is used to prevent loading levelpacks multiple times and for the game to know which levelpacks there are.
LevelPackManager levelPackManager;
//The scriptExecutor used for executing scripts.
ScriptExecutor scriptExecutor;
//Map containing changed settings using command line arguments.
map<string,string> tmpSettings;
//Pointer to the settings object.
//It is used to load and save the settings file and change the settings.
Settings* settings=nullptr;
SDL_Renderer* sdlRenderer=nullptr;
void applySurface(int x,int y,SDL_Surface* source,SDL_Surface* dest,SDL_Rect* clip){
//The offset is needed to draw at the right location.
SDL_Rect offset;
offset.x=x;
offset.y=y;
//Let SDL do the drawing of the surface.
SDL_BlitSurface(source,clip,dest,&offset);
}
void drawRect(int x,int y,int w,int h,SDL_Renderer& renderer,Uint32 color){
//NOTE: We let SDL_gfx render it.
SDL_SetRenderDrawColor(&renderer,color >> 24,color >> 16,color >> 8,255);
//rectangleRGBA(&renderer,x,y,x+w,y+h,color >> 24,color >> 16,color >> 8,255);
const SDL_Rect r{x,y,w,h};
SDL_RenderDrawRect(&renderer,&r);
}
//Draw a box with anti-aliased borders using SDL_gfx.
void drawGUIBox(int x,int y,int w,int h,SDL_Renderer& renderer,Uint32 color){
SDL_Renderer* rd = &renderer;
//FIXME, this may get the wrong color on system with different endianness.
//Fill content's background color from function parameter
SDL_SetRenderDrawColor(rd,color >> 24,color >> 16,color >> 8,color >> 0);
{
const SDL_Rect r{x+1,y+1,w-2,h-2};
SDL_RenderFillRect(rd, &r);
}
SDL_SetRenderDrawColor(rd,0,0,0,255);
//Draw first black borders around content and leave 1 pixel in every corner
SDL_RenderDrawLine(rd,x+1,y,x+w-2,y);
SDL_RenderDrawLine(rd,x+1,y+h-1,x+w-2,y+h-1);
SDL_RenderDrawLine(rd,x,y+1,x,y+h-2);
SDL_RenderDrawLine(rd,x+w-1,y+1,x+w-1,y+h-2);
//Fill the corners with transperent color to create anti-aliased borders
SDL_SetRenderDrawColor(rd,0,0,0,160);
SDL_RenderDrawPoint(rd,x,y);
SDL_RenderDrawPoint(rd,x,y+h-1);
SDL_RenderDrawPoint(rd,x+w-1,y);
SDL_RenderDrawPoint(rd,x+w-1,y+h-1);
//Draw second lighter border around content
SDL_SetRenderDrawColor(rd,0,0,0,64);
{
const SDL_Rect r{x+1,y+1,w-2,h-2};
SDL_RenderDrawRect(rd,&r);
}
SDL_SetRenderDrawColor(rd,0,0,0,50);
//Create anti-aliasing in corners of second border
SDL_RenderDrawPoint(rd,x+1,y+1);
SDL_RenderDrawPoint(rd,x+1,y+h-2);
SDL_RenderDrawPoint(rd,x+w-2,y+1);
SDL_RenderDrawPoint(rd,x+w-2,y+h-2);
}
void drawLine(int x1,int y1,int x2,int y2,SDL_Renderer& renderer,Uint32 color){
SDL_SetRenderDrawColor(&renderer,color >> 24,color >> 16,color >> 8,255);
//NOTE: We let SDL_gfx render it.
//lineRGBA(&renderer,x1,y1,x2,y2,color >> 24,color >> 16,color >> 8,255);
SDL_RenderDrawLine(&renderer,x1,y1,x2,y2);
}
void drawLineWithArrow(int x1,int y1,int x2,int y2,SDL_Renderer& renderer,Uint32 color,int spacing,int offset,int xsize,int ysize){
//Draw line first
drawLine(x1,y1,x2,y2,renderer,color);
//calc delta and length
double dx=x2-x1;
double dy=y2-y1;
double length=sqrt(dx*dx+dy*dy);
if(length<0.001) return;
//calc the unit vector
dx/=length; dy/=length;
//Now draw arrows on it
for(double p=offset;p<length;p+=spacing){
drawLine(int(x1+p*dx+0.5),int(y1+p*dy+0.5),
int(x1+(p-xsize)*dx-ysize*dy+0.5),int(y1+(p-xsize)*dy+ysize*dx+0.5),renderer,color);
drawLine(int(x1+p*dx+0.5),int(y1+p*dy+0.5),
int(x1+(p-xsize)*dx+ysize*dy+0.5),int(y1+(p-xsize)*dy-ysize*dx+0.5),renderer,color);
}
}
ScreenData creationFailed() {
return ScreenData{ nullptr };
}
ScreenData createScreen(){
//Check if we are going fullscreen.
if(settings->getBoolValue("fullscreen"))
pickFullscreenResolution();
//Set the screen_width and height.
SCREEN_WIDTH=atoi(settings->getValue("width").c_str());
SCREEN_HEIGHT=atoi(settings->getValue("height").c_str());
//Update the camera.
camera.w=SCREEN_WIDTH;
camera.h=SCREEN_HEIGHT;
//Set the flags.
Uint32 flags = 0;
Uint32 currentFlags = SDL_GetWindowFlags(sdlWindow);
//#if !defined(ANDROID)
// flags |= SDL_DOUBLEBUF;
//#endif
if(settings->getBoolValue("fullscreen")) {
flags|=SDL_WINDOW_FULLSCREEN; //TODO with SDL2 we can also do SDL_WINDOW_FULLSCREEN_DESKTOP
}
else if(settings->getBoolValue("resizable"))
flags|=SDL_WINDOW_RESIZABLE;
//Create the window and renderer if they don't exist and check if there weren't any errors.
if (!sdlWindow && !sdlRenderer) {
SDL_CreateWindowAndRenderer(SCREEN_WIDTH, SCREEN_HEIGHT, flags, &sdlWindow, &sdlRenderer);
if(!sdlWindow || !sdlRenderer){
std::cerr << "FATAL ERROR: SDL_CreateWindowAndRenderer failed.\nError: " << SDL_GetError() << std::endl;
return creationFailed();
}
SDL_SetRenderDrawBlendMode(sdlRenderer, SDL_BlendMode::SDL_BLENDMODE_BLEND);
// White background so we see the menu on failure.
SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, 255);
} else if (sdlWindow) {
// Try changing to/from fullscreen
if(SDL_SetWindowFullscreen(sdlWindow, flags & SDL_WINDOW_FULLSCREEN) != 0) {
std::cerr << "WARNING: Failed to switch to fullscreen: " << SDL_GetError() << std::endl;
};
currentFlags = SDL_GetWindowFlags(sdlWindow);
// Change fullscreen resolution
if((currentFlags & SDL_WINDOW_FULLSCREEN ) || (currentFlags & SDL_WINDOW_FULLSCREEN_DESKTOP)) {
SDL_DisplayMode m{0,0,0,0,nullptr};
SDL_GetWindowDisplayMode(sdlWindow,&m);
m.w = SCREEN_WIDTH;
m.h = SCREEN_HEIGHT;
if(SDL_SetWindowDisplayMode(sdlWindow, &m) != 0) {
std::cerr << "WARNING: Failed to set display mode: " << SDL_GetError() << std::endl;
}
} else {
SDL_SetWindowSize(sdlWindow, SCREEN_WIDTH, SCREEN_HEIGHT);
}
}
//Now configure the newly created window (if windowed).
if(settings->getBoolValue("fullscreen")==false)
configureWindow();
//Set the the window caption.
SDL_SetWindowTitle(sdlWindow, ("Me and My Shadow "+version).c_str());
//FIXME Seems to be obsolete
// SDL_EnableUNICODE(1);
//Nothing went wrong so return true.
return ScreenData{sdlRenderer};
}
vector<_res> getResolutionList(){
//Vector that will hold the resolutions to choose from.
vector<_res> resolutionList;
//Enumerate available resolutions using SDL_ListModes()
//NOTE: we enumerate fullscreen resolutions because
// windowed resolutions always can be arbitrary
if(resolutionList.empty()){
// SDL_Rect **modes=SDL_ListModes(NULL,SDL_FULLSCREEN|SCREEN_FLAGS|SDL_ANYFORMAT);
//NOTe - currently only using the first display (0)
int numDisplayModes = SDL_GetNumDisplayModes(0);
if(numDisplayModes < 1){
cerr<<"ERROR: Can't enumerate available screen resolutions."
" Use predefined screen resolutions list instead."<<endl;
static const _res predefinedResolutionList[] = {
{800,600},
{1024,600},
{1024,768},
{1152,864},
{1280,720},
{1280,768},
{1280,800},
{1280,960},
{1280,1024},
{1360,768},
{1366,768},
{1440,900},
{1600,900},
{1600,1200},
{1680,1080},
{1920,1080},
{1920,1200},
{2560,1440},
{3840,2160}
};
//Fill the resolutionList.
for(unsigned int i=0;i<sizeof(predefinedResolutionList)/sizeof(_res);i++){
resolutionList.push_back(predefinedResolutionList[i]);
}
}else{
//Fill the resolutionList.
for(int i=0;i < numDisplayModes; ++i){
SDL_DisplayMode mode;
int error = SDL_GetDisplayMode(0, i, &mode);
if(error < 0) {
//We failed to get a display mode. Should we crash here?
std::cerr << "ERROR: Failed to get display mode " << i << " " << std::endl;
}
//Check if the resolution is higher than the minimum (800x600).
if(mode.w >= 800 && mode.h >= 600){
_res res={mode.w, mode.h};
resolutionList.push_back(res);
}
}
//Reverse it so that we begin with the lowest resolution.
reverse(resolutionList.begin(),resolutionList.end());
}
}
//Return the resolution list.
return resolutionList;
}
void pickFullscreenResolution(){
//Get the resolution list.
vector<_res> resolutionList=getResolutionList();
//The resolution that will hold the final result, we start with the minimum (800x600).
_res closestMatch={800,600};
int width=atoi(getSettings()->getValue("width").c_str());
//int height=atoi(getSettings()->getValue("height").c_str());
//Now loop through the resolutionList.
for(int i=0;i<(int)resolutionList.size();i++){
//The delta between the closestMatch and the resolution from the list.
int dM=(closestMatch.w-resolutionList[i].w);
//The delta between the target width and the resolution from the list.
int dT=(width-resolutionList[i].w);
//Since the resolutions are getting higher the lower (more negative) the further away it is.
//That's why we check if the deltaMatch is lower than the the deltaTarget.
if((dM)<(dT)){
closestMatch.w=resolutionList[i].w;
closestMatch.h=resolutionList[i].h;
}
}
//Now set the resolution to the closest match.
char s[64];
sprintf(s,"%d",closestMatch.w);
getSettings()->setValue("width",s);
sprintf(s,"%d",closestMatch.h);
getSettings()->setValue("height",s);
}
void configureWindow(){
//We only need to configure the window if it's resizable.
if(!getSettings()->getBoolValue("resizable"))
return;
//We use a new function in SDL2 to restrict minimum window size
SDL_SetWindowMinimumSize(sdlWindow, 800, 600);
}
void onVideoResize(ImageManager& imageManager, SDL_Renderer &renderer){
//Check if the resize event isn't malformed.
if(event.window.data1<=0 || event.window.data2<=0)
return;
//Check the size limit.
//TODO: SDL2 porting note: This may break on systems non-X11 or Windows systems as the window size won't be limited
//there.
if(event.window.data1<800)
event.window.data1=800;
if(event.window.data2<600)
event.window.data2=600;
//Check if it really resizes.
if(SCREEN_WIDTH==event.window.data1 && SCREEN_HEIGHT==event.window.data2)
return;
char s[32];
//Set the new width and height.
SDL_snprintf(s,32,"%d",event.window.data1);
getSettings()->setValue("width",s);
SDL_snprintf(s,32,"%d",event.window.data2);
getSettings()->setValue("height",s);
//FIXME: THIS doesn't work properly.
//Do resizing.
SCREEN_WIDTH = event.window.data1;
SCREEN_HEIGHT = event.window.data2;
//Update the camera.
camera.w=SCREEN_WIDTH;
camera.h=SCREEN_HEIGHT;
//Tell the theme to resize.
if(!loadTheme(imageManager,renderer,""))
return;
//And let the currentState update it's GUI to the new resolution.
currentState->resize(imageManager, renderer);
}
ScreenData init(){
//Initialze SDL.
if(SDL_Init(SDL_INIT_EVERYTHING)==-1) {
std::cerr << "FATAL ERROR: SDL_Init failed\nError: " << SDL_GetError() << std::endl;
return creationFailed();
}
//Initialze SDL_mixer (audio).
//Note for SDL2 port: Changed frequency from 22050 to 44100.
//22050 caused some sound artifacts on my system, and I'm not sure
//why one would use it in this day and age anyhow.
//unless it's for compatability with some legacy system.
if(Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,1024)==-1){
std::cerr << "FATAL ERROR: Mix_OpenAudio failed\nError: " << Mix_GetError() << std::endl;
return creationFailed();
}
//Set the volume.
Mix_Volume(-1,atoi(settings->getValue("sound").c_str()));
//Increase the number of channels.
soundManager.setNumberOfChannels(48);
//Initialze SDL_ttf (fonts).
if(TTF_Init()==-1){
std::cerr << "FATAL ERROR: TTF_Init failed\nError: " << TTF_GetError() << std::endl;
return creationFailed();
}
//Create the screen.
ScreenData screenData(createScreen());
if(!screenData) {
return creationFailed();
}
//Load key config. Then initialize joystick support.
inputMgr.loadConfig();
inputMgr.openAllJoysitcks();
//Init tinygettext for translations for the right language
dictionaryManager = new tinygettext::DictionaryManager();
dictionaryManager->add_directory(getDataPath()+"locale");
dictionaryManager->set_charset("UTF-8");
//Check if user have defined own language. If not, find it out for the player using findlocale
string lang=getSettings()->getValue("lang");
if(lang.length()>0){
printf("Locale set by user to %s\n",lang.c_str());
language=lang;
}else{
FL_Locale *locale;
FL_FindLocale(&locale,FL_MESSAGES);
printf("Locale isn't set by user: %s\n",locale->lang);
language=locale->lang;
if(locale->country!=NULL){
language+=string("_")+string(locale->country);
}
if(locale->variant!=NULL){
language+=string("@")+string(locale->variant);
}
FL_FreeLocale(&locale);
}
//Now set the language in the dictionaryManager.
dictionaryManager->set_language(tinygettext::Language::from_name(language));
//Disable annoying 'Couldn't translate: blah blah blah'
tinygettext::Log::set_log_info_callback(NULL);
//Set time format to the user-preference of the system.
setlocale(LC_TIME,"");
//Create the types of blocks.
for(int i=0;i<TYPE_MAX;i++){
Game::blockNameMap[Game::blockName[i]]=i;
}
//Structure that holds the event type/name pair.
struct EventTypeName{
int type;
const char* name;
};
//Create the types of game object event types.
{
const EventTypeName types[]={
{GameObjectEvent_PlayerWalkOn,"playerWalkOn"},
{GameObjectEvent_PlayerIsOn,"playerIsOn"},
{GameObjectEvent_PlayerLeave,"playerLeave"},
{GameObjectEvent_OnCreate,"onCreate"},
{GameObjectEvent_OnEnterFrame,"onEnterFrame"},
{ GameObjectEvent_OnPlayerInteraction, "onPlayerInteraction" },
{GameObjectEvent_OnToggle,"onToggle"},
{GameObjectEvent_OnSwitchOn,"onSwitchOn"},
{GameObjectEvent_OnSwitchOff,"onSwitchOff"},
{0,NULL}
};
for(int i=0;types[i].name;i++){
Game::gameObjectEventNameMap[types[i].name]=types[i].type;
Game::gameObjectEventTypeMap[types[i].type]=types[i].name;
}
}
//Create the types of level event types.
{
const EventTypeName types[]={
{LevelEvent_OnCreate,"onCreate"},
{LevelEvent_OnSave,"onSave"},
{LevelEvent_OnLoad,"onLoad"},
{LevelEvent_OnReset,"onReset"},
{0,NULL}
};
for(int i=0;types[i].name;i++){
Game::levelEventNameMap[types[i].name]=types[i].type;
Game::levelEventTypeMap[types[i].type]=types[i].name;
}
}
//Nothing went wrong so we return true.
return screenData;
}
static TTF_Font* loadFont(const char* name,int size){
TTF_Font* tmpFont=TTF_OpenFont((getDataPath()+"font/"+name+".ttf").c_str(),size);
if(tmpFont){
return tmpFont;
}else{
#if defined(ANDROID)
//Android has built-in DroidSansFallback.ttf. (?)
return TTF_OpenFont("/system/fonts/DroidSansFallback.ttf",size);
#else
return TTF_OpenFont((getDataPath()+"font/DroidSansFallback.ttf").c_str(),size);
#endif
}
}
bool loadFonts(){
//Load the fonts.
//NOTE: This is a separate method because it will be called separately when re-initing in case of language change.
//First close the fonts if needed.
if(fontTitle)
TTF_CloseFont(fontTitle);
if(fontGUI)
TTF_CloseFont(fontGUI);
if(fontGUISmall)
TTF_CloseFont(fontGUISmall);
if(fontText)
TTF_CloseFont(fontText);
if(fontMono)
TTF_CloseFont(fontMono);
/// TRANSLATORS: Font used in GUI:
/// - Use "knewave" for languages using Latin and Latin-derived alphabets
/// - "DroidSansFallback" can be used for non-Latin writing systems
fontTitle=loadFont(_("knewave"),55);
fontGUI=loadFont(_("knewave"),32);
fontGUISmall=loadFont(_("knewave"),24);
/// TRANSLATORS: Font used for normal text:
/// - Use "Blokletters-Viltstift" for languages using Latin and Latin-derived alphabets
/// - "DroidSansFallback" can be used for non-Latin writing systems
fontText=loadFont(_("Blokletters-Viltstift"),16);
fontMono=loadFont("VeraMono",12);
if(fontTitle==NULL || fontGUI==NULL || fontGUISmall==NULL || fontText==NULL || fontMono==NULL){
printf("ERROR: Unable to load fonts! \n");
return false;
}
//Nothing went wrong so return true.
return true;
}
//Generate small arrows used for some GUI widgets.
static void generateArrows(SDL_Renderer& renderer){
TTF_Font* fontArrow=loadFont(_("knewave"),18);
arrowLeft1=textureFromText(renderer,*fontArrow,"<",objThemes.getTextColor(false));
arrowRight1=textureFromText(renderer,*fontArrow,">",objThemes.getTextColor(false));
arrowLeft2=textureFromText(renderer,*fontArrow,"<",objThemes.getTextColor(true));
arrowRight2=textureFromText(renderer,*fontArrow,">",objThemes.getTextColor(true));
TTF_CloseFont(fontArrow);
}
bool loadTheme(ImageManager& imageManager,SDL_Renderer& renderer,std::string name){
//Load default fallback theme if it isn't loaded yet
if(objThemes.themeCount()==0){
if(objThemes.appendThemeFromFile(getDataPath()+"themes/Cloudscape/theme.mnmstheme", imageManager, renderer)==NULL){
printf("ERROR: Can't load default theme file\n");
return false;
}
}
//Resize background or load specific theme
bool success=true;
if(name==""||name.empty()){
objThemes.scaleToScreen();
}else{
string theme=processFileName(name);
if(objThemes.appendThemeFromFile(theme+"/theme.mnmstheme", imageManager, renderer)==NULL){
printf("ERROR: Can't load theme %s\n",theme.c_str());
success=false;
}
}
generateArrows(renderer);
//Everything went fine so return true.
return success;
}
static SDL_Cursor* loadCursor(const char* image[]){
int i,row,col;
//The array that holds the data (0=white 1=black)
Uint8 data[4*32];
//The array that holds the alpha mask (0=transparent 1=visible)
Uint8 mask[4*32];
//The coordinates of the hotspot of the cursor.
int hotspotX, hotspotY;
i=-1;
//Loop through the rows and columns.
//NOTE: We assume a cursor size of 32x32.
for(row=0;row<32;++row){
for(col=0; col<32;++col){
if(col % 8) {
data[i]<<=1;
mask[i]<<=1;
}else{
++i;
data[i]=mask[i]=0;
}
switch(image[4+row][col]){
case '+':
data[i] |= 0x01;
mask[i] |= 0x01;
break;
case '.':
mask[i] |= 0x01;
break;
default:
break;
}
}
}
//Get the hotspot x and y locations from the last line of the cursor.
sscanf(image[4+row],"%d,%d",&hotspotX,&hotspotY);
return SDL_CreateCursor(data,mask,32,32,hotspotX,hotspotY);
}
bool loadFiles(ImageManager& imageManager, SDL_Renderer& renderer){
//Load the fonts.
if(!loadFonts())
return false;
//Show a loading screen
{
int w = 0,h = 0;
SDL_GetRendererOutputSize(&renderer, &w, &h);
SDL_Color fg={255,255,255,0};
TexturePtr loadingTexture = textureFromText(renderer, *fontTitle, _("Loading..."),fg);
SDL_Rect loadingRect = rectFromTexture(*loadingTexture);
loadingRect.x = (w-loadingRect.w)/2;
loadingRect.y = (h-loadingRect.h)/2;
SDL_RenderCopy(sdlRenderer, loadingTexture.get(), NULL, &loadingRect);
SDL_RenderPresent(sdlRenderer);
SDL_RenderClear(sdlRenderer);
}
musicManager.destroy();
//Load the music and play it.
if(musicManager.loadMusic((getDataPath()+"music/menu.music")).empty()){
printf("WARNING: Unable to load background music! \n");
}
musicManager.playMusic("menu",false);
//Load all the music lists from the data and user data path.
{
vector<string> musicLists=enumAllFiles((getDataPath()+"music/"),"list",true);
for(unsigned int i=0;i<musicLists.size();i++)
getMusicManager()->loadMusicList(musicLists[i]);
musicLists=enumAllFiles((getUserPath(USER_DATA)+"music/"),"list",true);
for(unsigned int i=0;i<musicLists.size();i++)
getMusicManager()->loadMusicList(musicLists[i]);
}
//Set the list to the configured one.
getMusicManager()->setMusicList(getSettings()->getValue("musiclist"));
//Check if music is enabled.
if(getSettings()->getBoolValue("music"))
getMusicManager()->setEnabled();
//Load the sound effects
soundManager.loadSound((getDataPath()+"sfx/jump.wav").c_str(),"jump");
soundManager.loadSound((getDataPath()+"sfx/hit.wav").c_str(),"hit");
soundManager.loadSound((getDataPath()+"sfx/checkpoint.wav").c_str(),"checkpoint");
soundManager.loadSound((getDataPath()+"sfx/swap.wav").c_str(),"swap");
soundManager.loadSound((getDataPath()+"sfx/toggle.ogg").c_str(),"toggle");
soundManager.loadSound((getDataPath()+"sfx/error.wav").c_str(),"error");
soundManager.loadSound((getDataPath()+"sfx/collect.wav").c_str(),"collect");
soundManager.loadSound((getDataPath()+"sfx/achievement.ogg").c_str(),"achievement");
//Load the cursor images from the Cursor.h file.
cursors[CURSOR_POINTER]=loadCursor(pointer);
cursors[CURSOR_CARROT]=loadCursor(ibeam);
cursors[CURSOR_DRAG]=loadCursor(closedhand);
cursors[CURSOR_SIZE_HOR]=loadCursor(size_hor);
cursors[CURSOR_SIZE_VER]=loadCursor(size_ver);
cursors[CURSOR_SIZE_FDIAG]=loadCursor(size_fdiag);
cursors[CURSOR_SIZE_BDIAG]=loadCursor(size_bdiag);
cursors[CURSOR_REMOVE]=loadCursor(remove_cursor);
cursors[CURSOR_POINTING_HAND] = loadCursor(pointing_hand);
//Set the default cursor right now.
SDL_SetCursor(cursors[CURSOR_POINTER]);
levelPackManager.destroy();
//Now sum up all the levelpacks.
vector<string> v=enumAllDirs(getDataPath()+"levelpacks/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelPackManager.loadLevelPack(getDataPath()+"levelpacks/"+*i);
}
v=enumAllDirs(getUserPath(USER_DATA)+"levelpacks/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelPackManager.loadLevelPack(getUserPath(USER_DATA)+"levelpacks/"+*i);
}
v=enumAllDirs(getUserPath(USER_DATA)+"custom/levelpacks/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelPackManager.loadLevelPack(getUserPath(USER_DATA)+"custom/levelpacks/"+*i);
}
//Now we add a special levelpack that will contain the levels not in a levelpack.
LevelPack* levelsPack=new LevelPack;
levelsPack->levelpackName="Levels";
levelsPack->levelpackPath="Levels/";
//NOTE: Set the type of 'levels' to main so it won't be added to the custom packs, even though it contains non-main levels.
levelsPack->type=COLLECTION;
LevelPack* customLevelsPack=new LevelPack;
customLevelsPack->levelpackName="Custom Levels";
customLevelsPack->levelpackPath="Custom Levels/";
customLevelsPack->type=COLLECTION;
//List the addon levels and add them one for one.
v=enumAllFiles(getUserPath(USER_DATA)+"levels/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelsPack->addLevel(getUserPath(USER_DATA)+"levels/"+*i);
levelsPack->setLocked(levelsPack->getLevelCount()-1);
}
//List the custom levels and add them one for one.
v=enumAllFiles(getUserPath(USER_DATA)+"custom/levels/");
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
levelsPack->addLevel(getUserPath(USER_DATA)+"custom/levels/"+*i);
levelsPack->setLocked(levelsPack->getLevelCount()-1);
customLevelsPack->addLevel(getUserPath(USER_DATA)+"custom/levels/"+*i);
customLevelsPack->setLocked(customLevelsPack->getLevelCount()-1);
}
//Add them to the manager.
levelPackManager.addLevelPack(levelsPack);
levelPackManager.addLevelPack(customLevelsPack);
//Load statistics
statsMgr.loadPicture(renderer, imageManager);
statsMgr.registerAchievements(imageManager);
statsMgr.loadFile(getUserPath(USER_CONFIG)+"statistics");
//Do something ugly and slow
statsMgr.reloadCompletedLevelsAndAchievements();
statsMgr.reloadOtherAchievements();
//Load the theme, both menu and default.
//NOTE: Loading theme may fail and returning false would stop everything, default theme will be used instead.
if (!loadTheme(imageManager,renderer,getSettings()->getValue("theme"))){
getSettings()->setValue("theme","%DATA%/themes/Cloudscape");
saveSettings();
}
//Nothing failed so return true.
return true;
}
bool loadSettings(){
settings=new Settings(getUserPath(USER_CONFIG)+"meandmyshadow.cfg");
settings->parseFile();
//Now apply settings changed through command line arguments, if any.
map<string,string>::iterator it;
for(it=tmpSettings.begin();it!=tmpSettings.end();++it){
settings->setValue(it->first,it->second);
}
tmpSettings.clear();
//Always return true?
return true;
}
bool saveSettings(){
return settings->save();
}
Settings* getSettings(){
return settings;
}
MusicManager* getMusicManager(){
return &musicManager;
}
SoundManager* getSoundManager(){
return &soundManager;
}
LevelPackManager* getLevelPackManager(){
return &levelPackManager;
}
ScriptExecutor* getScriptExecutor(){
return &scriptExecutor;
}
void flipScreen(SDL_Renderer& renderer){
// Render the data from the back buffer.
SDL_RenderPresent(&renderer);
}
void clean(){
//Save statistics
statsMgr.saveFile(getUserPath(USER_CONFIG)+"statistics");
//We delete the settings.
if(settings){
delete settings;
settings=NULL;
}
//Delete dictionaryManager.
delete dictionaryManager;
//Get rid of the currentstate.
//NOTE: The state is probably already deleted by the changeState function.
if(currentState)
delete currentState;
//Destroy the GUI if present.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//These calls to destroy makes sure stuff is
//deleted before SDL is uninitialised (as these managers are stack allocated
//globals.)
//Destroy the musicManager.
musicManager.destroy();
//Destroy all sounds
soundManager.destroy();
//Destroy the cursors.
for(int i=0;i<CURSOR_MAX;i++){
SDL_FreeCursor(cursors[i]);
cursors[i]=NULL;
}
//Destroy the levelPackManager.
levelPackManager.destroy();
levels=NULL;
//Close all joysticks.
inputMgr.closeAllJoysticks();
//Close the fonts and quit SDL_ttf.
TTF_CloseFont(fontTitle);
TTF_CloseFont(fontGUI);
TTF_CloseFont(fontGUISmall);
TTF_CloseFont(fontText);
TTF_CloseFont(fontMono);
TTF_Quit();
//Remove the temp surface.
SDL_DestroyRenderer(sdlRenderer);
SDL_DestroyWindow(sdlWindow);
arrowLeft1.reset(nullptr);
arrowLeft2.reset(nullptr);
arrowRight1.reset(nullptr);
arrowRight2.reset(nullptr);
//Stop audio.and quit
Mix_CloseAudio();
//SDL2 porting note. Not sure why this was only done on apple.
//#ifndef __APPLE__
Mix_Quit();
//#endif
//And finally quit SDL.
SDL_Quit();
}
void setNextState(int newstate){
//Only change the state when we aren't already exiting.
if(nextState!=STATE_EXIT){
nextState=newstate;
}
}
void changeState(ImageManager& imageManager, SDL_Renderer& renderer, int fade){
//Check if there's a nextState.
if(nextState!=STATE_NULL){
//Fade out, if fading is enabled.
if (currentState && settings->getBoolValue("fading")) {
for (; fade >= 0; fade -= 17) {
currentState->render(imageManager, renderer);
//TODO: Shouldn't the gamestate take care of rendering the GUI?
if (GUIObjectRoot) GUIObjectRoot->render(renderer);
dimScreen(renderer, static_cast<Uint8>(255 - fade));
//draw new achievements (if any) as overlay
statsMgr.render(imageManager, renderer);
flipScreen(renderer);
SDL_Delay(25);
}
}
//Delete the currentState.
delete currentState;
currentState=NULL;
//Set the currentState to the nextState.
stateID=nextState;
nextState=STATE_NULL;
//Init the state.
switch(stateID){
case STATE_GAME:
{
currentState=NULL;
Game* game=new Game(renderer, imageManager);
currentState=game;
//Check if we should load record file or a level.
if(!Game::recordFile.empty()){
game->loadRecord(imageManager,renderer,Game::recordFile.c_str());
Game::recordFile.clear();
}else{
game->loadLevel(imageManager,renderer,levels->getLevelFile());
levels->saveLevelProgress();
}
}
break;
case STATE_MENU:
currentState=new Menu(imageManager, renderer);
break;
case STATE_LEVEL_SELECT:
currentState=new LevelPlaySelect(imageManager, renderer);
break;
case STATE_LEVEL_EDIT_SELECT:
currentState=new LevelEditSelect(imageManager, renderer);
break;
case STATE_LEVEL_EDITOR:
{
currentState=NULL;
LevelEditor* levelEditor=new LevelEditor(renderer, imageManager);
currentState=levelEditor;
//Load the selected level.
levelEditor->loadLevel(imageManager,renderer,levels->getLevelFile());
}
break;
case STATE_OPTIONS:
currentState=new Options(imageManager, renderer);
break;
case STATE_ADDONS:
currentState=new Addons(renderer, imageManager);
break;
case STATE_CREDITS:
currentState=new Credits(imageManager,renderer);
break;
case STATE_STATISTICS:
currentState=new StatisticsScreen(imageManager,renderer);
break;
}
//NOTE: STATE_EXIT isn't mentioned, meaning that currentState is null.
//This way the game loop will break and the program will exit.
}
}
void musicStoppedHook(){
//We just call the musicStopped method of the MusicManager.
musicManager.musicStopped();
}
void channelFinishedHook(int channel){
soundManager.channelFinished(channel);
}
bool checkCollision(const SDL_Rect& a,const SDL_Rect& b){
//Check if the left side of box a isn't past the right side of b.
if(a.x>=b.x+b.w){
return false;
}
//Check if the right side of box a isn't left of the left side of b.
if(a.x+a.w<=b.x){
return false;
}
//Check if the top side of box a isn't under the bottom side of b.
if(a.y>=b.y+b.h){
return false;
}
//Check if the bottom side of box a isn't above the top side of b.
if(a.y+a.h<=b.y){
return false;
}
//We have collision.
return true;
}
int parseArguments(int argc, char** argv){
//Loop through all arguments.
//We start at one since 0 is the command itself.
for(int i=1;i<argc;i++){
string argument=argv[i];
//Check if the argument is the data-dir.
if(argument=="--data-dir"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Configure the dataPath with the given path.
dataPath=argv[i];
if(!getDataPath().empty()){
char c=dataPath[dataPath.size()-1];
if(c!='/'&&c!='\\') dataPath+="/";
}
}else if(argument=="--user-dir"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Configure the userPath with the given path.
userPath=argv[i];
if(!userPath.empty()){
char c=userPath[userPath.size()-1];
if(c!='/'&&c!='\\') userPath+="/";
}
}else if(argument=="-f" || argument=="-fullscreen" || argument=="--fullscreen"){
tmpSettings["fullscreen"]="1";
}else if(argument=="-w" || argument=="-windowed" || argument=="--windowed"){
tmpSettings["fullscreen"]="0";
}else if(argument=="-mv" || argument=="-music" || argument=="--music"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Now set the music volume.
tmpSettings["music"]=argv[i];
}else if(argument=="-sv" || argument=="-sound" || argument=="--sound"){
//We need a second argument so we increase i.
i++;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//Now set sound volume.
tmpSettings["sound"]=argv[i];
}else if(argument=="-set" || argument=="--set"){
//We need a second and a third argument so we increase i.
i+=2;
if(i>=argc){
printf("ERROR: Missing argument for command '%s'\n\n",argument.c_str());
return -1;
}
//And set the setting.
tmpSettings[argv[i-1]]=argv[i];
}else if(argument=="-v" || argument=="-version" || argument=="--version"){
//Print the version.
printf("%s\n",version.c_str());
return 0;
}else if(argument=="-h" || argument=="-help" || argument=="--help"){
//If the help is requested we'll return false without printing an error.
//This way the usage/help text will be printed.
return -1;
}else{
//Any other argument is unknow so we return false.
printf("ERROR: Unknown argument %s\n\n",argument.c_str());
return -1;
}
}
//If everything went well we can return true.
return 1;
}
//Special structure that will recieve the GUIEventCallbacks of the messagebox.
struct msgBoxHandler:public GUIEventCallback{
public:
//Integer containing the ret(urn) value of the messageBox.
int ret;
public:
//Constructor.
msgBoxHandler():ret(0){}
void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
//Make sure it's a click event.
if(eventType==GUIEventClick){
//Set the return value.
ret=obj->value;
//After a click event we can delete the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
}
};
msgBoxResult msgBox(ImageManager& imageManager,SDL_Renderer& renderer, string prompt,msgBoxButtons buttons,const string& title){
//Create the event handler.
msgBoxHandler objHandler;
//The GUI objects.
GUIObject* obj;
//Create the GUIObjectRoot, the height and y location is temp.
//It depends on the content what it will be.
GUIObject* root=new GUIFrame(imageManager,renderer,(SCREEN_WIDTH-600)/2,200,600,200,title.c_str());
//Integer containing the current y location used to grow dynamic depending on the content.
int y=50;
//Now process the prompt.
{
//Pointer to the string.
char* lps=(char*)prompt.c_str();
//Pointer to a character.
char* lp=NULL;
//We keep looping forever.
//The only way out is with the break statement.
for(;;){
//As long as it's still the same sentence we continue.
//It will stop when there's a newline or end of line.
for(lp=lps;*lp!='\n'&&*lp!='\r'&&*lp!=0;lp++);
//Store the character we stopped on. (End or newline)
char c=*lp;
//Set the character in the string to 0, making lps a string containing one sentence.
*lp=0;
//Add a GUIObjectLabel with the sentence.
root->addChild(new GUILabel(imageManager,renderer,0,y,root->width,25,lps,0,true,true,GUIGravityCenter));
//Increase y with 25, about the height of the text.
y+=25;
//Check the stored character if it was a stop.
if(c==0){
//It was so break out of the for loop.
lps=lp;
break;
}
//It wasn't meaning more will follow.
//We set lps to point after the "newline" forming a new string.
lps=lp+1;
}
}
//Add 70 to y to leave some space between the content and the buttons.
y+=70;
//Recalc the size of the message box.
root->top=(SCREEN_HEIGHT-y)/2;
root->height=y;
//Now we need to add the buttons.
//Integer containing the number of buttons to add.
int count=0;
//Array with the return codes for the buttons.
int value[3]={0};
//Array containing the captation for the buttons.
string button[3]={"","",""};
switch(buttons){
case MsgBoxOKCancel:
count=2;
button[0]=_("OK");value[0]=MsgBoxOK;
button[1]=_("Cancel");value[1]=MsgBoxCancel;
break;
case MsgBoxAbortRetryIgnore:
count=3;
button[0]=_("Abort");value[0]=MsgBoxAbort;
button[1]=_("Retry");value[1]=MsgBoxRetry;
button[2]=_("Ignore");value[2]=MsgBoxIgnore;
break;
case MsgBoxYesNoCancel:
count=3;
button[0]=_("Yes");value[0]=MsgBoxYes;
button[1]=_("No");value[1]=MsgBoxNo;
button[2]=_("Cancel");value[2]=MsgBoxCancel;
break;
case MsgBoxYesNo:
count=2;
button[0]=_("Yes");value[0]=MsgBoxYes;
button[1]=_("No");value[1]=MsgBoxNo;
break;
case MsgBoxRetryCancel:
count=2;
button[0]=_("Retry");value[0]=MsgBoxRetry;
button[1]=_("Cancel");value[1]=MsgBoxCancel;
break;
default:
count=1;
button[0]=_("OK");value[0]=MsgBoxOK;
break;
}
//Now we start making the buttons.
{
//Reduce y so that the buttons fit inside the frame.
y-=40;
double places[3]={0.0};
if(count==1){
places[0]=0.5;
}else if(count==2){
places[0]=0.4;
places[1]=0.6;
}else if(count==3){
places[0]=0.3;
places[1]=0.5;
places[2]=0.7;
}
//Loop to add the buttons.
for(int i=0;i<count;i++){
obj=new GUIButton(imageManager,renderer,root->width*places[i],y,-1,36,button[i].c_str(),value[i],true,true,GUIGravityCenter);
obj->eventCallback=&objHandler;
root->addChild(obj);
}
}
//Now we dim the screen and keep the GUI rendering/updating.
GUIOverlay* overlay=new GUIOverlay(renderer,root);
overlay->keyboardNavigationMode = 0x7 | ((count == 1) ? 0 : 0x8);
overlay->enterLoop(imageManager, renderer, true, count == 1);
//And return the result.
return (msgBoxResult)objHandler.ret;
}
//SDL2 port note: Commented this out since it was unused.
#if 0
struct fileDialogHandler:public GUIEventCallback{
public:
//The ret(urn) value, true=ok and false=cancel
bool ret;
//Boolean if it's a save dialog.
bool isSave;
//Boolean if the file should be verified.
bool verifyFile;
//Boolean if files should be listed instead of directories.
bool files;
//Pointer to the textfield containing the filename.
GUIObject* txtName;
//Pointer to the listbox containing the different files.
GUIListBox* lstFile;
//The extension the files listed should have.
const char* extension;
//The current filename.
string fileName;
//The current search path.
string path;
//Vector containing the search paths.
vector<string> searchPath;
public:
//Constructor.
fileDialogHandler(bool isSave=false,bool verifyFile=false, bool files=true):ret(false),
isSave(isSave),verifyFile(verifyFile),
files(files),txtName(NULL),lstFile(NULL),extension(NULL){}
void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer,std::string name,GUIObject* obj,int /*eventType*/) override {
//Check for the ok event.
if(name=="cmdOK"){
//Get the entered fileName from the text field.
std::string s=txtName->caption;
//If it doesn't contain a slash we need to add the path to the fileName.
if(s.find_first_of("/")==string::npos)
s=path+s;
//If the string empty we return.
if(s.empty() || s.find_first_of("*?")!=string::npos)
return;
//We only need to check for extensions if it isn't a folder dialog.
if(files){
//If there isn't right extension add it.
size_t found=s.find_first_of(".");
if(found!=string::npos)
s.replace(s.begin()+found+1,s.end(),extension);
else if (s.substr(found+1)!=extension)
s.append(string(".")+extension);
}
//Check if we should save or load the file.
//
if(isSave){
//Open the file with read permission to check if it already exists.
FILE* f;
f=fopen(processFileName(s).c_str(),"rb");
//Check if it exists.
if(f){
//Close the file.
fclose(f);
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render(imageManager,renderer);
//Prompt the user with a Yes or No question.
/// TRANSLATORS: Filename is coming before this text
if(msgBox(imageManager,renderer, tfm::format(_("%s already exists.\nDo you want to overwrite it?"),s),MsgBoxYesNo,_("Overwrite Prompt"))!=MsgBoxYes){
//He answered no, so we return.
return;
}
}
//Check if we should verify the file.
//Verifying only applies to files not to directories.
if(verifyFile && files){
//Open the file with write permission.
f=fopen(processFileName(s).c_str(),"wb");
//Check if their aren't problems.
if(f){
//Close the file.
fclose(f);
}else{
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render(imageManager,renderer);
//The file can't be opened so tell the user.
msgBox(imageManager,renderer, tfm::format(_("Can't open file %s."),s),MsgBoxOKOnly,_("Error"));
return;
}
}
}else if(verifyFile && files){
//We need to verify a file for opening.
FILE *f;
f=fopen(processFileName(s).c_str(),"rb");
//Check if it didn't fail.
if(f){
//Succes, so close the file.
fclose(f);
}else{
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render(imageManager,renderer);
//Unable to open file so tell the user.
msgBox(imageManager,renderer, tfm::format(_("Can't open file %s."),s),MsgBoxOKOnly,_("Error"));
return;
}
}
//If we haven't returned then it's fine.
//Set the fileName to the chosen file.
fileName=s;
//Delete the GUI.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Set return to true.
ret=true;
}else if(name=="cmdCancel"){
//Cancel means we can kill the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}else if(name=="lstFile"){
//Get a pointer to the listbox.
GUIListBox* obj1=lstFile;
//Make sure the option exist and change textfield to it.
if(obj1!=NULL && txtName!=NULL && obj1->value>=0 && obj1->value<(int)obj1->item.size()){
txtName->caption=obj1->item[obj1->value];
}
}else if(name=="lstSearchIn"){
//Get the searchpath listbox.
GUISingleLineListBox *obj1=dynamic_cast<GUISingleLineListBox*>(obj);
//Check if the entry exists.
if(obj1!=NULL && lstFile!=NULL && obj1->value>=0 && obj1->value<(int)searchPath.size()){
//Temp string.
string s;
//Get the new search path.
path=searchPath[obj1->value];
//Make sure it isn't empty.
if(!path.empty()){
//Process the filename.
s=processFileName(path);
}else{
//It's empty so we give the userpath.
s=getUserPath();
}
//Fill the list with files or directories.
if(files) {
lstFile->item=enumAllFiles(s,extension);
}else
lstFile->item=enumAllDirs(s);
//Remove any selection from the list.
lstFile->value=-1;
}
}
}
};
bool fileDialog(ImageManager& imageManager,SDL_Renderer& renderer, string& fileName,const char* title,const char* extension,const char* path,bool isSave,bool verifyFile,bool files){
//Pointer to GUIObject to make the GUI with.
GUIObject* obj;
//Create the fileDialogHandler, used for event handling.
fileDialogHandler objHandler(isSave,verifyFile,files);
//Vector containing the pathNames.
vector<string> pathNames;
//Set the extension of the objHandler.
objHandler.extension=extension;
//We now need to splits the given path into multiple path names.
if(path && path[0]){
//The string isn't empty.
//Pointer to the paths string.
char* lp=(char*)path;
//Pointer to the first newline.
char* lps=strchr(lp,'\n');
//Pointer used for checking if their's another newline.
//It will indicate if it's the last set or not.
char* lpe;
//Check for a newline.
if(lps){
//We have newline(s) so loop forever.
//We can only break out of the loop when the string ends.
for(;;){
//Add the first searchpath.
//This is the beginning of the string (lp) to the first newline. (lps)
objHandler.searchPath.push_back(string(lp,lps-lp));
//We should have another newline so search for it.
lpe=strchr(lps+1,'\n');
if(lpe){
//We found it so we add that to the pathname.
pathNames.push_back(string(lps+1,lpe-lps-1));
//And start over again by setting lp to the start of a new set of searchPath/pathName.
lp=lpe+1;
}else{
//There is no newline anymore, meaning the last entry, the rest of the string must be the pathName.
pathNames.push_back(string(lps+1));
//And break out of the loop.
break;
}
//We haven't broken out so search for a newline.
lps=strchr(lp,'\n');
//If there isn't a newline break.
if(!lps)
break;
}
}else{
//There is no newline thus the whole string is the searchPath.
objHandler.searchPath.push_back(path);
}
}else{
//Empty so put an empty string as searchPath.
objHandler.searchPath.push_back(string());
}
//It's time to create the GUI.
//If there are more than one pathNames we need to add a GUISingleLineListBox.
int base_y=pathNames.empty()?20:60;
//Create the frame.
GUIObject* root=new GUIFrame(100,100-base_y/2,600,400+base_y,title?title:(isSave?_("Save File"):_("Load File")));
//Create the search path list box if needed.
if(!pathNames.empty()){
root->addChild(new GUILabel(8,40,184,36,_("Search In")));
GUISingleLineListBox* obj1=new GUISingleLineListBox(160,40,432,36);
obj1->addItems(pathNames);
obj1->value=0;
obj1->name="lstSearchIn";
obj1->eventCallback=&objHandler;
root->addChild(obj1);
}
//Add the FileName label and textfield.
root->addChild(new GUILabel(8,20+base_y,184,36,_("File Name")));
{
//Fill the textbox with the given fileName.
string s=fileName;
if(!isSave){
//But only if it isn't empty.
if(s.empty() && extension && extension[0])
s=string("*.")+string(extension);
}
//Create the textbox and add it to the GUI.
objHandler.txtName=new GUITextBox(160,20+base_y,432,36,s.c_str());
root->addChild(objHandler.txtName);
}
//Now we add the ListBox containing the files or directories.
{
GUIListBox* obj1=new GUIListBox(8,60+base_y,584,292);
//Get the searchPath.
string s=objHandler.searchPath[0];
//Make sure it isn't empty.
if(!s.empty()){
objHandler.path=s;
s=processFileName(s);
}else{
s=getUserPath();
}
//Check if we should list files or directories.
if(files){
//Fill the list with files.
obj1->item=enumAllFiles(s,extension);
}else{
//Fill the list with directories.
obj1->item=enumAllDirs(s);
}
obj1->name="lstFile";
obj1->eventCallback=&objHandler;
root->addChild(obj1);
objHandler.lstFile=obj1;
}
//Now create the OK and Cancel buttons.
obj=new GUIButton(200,360+base_y,192,36,_("OK"));
obj->name="cmdOK";
obj->eventCallback=&objHandler;
root->addChild(obj);
obj=new GUIButton(400,360+base_y,192,36,_("Cancel"));
obj->name="cmdCancel";
obj->eventCallback=&objHandler;
root->addChild(obj);
//Create the gui overlay.
GUIOverlay* overlay=new GUIOverlay(renderer,root);
overlay->enterLoop(imageManager,renderer);
//Now determine what the return value is (and if there is one).
if(objHandler.ret)
fileName=objHandler.fileName;
return objHandler.ret;
}
#endif
// A helper function to read a character from utf8 string
// s: the string
// p [in,out]: the position
// return value: the character readed, in utf32 format, 0 means end of string, -1 means error
int utf8ReadForward(const char* s, int& p) {
int ch = (unsigned char)s[p];
if (ch < 0x80){
if (ch) p++;
return ch;
} else if (ch < 0xC0){
// skip invalid characters
while (((unsigned char)s[p] & 0xC0) == 0x80) p++;
return -1;
} else if (ch < 0xE0){
int c2 = (unsigned char)s[++p];
if ((c2 & 0xC0) != 0x80) return -1;
ch = ((ch & 0x1F) << 6) | (c2 & 0x3F);
p++;
return ch;
} else if (ch < 0xF0){
int c2 = (unsigned char)s[++p];
if ((c2 & 0xC0) != 0x80) return -1;
int c3 = (unsigned char)s[++p];
if ((c3 & 0xC0) != 0x80) return -1;
ch = ((ch & 0xF) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F);
p++;
return ch;
} else if (ch < 0xF8){
int c2 = (unsigned char)s[++p];
if ((c2 & 0xC0) != 0x80) return -1;
int c3 = (unsigned char)s[++p];
if ((c3 & 0xC0) != 0x80) return -1;
int c4 = (unsigned char)s[++p];
if ((c4 & 0xC0) != 0x80) return -1;
ch = ((ch & 0x7) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F);
if (ch >= 0x110000) ch = -1;
p++;
return ch;
} else {
p++;
return -1;
}
}
// A helper function to read a character backward from utf8 string (experimental)
// s: the string
// p [in,out]: the position
// return value: the character readed, in utf32 format, 0 means end of string, -1 means error
int utf8ReadBackward(const char* s, int& p) {
if (p <= 0) return 0;
do {
p--;
} while (p > 0 && ((unsigned char)s[p] & 0xC0) == 0x80);
int tmp = p;
return utf8ReadForward(s, tmp);
}
#ifndef WIN32
// ad-hoc function to check if a program is installed
static bool programExists(const std::string& program) {
std::string p = tfm::format("which \"%s\" 2>&1", program);
const int BUFSIZE = 128;
char buf[BUFSIZE];
FILE *fp;
if ((fp = popen(p.c_str(), "r")) == NULL) {
return false;
}
while (fgets(buf, BUFSIZE, fp) != NULL) {
// Drop all outputs since 'which' returns -1 when the program is not found
}
if (pclose(fp)) {
return false;
}
return true;
}
#endif
void openWebsite(const std::string& url) {
#ifdef WIN32
SDL_SysWMinfo info;
SDL_GetWindowWMInfo(sdlWindow,&info);
ShellExecuteA(info.info.win.window, "open", url.c_str(), NULL, NULL, SW_SHOW);
#else
static int method = -1;
// Some of these methods are copied from https://stackoverflow.com/questions/5116473/
const char* methods[] = {
"xdg-open", "xdg-open \"%s\"",
"gnome-open", "gnome-open \"%s\"",
"kde-open", "kde-open \"%s\"",
"open", "open \"%s\"",
"python", "python -m webbrowser \"%s\"",
"sensible-browser", "sensible-browser \"%s\"",
"x-www-browser", "x-www-browser \"%s\"",
NULL,
};
if (method < 0) {
for (method = 0; methods[method]; method += 2) {
if (programExists(methods[method])) break;
}
}
if (methods[method]) {
std::string p = tfm::format(methods[method + 1], url);
system(p.c_str());
} else {
fprintf(stderr, "TODO: openWebsite is not implemented on your system\n");
}
#endif
}
std::string appendURLToLicense(const std::string& license) {
// if the license doesn't include url, try to detect it from a predefined list
if (license.find("://") == std::string::npos) {
std::string normalized;
for (char c : license) {
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')) {
normalized.push_back(c);
} else if (c >= 'a' && c <= 'z') {
normalized.push_back(c + ('A' - 'a'));
}
}
const char* licenses[] = {
// AGPL
"AGPL1", "AGPLV1", NULL, "http://www.affero.org/oagpl.html",
"AGPL2", "AGPLV2", NULL, "http://www.affero.org/agpl2.html",
"AGPL", NULL, "https://gnu.org/licenses/agpl.html",
// LGPL
"LGPL21", "LGPLV21", NULL, "https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html",
"LGPL2", "LGPLV2", NULL, "https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html",
"LGPL", NULL, "https://www.gnu.org/copyleft/lesser.html",
// GPL
"GPL1", "GPLV1", NULL, "https://www.gnu.org/licenses/old-licenses/gpl-1.0.html",
"GPL2", "GPLV2", NULL, "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html",
"GPL", NULL, "https://gnu.org/licenses/gpl.html",
// CC BY-NC-ND
"CCBYNCND1", "CCBYNDNC1", NULL, "https://creativecommons.org/licenses/by-nd-nc/1.0",
"CCBYNCND25", "CCBYNDNC25", NULL, "https://creativecommons.org/licenses/by-nc-nd/2.5",
"CCBYNCND2", "CCBYNDNC2", NULL, "https://creativecommons.org/licenses/by-nc-nd/2.0",
"CCBYNCND3", "CCBYNDNC3", NULL, "https://creativecommons.org/licenses/by-nc-nd/3.0",
"CCBYNCND", "CCBYNDNC", NULL, "https://creativecommons.org/licenses/by-nc-nd/4.0",
// CC BY-NC-SA
"CCBYNCSA1", NULL, "https://creativecommons.org/licenses/by-nc-sa/1.0",
"CCBYNCSA25", NULL, "https://creativecommons.org/licenses/by-nc-sa/2.5",
"CCBYNCSA2", NULL, "https://creativecommons.org/licenses/by-nc-sa/2.0",
"CCBYNCSA3", NULL, "https://creativecommons.org/licenses/by-nc-sa/3.0",
"CCBYNCSA", NULL, "https://creativecommons.org/licenses/by-nc-sa/4.0",
// CC BY-ND
"CCBYND1", NULL, "https://creativecommons.org/licenses/by-nd/1.0",
"CCBYND25", NULL, "https://creativecommons.org/licenses/by-nd/2.5",
"CCBYND2", NULL, "https://creativecommons.org/licenses/by-nd/2.0",
"CCBYND3", NULL, "https://creativecommons.org/licenses/by-nd/3.0",
"CCBYND", NULL, "https://creativecommons.org/licenses/by-nd/4.0",
// CC BY-NC
"CCBYNC1", NULL, "https://creativecommons.org/licenses/by-nc/1.0",
"CCBYNC25", NULL, "https://creativecommons.org/licenses/by-nc/2.5",
"CCBYNC2", NULL, "https://creativecommons.org/licenses/by-nc/2.0",
"CCBYNC3", NULL, "https://creativecommons.org/licenses/by-nc/3.0",
"CCBYNC", NULL, "https://creativecommons.org/licenses/by-nc/4.0",
// CC BY-SA
"CCBYSA1", NULL, "https://creativecommons.org/licenses/by-sa/1.0",
"CCBYSA25", NULL, "https://creativecommons.org/licenses/by-sa/2.5",
"CCBYSA2", NULL, "https://creativecommons.org/licenses/by-sa/2.0",
"CCBYSA3", NULL, "https://creativecommons.org/licenses/by-sa/3.0",
"CCBYSA", NULL, "https://creativecommons.org/licenses/by-sa/4.0",
// CC BY
"CCBY1", NULL, "https://creativecommons.org/licenses/by/1.0",
"CCBY25", NULL, "https://creativecommons.org/licenses/by/2.5",
"CCBY2", NULL, "https://creativecommons.org/licenses/by/2.0",
"CCBY3", NULL, "https://creativecommons.org/licenses/by/3.0",
"CCBY", NULL, "https://creativecommons.org/licenses/by/4.0",
// CC0
"CC0", NULL, "https://creativecommons.org/publicdomain/zero/1.0",
// WTFPL
"WTFPL", NULL, "http://www.wtfpl.net/",
// end
NULL,
};
for (int i = 0; licenses[i]; i++) {
bool found = false;
for (; licenses[i]; i++) {
if (normalized.find(licenses[i]) != std::string::npos) found = true;
}
i++;
if (found) {
return license + tfm::format(" <%s>", licenses[i]);
}
}
}
return license;
}
diff --git a/src/TitleMenu.cpp b/src/OptionsMenu.cpp
similarity index 58%
copy from src/TitleMenu.cpp
copy to src/OptionsMenu.cpp
index c6b7ae7..d91daa6 100644
--- a/src/TitleMenu.cpp
+++ b/src/OptionsMenu.cpp
@@ -1,884 +1,520 @@
-/*
- * Copyright (C) 2011-2013 Me and My Shadow
- *
- * This file is part of Me and My Shadow.
- *
- * Me and My Shadow is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Me and My Shadow is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "Functions.h"
-#include "GameState.h"
-#include "TitleMenu.h"
-#include "ThemeManager.h"
-#include "GUIListBox.h"
-#include "GUITextArea.h"
-#include "InputManager.h"
-#include "LevelPackManager.h"
-#include "StatisticsManager.h"
-#include "MusicManager.h"
-#include "SoundManager.h"
-#include <iostream>
-#include <algorithm>
-#include <sstream>
-
-#include "libs/tinygettext/tinygettext.hpp"
-
-using namespace std;
-
-/////////////////////////MAIN_MENU//////////////////////////////////
-
-Menu::Menu(ImageManager &imageManager, SDL_Renderer& renderer){
- animation=highlight=0;
-
- //Load the title image.
- titleTexture=imageManager.loadTexture(getDataPath()+"gfx/menu/title.png",renderer);
-
-
- auto tft = [&](const char* text){
- return textureFromText(renderer, *fontTitle, text, objThemes.getTextColor(false));
- };
-
- //Now render the five entries.
- entries[0]=tft(_("Play"));
- entries[1]=tft(_("Options"));
- entries[2]=tft(_("Map Editor"));
- entries[3]=tft(_("Addons"));
- entries[4]=tft(_("Quit"));
- entries[5]=tft(">");
- entries[6]=tft("<");
-
- //Load the textures for the credits and statistics buttons and their tooltips.
- creditsIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/credits.png", renderer);
- creditsTooltip=textureFromText(renderer, *fontText, _("Credits"), objThemes.getTextColor(true));
- statisticsIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/statistics.png", renderer);
- statisticsTooltip=textureFromText(renderer, *fontText, _("Achievements and Statistics"), objThemes.getTextColor(true));
-
- // Check if textures were loaded.
- //TODO: Handle this better.
- if(!titleTexture || !creditsIcon || !statisticsIcon) {
- std::cerr << "Failed to load one or more images for the main menu, exiting. : " << SDL_GetError() << std::endl;
- std::terminate();
- }
-}
-
-Menu::~Menu(){
-}
-
-
-void Menu::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
- //Get the x and y location of the mouse.
- int x,y;
- SDL_GetMouseState(&x,&y);
-
- //Calculate which option is highlighted using the location of the mouse.
- //Only if mouse is 'doing something'
- if(event.type==SDL_MOUSEMOTION || event.type==SDL_MOUSEBUTTONDOWN){
- highlight=0;
-
- if(x>=200&&x<SCREEN_WIDTH-200&&y>=(SCREEN_HEIGHT-250)/2&&y<(SCREEN_HEIGHT-200)/2+320){
- highlight=(y-((SCREEN_HEIGHT-200)/2-64))/64;
- if(highlight>5) highlight=0;
- }
-
- //Also check the icons.
- if(y>=SCREEN_HEIGHT-56&&y<SCREEN_HEIGHT-8){
- if(x>=SCREEN_WIDTH-8){
- //do nothing
- }else if(x>=SCREEN_WIDTH-56){
- highlight=7;
- }else if(x>=SCREEN_WIDTH-104){
- highlight=6;
- }
- }
- }
-
- //Down/Up -arrows move highlight
- int mod = SDL_GetModState();
- if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN) || inputMgr.isKeyDownEvent(INPUTMGR_RIGHT) || (inputMgr.isKeyDownEvent(INPUTMGR_TAB) && (mod & KMOD_SHIFT) == 0)) {
- isKeyboardOnly = true;
- highlight++;
- if(highlight>7)
- highlight=1;
- } else if (inputMgr.isKeyDownEvent(INPUTMGR_UP) || inputMgr.isKeyDownEvent(INPUTMGR_LEFT) || (inputMgr.isKeyDownEvent(INPUTMGR_TAB) && (mod & KMOD_SHIFT) != 0)) {
- isKeyboardOnly = true;
- highlight--;
- if(highlight<1)
- highlight=7;
- }
-
- //Check if there's a press event.
- if((event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT) ||
- (inputMgr.isKeyDownEvent(INPUTMGR_SELECT))){
- //We have one so check which selected/highlighted option needs to be done.
- switch(highlight){
- case 1:
- //Enter the levelSelect state.
- setNextState(STATE_LEVEL_SELECT);
- break;
- case 2:
- //Enter the options state.
- setNextState(STATE_OPTIONS);
- break;
- case 3:
- //Enter the levelEditor, but first set the level to a default leveledit map.
- levelName="";
- setNextState(STATE_LEVEL_EDIT_SELECT);
- break;
- case 4:
- //Check if internet is enabled.
- if(!getSettings()->getBoolValue("internet")){
- msgBox(imageManager,renderer,_("Enable internet in order to install addons."),MsgBoxOKOnly,_("Internet disabled"));
- break;
- }
-
- //Enter the addons state.
- setNextState(STATE_ADDONS);
- break;
- case 5:
- //We quit, so we enter the exit state.
- setNextState(STATE_EXIT);
- break;
- case 6:
- //Show the credits screen.
- setNextState(STATE_CREDITS);
- break;
- case 7:
- //Show the statistics screen.
- setNextState(STATE_STATISTICS);
- break;
- }
- }
-
- //We also need to quit the menu when escape is pressed.
- if(inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
- setNextState(STATE_EXIT);
- }
-
- //Check if we need to quit, if so we enter the exit state.
- if(event.type==SDL_QUIT){
- setNextState(STATE_EXIT);
- }
-}
-
-void Menu::logic(ImageManager&, SDL_Renderer&){
- animation++;
- if(animation>10)
- animation=-10;
-}
-
-void Menu::render(ImageManager&, SDL_Renderer& renderer){
- //Draw background.
- objThemes.getBackground(true)->draw(renderer);
- objThemes.getBackground(true)->updateAnimation();
-
- //Draw the title.
- {
- int titleWidth, titleHeight = 0;
- SDL_QueryTexture(titleTexture.get(), NULL, NULL, &titleWidth, &titleHeight);
- const SDL_Rect rect = SDL_Rect{(SCREEN_WIDTH-titleWidth)/2, 40, titleWidth, titleHeight};
- SDL_RenderCopy(&renderer, titleTexture.get(), NULL, &rect);
- }
-
- // Position where we start drawing the menu entries from.
- const int menuStartY = std::max(SCREEN_HEIGHT - 200, 0) / 2;
-
- //Draw the menu entries.
- for(unsigned int i=0;i<5;i++){
- SDL_Rect dstRect = rectFromTexture(0, 0, *entries[i]);
- dstRect.x = std::max(SCREEN_WIDTH - dstRect.w, 0) / 2;
- dstRect.y = menuStartY + 64*i+(64-dstRect.h) / 2;
- SDL_RenderCopy(&renderer, entries[i].get(), NULL, &dstRect);
- }
-
- //Check if an option is selected/highlighted.
- if(highlight>0 && highlight<=5){
- // Width of highlighted entry.
- const int highlightWidth = rectFromTexture(0, 0, *entries[highlight - 1]).w;
- const int leftOfHighlight = (SCREEN_WIDTH-highlightWidth)/2;
- const SDL_Rect leftSize = rectFromTexture(0, 0, *entries[5]);
- const int rightHeight = rectFromTexture(0, 0, *entries[6]).h;
- // How much to offset the arrows to create the animation.
- const int animationX = (25-abs(animation)/2);
- // The common value of both arrow's y positions.
- const int yCommon = menuStartY-64+64*highlight;
-
- //Draw the '>' sign, which is entry 5.
- int x=leftOfHighlight-animationX-leftSize.w;
- int y=yCommon+(64-leftSize.h)/2;
- applyTexture(x, y, *entries[5], renderer);
-
- //Draw the '<' sign, which is entry 6.
- x=leftOfHighlight+highlightWidth+animationX;
- y=yCommon+(64-rightHeight)/2;
- applyTexture(x, y, *entries[6], renderer);
- }
-
- //Check if an icon is selected/highlighted and draw tooltip
- if(highlight==6 || highlight==7){
- SDL_Texture* texture;
- if(highlight==6) {
- texture = creditsTooltip.get();
- } else {
- texture = statisticsTooltip.get();
- }
- const SDL_Rect textureSize = rectFromTexture(*texture);
- drawGUIBox(-2,SCREEN_HEIGHT-textureSize.h-2,textureSize.w+4,textureSize.h+4,renderer,0xFFFFFFFF);
- applyTexture(0, SCREEN_HEIGHT - textureSize.h, *texture, renderer);
- }
-
- //Draw border of icon if it's keyboard only mode.
- if (isKeyboardOnly) {
- if (highlight == 6) {
- drawGUIBox(SCREEN_WIDTH - 100, SCREEN_HEIGHT - 52, 40, 40, renderer, 0xFFFFFF40);
- }
- if (highlight == 7) {
- drawGUIBox(SCREEN_WIDTH - 52, SCREEN_HEIGHT - 52, 40, 40, renderer, 0xFFFFFF40);
- }
- }
-
- //Draw icons.
- applyTexture(SCREEN_WIDTH-96,SCREEN_HEIGHT-48,*creditsIcon,renderer);
- applyTexture(SCREEN_WIDTH-48,SCREEN_HEIGHT-48,*statisticsIcon,renderer);
-}
-
-void Menu::resize(ImageManager &, SDL_Renderer&){}
-
-
-/////////////////////////OPTIONS_MENU//////////////////////////////////
-
-//Some variables for the options.
-static bool fullscreen,internet,fade,quickrec;
-static string themeName,languageName;
-static int lastLang,lastRes;
-
-static bool useProxy;
-static string internetProxy;
-
-static bool restartFlag;
-
-static _res currentRes;
-static vector<_res> resolutionList;
-
-Options::Options(ImageManager& imageManager,SDL_Renderer& renderer){
- //Render the title.
- title=textureFromText(renderer, *fontTitle, _("Settings"), objThemes.getTextColor(false));
-
- //Initialize variables.
- lastJumpSound=0;
- clearIconHower=false;
-
- //Load icon image and tooltip text.
- clearIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/clear-progress.png",renderer);
- /// TRANSLATORS: Used for button which clear any level progress like unlocked levels and highscores.
- clearTooltip=textureFromText(renderer, *fontText, _("Clear Progress"), objThemes.getTextColor(true));
-
- //Set some default settings.
- fullscreen=getSettings()->getBoolValue("fullscreen");
- languageName=getSettings()->getValue("lang");
- themeName=processFileName(getSettings()->getValue("theme"));
- internet=getSettings()->getBoolValue("internet");
- internetProxy=getSettings()->getValue("internet-proxy");
- useProxy=!internetProxy.empty();
- fade=getSettings()->getBoolValue("fading");
- quickrec=getSettings()->getBoolValue("quickrecord");
-
- //Set the restartFlag false.
- restartFlag=false;
-
- //Now create the gui.
- createGUI(imageManager,renderer);
-}
-
-Options::~Options(){
- //Delete the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
-}
-
-void Options::createGUI(ImageManager& imageManager,SDL_Renderer& renderer){
- //Variables for positioning
- const int columnW=SCREEN_WIDTH*0.3;
- const int column1X=SCREEN_WIDTH*0.15;
- const int column2X=SCREEN_WIDTH*0.55;
- const int lineHeight=40;
-
- //Create the root element of the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
- GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
-
- //Single line list for different tabs.
- GUISingleLineListBox* listBox=new GUISingleLineListBox(imageManager,renderer,(SCREEN_WIDTH-500)/2,104,500,32);
- listBox->addItem(_("General"));
- listBox->addItem(_("Controls"));
- listBox->value=0;
- listBox->name="lstTabs";
- listBox->eventCallback=this;
- GUIObjectRoot->addChild(listBox);
-
- //Create general tab.
- tabGeneral=new GUIObject(imageManager,renderer,0,150,SCREEN_WIDTH,SCREEN_HEIGHT);
- GUIObjectRoot->addChild(tabGeneral);
-
- //Now we create GUIObjects for every option.
- GUIObject* obj=new GUILabel(imageManager,renderer,column1X,0,columnW,36,_("Music"));
- tabGeneral->addChild(obj);
-
- musicSlider=new GUISlider(imageManager,renderer,column2X,0,columnW,36,atoi(getSettings()->getValue("music").c_str()),0,128,15);
- musicSlider->name="sldMusic";
- musicSlider->eventCallback=this;
- tabGeneral->addChild(musicSlider);
-
- obj=new GUILabel(imageManager,renderer,column1X,lineHeight,columnW,36,_("Sound"));
- tabGeneral->addChild(obj);
-
- soundSlider=new GUISlider(imageManager,renderer,column2X,lineHeight,columnW,36,atoi(getSettings()->getValue("sound").c_str()),0,128,15);
- soundSlider->name="sldSound";
- soundSlider->eventCallback=this;
- tabGeneral->addChild(soundSlider);
-
- obj=new GUILabel(imageManager,renderer,column1X,2*lineHeight,columnW,36,_("Resolution"));
- obj->name="lstResolution";
- tabGeneral->addChild(obj);
-
- //Create list with many different resolutions.
- resolutions = new GUISingleLineListBox(imageManager,renderer,column2X,2*lineHeight,columnW,36);
- resolutions->value=-1;
-
- //Only get the resolution list if it hasn't been done before.
- if(resolutionList.empty()){
- resolutionList=getResolutionList();
- }
-
- //Get current resolution from config file. Thus it can be user defined.
- currentRes.w=atoi(getSettings()->getValue("width").c_str());
- currentRes.h=atoi(getSettings()->getValue("height").c_str());
-
- for(int i=0; i<(int)resolutionList.size();i++){
- //Create a string from width and height and then add it to list.
- ostringstream out;
- out << resolutionList[i].w << "x" << resolutionList[i].h;
- resolutions->addItem(out.str());
-
- //Check if current resolution matches, select it.
- if(resolutionList[i].w==currentRes.w && resolutionList[i].h==currentRes.h){
- resolutions->value=i;
- }
- }
-
- //Add current resolution if it isn't already in the list.
- if(resolutions->value==-1){
- ostringstream out;
- out << currentRes.w << "x" << currentRes.h;
- resolutions->addItem(out.str());
- resolutions->value=resolutions->item.size()-1;
- }
- lastRes=resolutions->value;
-
- tabGeneral->addChild(resolutions);
-
- obj=new GUILabel(imageManager,renderer,column1X,3*lineHeight,columnW,36,_("Language"));
- tabGeneral->addChild(obj);
-
- //Create GUI list with available languages.
- langs = new GUISingleLineListBox(imageManager,renderer,column2X,3*lineHeight,columnW,36);
- langs->name="lstLanguages";
-
- /// TRANSLATORS: as detect user's language automatically
- langs->addItem("",_("Auto-Detect"));
- langs->addItem("en","English");
-
- //Get a list of every available language.
- set<tinygettext::Language> languages = dictionaryManager->get_languages();
- for (set<tinygettext::Language>::iterator s0 = languages.begin(); s0 != languages.end(); ++s0){
- //If language in loop is the same in config file, then select it
- if(getSettings()->getValue("lang")==s0->str()){
- lastLang=distance(languages.begin(),s0)+2;
- }
- //Add language in loop to list and listbox.
- langs->addItem(s0->str(),s0->get_name());
- }
-
- //If Auto or English are selected.
- if(getSettings()->getValue("lang")==""){
- lastLang=0;
- }else if(getSettings()->getValue("lang")=="en"){
- lastLang=1;
- }
-
- langs->value=lastLang;
- tabGeneral->addChild(langs);
-
- obj=new GUILabel(imageManager,renderer,column1X,4*lineHeight,columnW,36,_("Theme"));
- obj->name="theme";
- tabGeneral->addChild(obj);
-
- //Create the theme option gui element.
- theme=new GUISingleLineListBox(imageManager,renderer,column2X,4*lineHeight,columnW,36);
- theme->name="lstTheme";
-
- //Vector containing the theme locations and names.
- vector<pair<string,string> > themes;
- vector<string> v=enumAllDirs(getUserPath(USER_DATA)+"themes/");
- for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
- string location=getUserPath(USER_DATA)+"themes/"+*i;
- themes.push_back(pair<string,string>(location,*i));
- }
- vector<string> v2=enumAllDirs(getDataPath()+"themes/");
- for(vector<string>::iterator i=v2.begin(); i!=v2.end(); ++i){
- string location=getDataPath()+"themes/"+*i;
- themes.push_back(pair<string,string>(location,*i));
- }
-
- //Try to find the configured theme so we can display it.
- int value=-1;
- for(vector<pair<string,string> >::iterator i=themes.begin(); i!=themes.end(); ++i){
- if(i->first==themeName) {
- value=i-themes.begin();
- }
- }
- theme->addItems(themes);
- if(value==-1)
- value=theme->item.size()-1;
- theme->value=value;
- //NOTE: We call the event handling method to correctly set the themename.
- GUIEventCallback_OnEvent(imageManager,renderer,"lstTheme",theme,GUIEventChange);
- theme->eventCallback=this;
- tabGeneral->addChild(theme);
-
- //Proxy settings.
- obj=new GUILabel(imageManager,renderer,column1X,5*lineHeight,columnW,36,_("Internet proxy"));
- obj->name="chkProxy";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
- obj=new GUITextBox(imageManager,renderer,column2X,5*lineHeight,columnW,36,internetProxy.c_str());
- obj->name="txtProxy";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column1X,6*lineHeight,columnW,36,_("Fullscreen"),fullscreen?1:0);
- obj->name="chkFullscreen";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column2X,6*lineHeight,columnW,36,_("Internet"),internet?1:0);
- obj->name="chkInternet";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column2X,7*lineHeight,columnW,36,_("Fade transition"),fade?1:0);
- obj->name="chkFade";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column1X,7*lineHeight,columnW,36,_("Quick record"),quickrec?1:0);
- obj->name="chkQuickRec";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- //Create the controls tab.
- tabControls=inputMgr.showConfig(imageManager,renderer,SCREEN_HEIGHT-210);
- tabControls->top=140;
- tabControls->visible=false;
- GUIObjectRoot->addChild(tabControls);
-
- //Save original keys.
- for(int i=0;i<INPUTMGR_MAX;i++){
- tmpKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,false);
- tmpAlternativeKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,true);
- }
-
- //Create buttons.
- GUIObject*b1=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.3,SCREEN_HEIGHT-60,-1,36,_("Cancel"),0,true,true,GUIGravityCenter);
- b1->name="cmdBack";
- b1->eventCallback=this;
- GUIObjectRoot->addChild(b1);
-
- GUIObject* b2=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.7,SCREEN_HEIGHT-60,-1,36,_("Save Changes"),0,true,true,GUIGravityCenter);
- b2->name="cmdSave";
- b2->eventCallback=this;
- GUIObjectRoot->addChild(b2);
-}
-
-static string convertInt(int i){
- stringstream ss;
- ss << i;
- return ss.str();
-}
-
-void Options::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
- //Check what type of event it was.
- if(eventType==GUIEventClick){
- if(name=="cmdBack"){
- //Reset the key changes.
- for(int i=0;i<INPUTMGR_MAX;i++){
- inputMgr.setKeyCode((InputManagerKeys)i,tmpKeys[i],false);
- inputMgr.setKeyCode((InputManagerKeys)i,tmpAlternativeKeys[i],true);
- }
-
- //Reset the music volume.
- getMusicManager()->setVolume(atoi(getSettings()->getValue("music").c_str()));
- Mix_Volume(-1,atoi(getSettings()->getValue("sound").c_str()));
-
- //And goto the main menu.
- setNextState(STATE_MENU);
- }else if(name=="cmdSave"){
- //Save is pressed thus save
- char s[64];
- sprintf(s,"%d",soundSlider->value);
- getSettings()->setValue("sound",s);
- sprintf(s,"%d",musicSlider->value);
- getSettings()->setValue("music",s);
- getMusicManager()->setEnabled(musicSlider->value>0);
- Mix_Volume(-1,soundSlider->value);
- getSettings()->setValue("fullscreen",fullscreen?"1":"0");
- getSettings()->setValue("internet",internet?"1":"0");
- getSettings()->setValue("theme",themeName);
- getSettings()->setValue("fading",fade?"1":"0");
- getSettings()->setValue("quickrecord",quickrec?"1":"0");
- //Before loading the theme remove the previous one from the stack.
- objThemes.removeTheme();
- loadTheme(imageManager,renderer,themeName);
- if(!useProxy)
- internetProxy.clear();
- getSettings()->setValue("internet-proxy",internetProxy);
- getSettings()->setValue("lang",langs->getName());
-
- //Is resolution from the list or is it user defined in config file
- if(resolutions->value<(int)resolutionList.size()){
- getSettings()->setValue("width",convertInt(resolutionList[resolutions->value].w));
- getSettings()->setValue("height",convertInt(resolutionList[resolutions->value].h));
- }else{
- getSettings()->setValue("width",convertInt(currentRes.w));
- getSettings()->setValue("height",convertInt(currentRes.h));
- }
-
- //Save the key configuration.
- inputMgr.saveConfig();
-
- //Save the settings.
- saveSettings();
-
- //Before we return check if some .
- if(restartFlag || resolutions->value!=lastRes){
- //The resolution changed so we need to recreate the screen.
- if(!createScreen()){
- //Screen creation failed so set to safe settings.
- getSettings()->setValue("fullscreen","0");
- getSettings()->setValue("width",convertInt(resolutionList[lastRes].w));
- getSettings()->setValue("height",convertInt(resolutionList[lastRes].h));
-
- if(!createScreen()){
- //Everything fails so quit.
- setNextState(STATE_EXIT);
- return;
- }
- }
-
- //The screen is created, now load the (menu) theme.
- if(!loadTheme(imageManager,renderer,"")){
- //Loading the theme failed so quit.
- setNextState(STATE_EXIT);
- return;
- }
- }
-
- if(langs->value!=lastLang){
- //We set the language.
- language=langs->getName();
- dictionaryManager->set_language(tinygettext::Language::from_name(language));
- getLevelPackManager()->updateLanguage();
-
- //And reload the font.
- if(!loadFonts()){
- //Loading failed so quit.
- setNextState(STATE_EXIT);
- return;
- }
- }
-
- //Now return to the main menu.
- setNextState(STATE_MENU);
- }else if(name=="chkFullscreen"){
- fullscreen=obj->value?true:false;
-
- //Check if fullscreen changed.
- if(fullscreen==getSettings()->getBoolValue("fullscreen")){
- //We disable the restart message flag.
- restartFlag=false;
- }else{
- //We set the restart message flag.
- restartFlag=true;
- }
-
- }else if(name=="chkInternet"){
- internet=obj->value?true:false;
- }else if(name=="chkProxy"){
- useProxy=obj->value?true:false;
- }else if(name=="chkFade"){
- fade=obj->value?true:false;
- }else if(name=="chkQuickRec"){
- quickrec=obj->value?true:false;
- }
- }
- if(name=="lstTheme"){
- if(theme!=NULL && theme->value>=0 && theme->value<(int)theme->item.size()){
- //Convert the themeName to contain %DATA%, etc...
- themeName=compressFileName(theme->item[theme->value].first);
- }
- }else if(name=="txtProxy"){
- internetProxy=obj->caption;
-
- //Check if the internetProxy field is empty.
- useProxy=!internetProxy.empty();
- }else if(name=="sldMusic"){
- getMusicManager()->setEnabled(musicSlider->value>0);
- getMusicManager()->setVolume(musicSlider->value);
- }else if(name=="sldSound"){
- Mix_Volume(-1,soundSlider->value);
- if(lastJumpSound==0){
- getSoundManager()->playSound("jump");
- lastJumpSound=15;
- }
- }
- if(name=="lstTabs"){
- if(obj->value==0){
- tabGeneral->visible=true;
- tabControls->visible=false;
- }else{
- tabGeneral->visible=false;
- tabControls->visible=true;
- }
- }
-}
-
-void Options::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
- //Get the x and y location of the mouse.
- int x,y;
- SDL_GetMouseState(&x,&y);
-
- //Check icon.
- if(event.type==SDL_MOUSEMOTION || event.type==SDL_MOUSEBUTTONDOWN){
- if(y>=SCREEN_HEIGHT-56&&y<SCREEN_HEIGHT-8&&x>=SCREEN_WIDTH-56)
- clearIconHower=true;
- else
- clearIconHower=false;
- }
-
- if(event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT && clearIconHower){
- if(msgBox(imageManager,renderer,_("Do you really want to reset level progress?"),MsgBoxYesNo,_("Warning"))==MsgBoxYes){
- //We delete the progress folder.
-#ifdef WIN32
- removeDirectory((getUserPath()+"progress").c_str());
- createDirectory((getUserPath()+"progress").c_str());
-#else
- removeDirectory((getUserPath(USER_DATA)+"/progress").c_str());
- createDirectory((getUserPath(USER_DATA)+"/progress").c_str());
-#endif
- //Reset statistics.
- statsMgr.reloadCompletedLevelsAndAchievements();
- }
- }
-
- //Check if we need to quit, if so enter the exit state.
- if(event.type==SDL_QUIT){
- setNextState(STATE_EXIT);
- }
-
- //Check if the escape button is pressed, if so go back to the main menu.
- if (inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE) && (tabControls == NULL || !tabControls->visible)) {
- setNextState(STATE_MENU);
- }
-}
-
-void Options::logic(ImageManager&, SDL_Renderer&){
- //Increase the lastJumpSound variable if needed.
- if(lastJumpSound!=0){
- lastJumpSound--;
- }
-}
-
-void Options::render(ImageManager&, SDL_Renderer& renderer){
- //Draw background.
- objThemes.getBackground(true)->draw(renderer);
- objThemes.getBackground(true)->updateAnimation();
-
- //Now render the title.
- drawTitleTexture(SCREEN_WIDTH, *title, renderer);
-
- //Check if an icon is selected/highlighted and draw tooltip
- if(clearIconHower){
- const SDL_Rect texSize = rectFromTexture(*clearTooltip);
- drawGUIBox(-2,SCREEN_HEIGHT-texSize.h-2,texSize.w+4,texSize.h+4,renderer,0xFFFFFFFF);
- applyTexture(0,SCREEN_HEIGHT-texSize.h,clearTooltip,renderer);
- }
-
- //Draw icon.
- applyTexture(SCREEN_WIDTH-48,SCREEN_HEIGHT-48,*clearIcon,renderer);
-
- //NOTE: The rendering of the GUI is done in Main.
-}
-
-void Options::resize(ImageManager& imageManager, SDL_Renderer& renderer){
- //Recreate the gui to fit the new resolution.
- createGUI(imageManager,renderer);
-}
-
-/////////////////////////CREDITS_MENU//////////////////////////////////
-
-Credits::Credits(ImageManager& imageManager,SDL_Renderer& renderer){
- //Render the title.
- title=textureFromText(renderer, *fontTitle,_("Credits"),objThemes.getTextColor(false));
-
- //Vector that will hold every line of the credits.
- vector<string> credits;
-
- //Open the AUTHORS file and read every line.
- {
- ifstream fin((getDataPath()+"/../AUTHORS").c_str());
- if(!fin.is_open()) {
- cerr<<"ERROR: Unable to open the AUTHORS file."<<endl;
- credits.push_back("ERROR: Unable to open the AUTHORS file.");
- credits.push_back("");
- }
-
- //Loop the lines of the file.
- string line;
- while(getline(fin,line)){
- credits.push_back(line);
- }
- }
-
- //Enter a new line between the two files.
- credits.push_back("");
-
- //Open the Credits.text file and read every line.
- {
- ifstream fin((getDataPath()+"/Credits.txt").c_str());
- if(!fin.is_open()) {
- cerr<<"ERROR: Unable to open the Credits.txt file."<<endl;
- credits.push_back("ERROR: Unable to open the Credits.txt file.");
- credits.push_back("");
- }
-
- //Loop the lines of the file.
- string line;
- while(getline(fin,line)){
- credits.push_back(line);
-
- //NOTE: Some sections point to other credits files.
- if(line=="music/") {
- vector<string> musicCredits=getMusicManager()->createCredits();
- credits.insert(credits.end(),musicCredits.begin(),musicCredits.end());
- }
- }
- }
-
- //Create the root element of the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
- GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
-
- //Create back button.
- backButton=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,36,_("Back"),0,true,true,GUIGravityCenter);
- backButton->name="cmdBack";
- backButton->eventCallback=this;
- GUIObjectRoot->addChild(backButton);
-
- //Create a text area for credits.
- textArea=new GUITextArea(imageManager,renderer,SCREEN_WIDTH*0.05,114,SCREEN_WIDTH*0.9,SCREEN_HEIGHT-200);
- textArea->setFont(fontMono);
- textArea->setStringArray(renderer, std::move(credits));
- textArea->editable=false;
- textArea->extractHyperlinks();
- GUIObjectRoot->addChild(textArea);
-}
-
-Credits::~Credits(){
- //Delete the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
-}
-
-void Credits::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
- //Check what type of event it was.
- if(eventType==GUIEventClick){
- if(name=="cmdBack"){
- //Goto the main menu.
- setNextState(STATE_MENU);
- }
- }
-}
-
-void Credits::handleEvents(ImageManager&, SDL_Renderer&){
- //Check if we need to quit, if so enter the exit state.
- if(event.type==SDL_QUIT){
- setNextState(STATE_EXIT);
- }
-
- //Check movement
- if (inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(20, 0);
- } else if (inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(-20, 0);
- } else if (inputMgr.isKeyDownEvent(INPUTMGR_UP)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(0, -1);
- } else if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(0, 1);
- }
-
- //Check if the escape button is pressed, if so go back to the main menu.
- if(inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
- setNextState(STATE_MENU);
- }
-}
-
-void Credits::logic(ImageManager&, SDL_Renderer&){}
-
-void Credits::render(ImageManager&,SDL_Renderer &renderer){
- //Draw background.
- objThemes.getBackground(true)->draw(renderer);
- objThemes.getBackground(true)->updateAnimation();
-
- //Now render the title.
- drawTitleTexture(SCREEN_WIDTH, *title, renderer);
-
- //NOTE: The rendering of the GUI is done in Main.
-}
-
-void Credits::resize(ImageManager&, SDL_Renderer&){
- //Resize and position widgets.
- GUIObjectRoot->width=SCREEN_WIDTH;
- GUIObjectRoot->height=SCREEN_HEIGHT;
-
- backButton->left=SCREEN_WIDTH/2;
- backButton->top=SCREEN_HEIGHT-60;
-
- textArea->left=SCREEN_WIDTH*0.05;
- textArea->width=SCREEN_WIDTH*0.9;
- textArea->height=SCREEN_HEIGHT-200;
- textArea->resize();
-}
+/*
+ * Copyright (C) 2011-2013 Me and My Shadow
+ *
+ * This file is part of Me and My Shadow.
+ *
+ * Me and My Shadow is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Me and My Shadow is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Functions.h"
+#include "GameState.h"
+#include "OptionsMenu.h"
+#include "ThemeManager.h"
+#include "GUIListBox.h"
+#include "GUISlider.h"
+#include "InputManager.h"
+#include "LevelPackManager.h"
+#include "StatisticsManager.h"
+#include "MusicManager.h"
+#include "SoundManager.h"
+#include <iostream>
+#include <sstream>
+
+#include "libs/tinygettext/tinygettext.hpp"
+
+using namespace std;
+
+/////////////////////////OPTIONS_MENU//////////////////////////////////
+
+//Some variables for the options.
+static bool fullscreen,internet,fade,quickrec;
+static string themeName,languageName;
+static int lastLang,lastRes;
+
+static bool useProxy;
+static string internetProxy;
+
+static bool restartFlag;
+
+static _res currentRes;
+static vector<_res> resolutionList;
+
+Options::Options(ImageManager& imageManager,SDL_Renderer& renderer){
+ //Render the title.
+ title=textureFromText(renderer, *fontTitle, _("Settings"), objThemes.getTextColor(false));
+
+ //Initialize variables.
+ lastJumpSound=0;
+ clearIconHower=false;
+
+ //Load icon image and tooltip text.
+ clearIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/clear-progress.png",renderer);
+ /// TRANSLATORS: Used for button which clear any level progress like unlocked levels and highscores.
+ clearTooltip=textureFromText(renderer, *fontText, _("Clear Progress"), objThemes.getTextColor(true));
+
+ //Set some default settings.
+ fullscreen=getSettings()->getBoolValue("fullscreen");
+ languageName=getSettings()->getValue("lang");
+ themeName=processFileName(getSettings()->getValue("theme"));
+ internet=getSettings()->getBoolValue("internet");
+ internetProxy=getSettings()->getValue("internet-proxy");
+ useProxy=!internetProxy.empty();
+ fade=getSettings()->getBoolValue("fading");
+ quickrec=getSettings()->getBoolValue("quickrecord");
+
+ //Set the restartFlag false.
+ restartFlag=false;
+
+ //Now create the gui.
+ createGUI(imageManager,renderer);
+}
+
+Options::~Options(){
+ //Delete the GUI.
+ if(GUIObjectRoot){
+ delete GUIObjectRoot;
+ GUIObjectRoot=NULL;
+ }
+}
+
+void Options::createGUI(ImageManager& imageManager,SDL_Renderer& renderer){
+ //Variables for positioning
+ const int columnW=SCREEN_WIDTH*0.3;
+ const int column1X=SCREEN_WIDTH*0.15;
+ const int column2X=SCREEN_WIDTH*0.55;
+ const int lineHeight=40;
+
+ //Create the root element of the GUI.
+ if(GUIObjectRoot){
+ delete GUIObjectRoot;
+ GUIObjectRoot=NULL;
+ }
+ GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
+
+ //Single line list for different tabs.
+ GUISingleLineListBox* listBox=new GUISingleLineListBox(imageManager,renderer,(SCREEN_WIDTH-500)/2,104,500,32);
+ listBox->addItem(_("General"));
+ listBox->addItem(_("Controls"));
+ listBox->value=0;
+ listBox->name="lstTabs";
+ listBox->eventCallback=this;
+ GUIObjectRoot->addChild(listBox);
+
+ //Create general tab.
+ tabGeneral=new GUIObject(imageManager,renderer,0,150,SCREEN_WIDTH,SCREEN_HEIGHT);
+ GUIObjectRoot->addChild(tabGeneral);
+
+ //Now we create GUIObjects for every option.
+ GUIObject* obj=new GUILabel(imageManager,renderer,column1X,0,columnW,36,_("Music"));
+ tabGeneral->addChild(obj);
+
+ musicSlider=new GUISlider(imageManager,renderer,column2X,0,columnW,36,atoi(getSettings()->getValue("music").c_str()),0,128,15);
+ musicSlider->name="sldMusic";
+ musicSlider->eventCallback=this;
+ tabGeneral->addChild(musicSlider);
+
+ obj=new GUILabel(imageManager,renderer,column1X,lineHeight,columnW,36,_("Sound"));
+ tabGeneral->addChild(obj);
+
+ soundSlider=new GUISlider(imageManager,renderer,column2X,lineHeight,columnW,36,atoi(getSettings()->getValue("sound").c_str()),0,128,15);
+ soundSlider->name="sldSound";
+ soundSlider->eventCallback=this;
+ tabGeneral->addChild(soundSlider);
+
+ obj=new GUILabel(imageManager,renderer,column1X,2*lineHeight,columnW,36,_("Resolution"));
+ obj->name="lstResolution";
+ tabGeneral->addChild(obj);
+
+ //Create list with many different resolutions.
+ resolutions = new GUISingleLineListBox(imageManager,renderer,column2X,2*lineHeight,columnW,36);
+ resolutions->value=-1;
+
+ //Only get the resolution list if it hasn't been done before.
+ if(resolutionList.empty()){
+ resolutionList=getResolutionList();
+ }
+
+ //Get current resolution from config file. Thus it can be user defined.
+ currentRes.w=atoi(getSettings()->getValue("width").c_str());
+ currentRes.h=atoi(getSettings()->getValue("height").c_str());
+
+ for(int i=0; i<(int)resolutionList.size();i++){
+ //Create a string from width and height and then add it to list.
+ ostringstream out;
+ out << resolutionList[i].w << "x" << resolutionList[i].h;
+ resolutions->addItem(out.str());
+
+ //Check if current resolution matches, select it.
+ if(resolutionList[i].w==currentRes.w && resolutionList[i].h==currentRes.h){
+ resolutions->value=i;
+ }
+ }
+
+ //Add current resolution if it isn't already in the list.
+ if(resolutions->value==-1){
+ ostringstream out;
+ out << currentRes.w << "x" << currentRes.h;
+ resolutions->addItem(out.str());
+ resolutions->value=resolutions->item.size()-1;
+ }
+ lastRes=resolutions->value;
+
+ tabGeneral->addChild(resolutions);
+
+ obj=new GUILabel(imageManager,renderer,column1X,3*lineHeight,columnW,36,_("Language"));
+ tabGeneral->addChild(obj);
+
+ //Create GUI list with available languages.
+ langs = new GUISingleLineListBox(imageManager,renderer,column2X,3*lineHeight,columnW,36);
+ langs->name="lstLanguages";
+
+ /// TRANSLATORS: as detect user's language automatically
+ langs->addItem("",_("Auto-Detect"));
+ langs->addItem("en","English");
+
+ //Get a list of every available language.
+ set<tinygettext::Language> languages = dictionaryManager->get_languages();
+ for (set<tinygettext::Language>::iterator s0 = languages.begin(); s0 != languages.end(); ++s0){
+ //If language in loop is the same in config file, then select it
+ if(getSettings()->getValue("lang")==s0->str()){
+ lastLang=distance(languages.begin(),s0)+2;
+ }
+ //Add language in loop to list and listbox.
+ langs->addItem(s0->str(),s0->get_name());
+ }
+
+ //If Auto or English are selected.
+ if(getSettings()->getValue("lang")==""){
+ lastLang=0;
+ }else if(getSettings()->getValue("lang")=="en"){
+ lastLang=1;
+ }
+
+ langs->value=lastLang;
+ tabGeneral->addChild(langs);
+
+ obj=new GUILabel(imageManager,renderer,column1X,4*lineHeight,columnW,36,_("Theme"));
+ obj->name="theme";
+ tabGeneral->addChild(obj);
+
+ //Create the theme option gui element.
+ theme=new GUISingleLineListBox(imageManager,renderer,column2X,4*lineHeight,columnW,36);
+ theme->name="lstTheme";
+
+ //Vector containing the theme locations and names.
+ vector<pair<string,string> > themes;
+ vector<string> v=enumAllDirs(getUserPath(USER_DATA)+"themes/");
+ for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
+ string location=getUserPath(USER_DATA)+"themes/"+*i;
+ themes.push_back(pair<string,string>(location,*i));
+ }
+ vector<string> v2=enumAllDirs(getDataPath()+"themes/");
+ for(vector<string>::iterator i=v2.begin(); i!=v2.end(); ++i){
+ string location=getDataPath()+"themes/"+*i;
+ themes.push_back(pair<string,string>(location,*i));
+ }
+
+ //Try to find the configured theme so we can display it.
+ int value=-1;
+ for(vector<pair<string,string> >::iterator i=themes.begin(); i!=themes.end(); ++i){
+ if(i->first==themeName) {
+ value=i-themes.begin();
+ }
+ }
+ theme->addItems(themes);
+ if(value==-1)
+ value=theme->item.size()-1;
+ theme->value=value;
+ //NOTE: We call the event handling method to correctly set the themename.
+ GUIEventCallback_OnEvent(imageManager,renderer,"lstTheme",theme,GUIEventChange);
+ theme->eventCallback=this;
+ tabGeneral->addChild(theme);
+
+ //Proxy settings.
+ obj=new GUILabel(imageManager,renderer,column1X,5*lineHeight,columnW,36,_("Internet proxy"));
+ obj->name="chkProxy";
+ obj->eventCallback=this;
+ tabGeneral->addChild(obj);
+ obj=new GUITextBox(imageManager,renderer,column2X,5*lineHeight,columnW,36,internetProxy.c_str());
+ obj->name="txtProxy";
+ obj->eventCallback=this;
+ tabGeneral->addChild(obj);
+
+ obj=new GUICheckBox(imageManager,renderer,column1X,6*lineHeight,columnW,36,_("Fullscreen"),fullscreen?1:0);
+ obj->name="chkFullscreen";
+ obj->eventCallback=this;
+ tabGeneral->addChild(obj);
+
+ obj=new GUICheckBox(imageManager,renderer,column2X,6*lineHeight,columnW,36,_("Internet"),internet?1:0);
+ obj->name="chkInternet";
+ obj->eventCallback=this;
+ tabGeneral->addChild(obj);
+
+ obj=new GUICheckBox(imageManager,renderer,column2X,7*lineHeight,columnW,36,_("Fade transition"),fade?1:0);
+ obj->name="chkFade";
+ obj->eventCallback=this;
+ tabGeneral->addChild(obj);
+
+ obj=new GUICheckBox(imageManager,renderer,column1X,7*lineHeight,columnW,36,_("Quick record"),quickrec?1:0);
+ obj->name="chkQuickRec";
+ obj->eventCallback=this;
+ tabGeneral->addChild(obj);
+
+ //Create the controls tab.
+ tabControls=inputMgr.showConfig(imageManager,renderer,SCREEN_HEIGHT-210);
+ tabControls->top=140;
+ tabControls->visible=false;
+ GUIObjectRoot->addChild(tabControls);
+
+ //Save original keys.
+ for(int i=0;i<INPUTMGR_MAX;i++){
+ tmpKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,false);
+ tmpAlternativeKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,true);
+ }
+
+ //Create buttons.
+ GUIObject*b1=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.3,SCREEN_HEIGHT-60,-1,36,_("Cancel"),0,true,true,GUIGravityCenter);
+ b1->name="cmdBack";
+ b1->eventCallback=this;
+ GUIObjectRoot->addChild(b1);
+
+ GUIObject* b2=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.7,SCREEN_HEIGHT-60,-1,36,_("Save Changes"),0,true,true,GUIGravityCenter);
+ b2->name="cmdSave";
+ b2->eventCallback=this;
+ GUIObjectRoot->addChild(b2);
+}
+
+static string convertInt(int i){
+ stringstream ss;
+ ss << i;
+ return ss.str();
+}
+
+void Options::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
+ //Check what type of event it was.
+ if(eventType==GUIEventClick){
+ if(name=="cmdBack"){
+ //Reset the key changes.
+ for(int i=0;i<INPUTMGR_MAX;i++){
+ inputMgr.setKeyCode((InputManagerKeys)i,tmpKeys[i],false);
+ inputMgr.setKeyCode((InputManagerKeys)i,tmpAlternativeKeys[i],true);
+ }
+
+ //Reset the music volume.
+ getMusicManager()->setVolume(atoi(getSettings()->getValue("music").c_str()));
+ Mix_Volume(-1,atoi(getSettings()->getValue("sound").c_str()));
+
+ //And goto the main menu.
+ setNextState(STATE_MENU);
+ }else if(name=="cmdSave"){
+ //Save is pressed thus save
+ char s[64];
+ sprintf(s,"%d",soundSlider->value);
+ getSettings()->setValue("sound",s);
+ sprintf(s,"%d",musicSlider->value);
+ getSettings()->setValue("music",s);
+ getMusicManager()->setEnabled(musicSlider->value>0);
+ Mix_Volume(-1,soundSlider->value);
+ getSettings()->setValue("fullscreen",fullscreen?"1":"0");
+ getSettings()->setValue("internet",internet?"1":"0");
+ getSettings()->setValue("theme",themeName);
+ getSettings()->setValue("fading",fade?"1":"0");
+ getSettings()->setValue("quickrecord",quickrec?"1":"0");
+ //Before loading the theme remove the previous one from the stack.
+ objThemes.removeTheme();
+ loadTheme(imageManager,renderer,themeName);
+ if(!useProxy)
+ internetProxy.clear();
+ getSettings()->setValue("internet-proxy",internetProxy);
+ getSettings()->setValue("lang",langs->getName());
+
+ //Is resolution from the list or is it user defined in config file
+ if(resolutions->value<(int)resolutionList.size()){
+ getSettings()->setValue("width",convertInt(resolutionList[resolutions->value].w));
+ getSettings()->setValue("height",convertInt(resolutionList[resolutions->value].h));
+ }else{
+ getSettings()->setValue("width",convertInt(currentRes.w));
+ getSettings()->setValue("height",convertInt(currentRes.h));
+ }
+
+ //Save the key configuration.
+ inputMgr.saveConfig();
+
+ //Save the settings.
+ saveSettings();
+
+ //Before we return check if some .
+ if(restartFlag || resolutions->value!=lastRes){
+ //The resolution changed so we need to recreate the screen.
+ if(!createScreen()){
+ //Screen creation failed so set to safe settings.
+ getSettings()->setValue("fullscreen","0");
+ getSettings()->setValue("width",convertInt(resolutionList[lastRes].w));
+ getSettings()->setValue("height",convertInt(resolutionList[lastRes].h));
+
+ if(!createScreen()){
+ //Everything fails so quit.
+ setNextState(STATE_EXIT);
+ return;
+ }
+ }
+
+ //The screen is created, now load the (menu) theme.
+ if(!loadTheme(imageManager,renderer,"")){
+ //Loading the theme failed so quit.
+ setNextState(STATE_EXIT);
+ return;
+ }
+ }
+
+ if(langs->value!=lastLang){
+ //We set the language.
+ language=langs->getName();
+ dictionaryManager->set_language(tinygettext::Language::from_name(language));
+ getLevelPackManager()->updateLanguage();
+
+ //And reload the font.
+ if(!loadFonts()){
+ //Loading failed so quit.
+ setNextState(STATE_EXIT);
+ return;
+ }
+ }
+
+ //Now return to the main menu.
+ setNextState(STATE_MENU);
+ }else if(name=="chkFullscreen"){
+ fullscreen=obj->value?true:false;
+
+ //Check if fullscreen changed.
+ if(fullscreen==getSettings()->getBoolValue("fullscreen")){
+ //We disable the restart message flag.
+ restartFlag=false;
+ }else{
+ //We set the restart message flag.
+ restartFlag=true;
+ }
+
+ }else if(name=="chkInternet"){
+ internet=obj->value?true:false;
+ }else if(name=="chkProxy"){
+ useProxy=obj->value?true:false;
+ }else if(name=="chkFade"){
+ fade=obj->value?true:false;
+ }else if(name=="chkQuickRec"){
+ quickrec=obj->value?true:false;
+ }
+ }
+ if(name=="lstTheme"){
+ if(theme!=NULL && theme->value>=0 && theme->value<(int)theme->item.size()){
+ //Convert the themeName to contain %DATA%, etc...
+ themeName=compressFileName(theme->item[theme->value].first);
+ }
+ }else if(name=="txtProxy"){
+ internetProxy=obj->caption;
+
+ //Check if the internetProxy field is empty.
+ useProxy=!internetProxy.empty();
+ }else if(name=="sldMusic"){
+ getMusicManager()->setEnabled(musicSlider->value>0);
+ getMusicManager()->setVolume(musicSlider->value);
+ }else if(name=="sldSound"){
+ Mix_Volume(-1,soundSlider->value);
+ if(lastJumpSound==0){
+ getSoundManager()->playSound("jump");
+ lastJumpSound=15;
+ }
+ }
+ if(name=="lstTabs"){
+ if(obj->value==0){
+ tabGeneral->visible=true;
+ tabControls->visible=false;
+ }else{
+ tabGeneral->visible=false;
+ tabControls->visible=true;
+ }
+ }
+}
+
+void Options::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
+ //Get the x and y location of the mouse.
+ int x,y;
+ SDL_GetMouseState(&x,&y);
+
+ //Check icon.
+ if(event.type==SDL_MOUSEMOTION || event.type==SDL_MOUSEBUTTONDOWN){
+ if(y>=SCREEN_HEIGHT-56&&y<SCREEN_HEIGHT-8&&x>=SCREEN_WIDTH-56)
+ clearIconHower=true;
+ else
+ clearIconHower=false;
+ }
+
+ if(event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT && clearIconHower){
+ if(msgBox(imageManager,renderer,_("Do you really want to reset level progress?"),MsgBoxYesNo,_("Warning"))==MsgBoxYes){
+ //We delete the progress folder.
+#ifdef WIN32
+ removeDirectory((getUserPath()+"progress").c_str());
+ createDirectory((getUserPath()+"progress").c_str());
+#else
+ removeDirectory((getUserPath(USER_DATA)+"/progress").c_str());
+ createDirectory((getUserPath(USER_DATA)+"/progress").c_str());
+#endif
+ //Reset statistics.
+ statsMgr.reloadCompletedLevelsAndAchievements();
+ }
+ }
+
+ //Check if we need to quit, if so enter the exit state.
+ if(event.type==SDL_QUIT){
+ setNextState(STATE_EXIT);
+ }
+
+ //Check if the escape button is pressed, if so go back to the main menu.
+ if (inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE) && (tabControls == NULL || !tabControls->visible)) {
+ setNextState(STATE_MENU);
+ }
+}
+
+void Options::logic(ImageManager&, SDL_Renderer&){
+ //Increase the lastJumpSound variable if needed.
+ if(lastJumpSound!=0){
+ lastJumpSound--;
+ }
+}
+
+void Options::render(ImageManager&, SDL_Renderer& renderer){
+ //Draw background.
+ objThemes.getBackground(true)->draw(renderer);
+ objThemes.getBackground(true)->updateAnimation();
+
+ //Now render the title.
+ drawTitleTexture(SCREEN_WIDTH, *title, renderer);
+
+ //Check if an icon is selected/highlighted and draw tooltip
+ if(clearIconHower){
+ const SDL_Rect texSize = rectFromTexture(*clearTooltip);
+ drawGUIBox(-2,SCREEN_HEIGHT-texSize.h-2,texSize.w+4,texSize.h+4,renderer,0xFFFFFFFF);
+ applyTexture(0,SCREEN_HEIGHT-texSize.h,clearTooltip,renderer);
+ }
+
+ //Draw icon.
+ applyTexture(SCREEN_WIDTH-48,SCREEN_HEIGHT-48,*clearIcon,renderer);
+
+ //NOTE: The rendering of the GUI is done in Main.
+}
+
+void Options::resize(ImageManager& imageManager, SDL_Renderer& renderer){
+ //Recreate the gui to fit the new resolution.
+ createGUI(imageManager,renderer);
+}
diff --git a/src/TitleMenu.h b/src/OptionsMenu.h
similarity index 54%
copy from src/TitleMenu.h
copy to src/OptionsMenu.h
index 02a53d2..78a5c50 100644
--- a/src/TitleMenu.h
+++ b/src/OptionsMenu.h
@@ -1,159 +1,92 @@
-/*
- * Copyright (C) 2011-2013 Me and My Shadow
- *
- * This file is part of Me and My Shadow.
- *
- * Me and My Shadow is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Me and My Shadow is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TITLE_MENU_H
-#define TITLE_MENU_H
-
-#include <array>
-
-#include <SDL.h>
-#include "GameState.h"
-
-//Included for the Options menu.
-#include "Render.h"
-#include "GUIObject.h"
-#include "GUIListBox.h"
-#include "GUISlider.h"
-#include "GUITextArea.h"
-#include "InputManager.h"
-#include "ImageManager.h"
-
-//The Main menu.
-class Menu : public GameState{
-private:
- //The title of the main menu.
- SharedTexture titleTexture;
-
- //Array containg pointers the five main menu entries.
- //The last two are the '>' and '<' characters.
- std::array<TexturePtr, 7> entries;
-
- //The icon and for the statistics menu.
- SharedTexture statisticsIcon;
- TexturePtr statisticsTooltip;
-
- //The icon for the credits menu.
- SharedTexture creditsIcon;
- TexturePtr creditsTooltip;
-
- //Integer used for animations.
- int animation;
-
- //Integer containing the highlighted/selected menu option.
- int highlight;
-public:
- //Constructor.
- Menu(ImageManager& imageManager, SDL_Renderer &renderer);
- //Destructor.
- ~Menu();
-
- //Inherited from GameState.
- void handleEvents(ImageManager& imageManager, SDL_Renderer& renderer) override;
- void logic(ImageManager&, SDL_Renderer&) override;
- void render(ImageManager&, SDL_Renderer& renderer) override;
- void resize(ImageManager&, SDL_Renderer&) override;
-};
-
-//The Options menu.
-class Options : public GameState, private GUIEventCallback{
-private:
- //The title of the options menu.
- TexturePtr title;
-
- //Icon.
- SharedTexture clearIcon;
- bool clearIconHower;
- TexturePtr clearTooltip;
-
- //Slider used to set the music volume
- GUISlider* musicSlider;
- //Slider used to set the sound volume
- GUISlider* soundSlider;
-
- //Integer to keep track of the time passed since last playing the test sound.
- int lastJumpSound;
-
- //ListBox containing the themes the user can choose out.
- GUISingleLineListBox* theme;
-
- //Available languages
- GUISingleLineListBox* langs;
-
- //Resolution list
- GUISingleLineListBox* resolutions;
-
- //Containers for different tabs.
- GUIObject* tabGeneral;
- GUIObject* tabControls;
-
- //Keys.
- InputManagerKeyCode tmpKeys[INPUTMGR_MAX], tmpAlternativeKeys[INPUTMGR_MAX];
-
- //GUI events are handled here.
- //name: The name of the element that invoked the event.
- //obj: Pointer to the object that invoked the event.
- //eventType: Integer containing the type of event.
- void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
-
-public:
- //Constructor.
- Options(ImageManager& imageManager,SDL_Renderer& renderer);
- //Destructor.
- ~Options();
-
- //Method that will create the GUI for the options menu.
- void createGUI(ImageManager &imageManager, SDL_Renderer &renderer);
-
- //Inherited from GameState.
- void handleEvents(ImageManager& imageManager, SDL_Renderer& renderer) override;
- void logic(ImageManager&, SDL_Renderer&) override;
- void render(ImageManager&, SDL_Renderer& renderer) override;
- void resize(ImageManager &imageManager, SDL_Renderer&renderer) override;
-};
-
-//The Credits menu.
-class Credits : public GameState, private GUIEventCallback{
-private:
- //The title of the credits menu.
- TexturePtr title;
-
- //Widgets.
- GUITextArea* textArea;
- GUIObject* backButton;
-
- //GUI events are handled here.
- //name: The name of the element that invoked the event.
- //obj: Pointer to the object that invoked the event.
- //eventType: Integer containing the type of event.
- void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
-
-public:
- //Constructor.
- Credits(ImageManager& imageManager, SDL_Renderer &renderer);
- //Destructor.
- ~Credits();
-
- //Inherited from GameState.
- void handleEvents(ImageManager&, SDL_Renderer&) override;
- void logic(ImageManager&, SDL_Renderer&) override;
- void render(ImageManager&, SDL_Renderer& renderer) override;
- void resize(ImageManager &imageManager, SDL_Renderer& renderer) override;
-};
-
-#endif
+/*
+ * Copyright (C) 2011-2013 Me and My Shadow
+ *
+ * This file is part of Me and My Shadow.
+ *
+ * Me and My Shadow is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Me and My Shadow is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OPTIONS_MENU_H
+#define OPTIONS_MENU_H
+
+#include <SDL.h>
+#include "GameState.h"
+
+//Included for the Options menu.
+#include "Render.h"
+#include "GUIObject.h"
+#include "InputManager.h"
+#include "ImageManager.h"
+
+class GUISlider;
+class GUISingleLineListBox;
+
+//The Options menu.
+class Options : public GameState, private GUIEventCallback{
+private:
+ //The title of the options menu.
+ TexturePtr title;
+
+ //Icon.
+ SharedTexture clearIcon;
+ bool clearIconHower;
+ TexturePtr clearTooltip;
+
+ //Slider used to set the music volume
+ GUISlider* musicSlider;
+ //Slider used to set the sound volume
+ GUISlider* soundSlider;
+
+ //Integer to keep track of the time passed since last playing the test sound.
+ int lastJumpSound;
+
+ //ListBox containing the themes the user can choose out.
+ GUISingleLineListBox* theme;
+
+ //Available languages
+ GUISingleLineListBox* langs;
+
+ //Resolution list
+ GUISingleLineListBox* resolutions;
+
+ //Containers for different tabs.
+ GUIObject* tabGeneral;
+ GUIObject* tabControls;
+
+ //Keys.
+ InputManagerKeyCode tmpKeys[INPUTMGR_MAX], tmpAlternativeKeys[INPUTMGR_MAX];
+
+ //GUI events are handled here.
+ //name: The name of the element that invoked the event.
+ //obj: Pointer to the object that invoked the event.
+ //eventType: Integer containing the type of event.
+ void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
+
+public:
+ //Constructor.
+ Options(ImageManager& imageManager,SDL_Renderer& renderer);
+ //Destructor.
+ ~Options();
+
+ //Method that will create the GUI for the options menu.
+ void createGUI(ImageManager &imageManager, SDL_Renderer &renderer);
+
+ //Inherited from GameState.
+ void handleEvents(ImageManager& imageManager, SDL_Renderer& renderer) override;
+ void logic(ImageManager&, SDL_Renderer&) override;
+ void render(ImageManager&, SDL_Renderer& renderer) override;
+ void resize(ImageManager &imageManager, SDL_Renderer&renderer) override;
+};
+
+#endif
diff --git a/src/TitleMenu.cpp b/src/TitleMenu.cpp
index c6b7ae7..415a93a 100644
--- a/src/TitleMenu.cpp
+++ b/src/TitleMenu.cpp
@@ -1,884 +1,246 @@
/*
* Copyright (C) 2011-2013 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Functions.h"
#include "GameState.h"
#include "TitleMenu.h"
#include "ThemeManager.h"
-#include "GUIListBox.h"
-#include "GUITextArea.h"
#include "InputManager.h"
-#include "LevelPackManager.h"
-#include "StatisticsManager.h"
-#include "MusicManager.h"
-#include "SoundManager.h"
#include <iostream>
-#include <algorithm>
-#include <sstream>
-
-#include "libs/tinygettext/tinygettext.hpp"
using namespace std;
/////////////////////////MAIN_MENU//////////////////////////////////
Menu::Menu(ImageManager &imageManager, SDL_Renderer& renderer){
animation=highlight=0;
//Load the title image.
titleTexture=imageManager.loadTexture(getDataPath()+"gfx/menu/title.png",renderer);
auto tft = [&](const char* text){
return textureFromText(renderer, *fontTitle, text, objThemes.getTextColor(false));
};
//Now render the five entries.
entries[0]=tft(_("Play"));
entries[1]=tft(_("Options"));
entries[2]=tft(_("Map Editor"));
entries[3]=tft(_("Addons"));
entries[4]=tft(_("Quit"));
entries[5]=tft(">");
entries[6]=tft("<");
//Load the textures for the credits and statistics buttons and their tooltips.
creditsIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/credits.png", renderer);
creditsTooltip=textureFromText(renderer, *fontText, _("Credits"), objThemes.getTextColor(true));
statisticsIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/statistics.png", renderer);
statisticsTooltip=textureFromText(renderer, *fontText, _("Achievements and Statistics"), objThemes.getTextColor(true));
// Check if textures were loaded.
//TODO: Handle this better.
if(!titleTexture || !creditsIcon || !statisticsIcon) {
std::cerr << "Failed to load one or more images for the main menu, exiting. : " << SDL_GetError() << std::endl;
std::terminate();
}
}
Menu::~Menu(){
}
void Menu::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
//Get the x and y location of the mouse.
int x,y;
SDL_GetMouseState(&x,&y);
//Calculate which option is highlighted using the location of the mouse.
//Only if mouse is 'doing something'
if(event.type==SDL_MOUSEMOTION || event.type==SDL_MOUSEBUTTONDOWN){
highlight=0;
if(x>=200&&x<SCREEN_WIDTH-200&&y>=(SCREEN_HEIGHT-250)/2&&y<(SCREEN_HEIGHT-200)/2+320){
highlight=(y-((SCREEN_HEIGHT-200)/2-64))/64;
if(highlight>5) highlight=0;
}
//Also check the icons.
if(y>=SCREEN_HEIGHT-56&&y<SCREEN_HEIGHT-8){
if(x>=SCREEN_WIDTH-8){
//do nothing
}else if(x>=SCREEN_WIDTH-56){
highlight=7;
}else if(x>=SCREEN_WIDTH-104){
highlight=6;
}
}
}
//Down/Up -arrows move highlight
int mod = SDL_GetModState();
if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN) || inputMgr.isKeyDownEvent(INPUTMGR_RIGHT) || (inputMgr.isKeyDownEvent(INPUTMGR_TAB) && (mod & KMOD_SHIFT) == 0)) {
isKeyboardOnly = true;
highlight++;
if(highlight>7)
highlight=1;
} else if (inputMgr.isKeyDownEvent(INPUTMGR_UP) || inputMgr.isKeyDownEvent(INPUTMGR_LEFT) || (inputMgr.isKeyDownEvent(INPUTMGR_TAB) && (mod & KMOD_SHIFT) != 0)) {
isKeyboardOnly = true;
highlight--;
if(highlight<1)
highlight=7;
}
//Check if there's a press event.
if((event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT) ||
(inputMgr.isKeyDownEvent(INPUTMGR_SELECT))){
//We have one so check which selected/highlighted option needs to be done.
switch(highlight){
case 1:
//Enter the levelSelect state.
setNextState(STATE_LEVEL_SELECT);
break;
case 2:
//Enter the options state.
setNextState(STATE_OPTIONS);
break;
case 3:
//Enter the levelEditor, but first set the level to a default leveledit map.
levelName="";
setNextState(STATE_LEVEL_EDIT_SELECT);
break;
case 4:
//Check if internet is enabled.
if(!getSettings()->getBoolValue("internet")){
msgBox(imageManager,renderer,_("Enable internet in order to install addons."),MsgBoxOKOnly,_("Internet disabled"));
break;
}
//Enter the addons state.
setNextState(STATE_ADDONS);
break;
case 5:
//We quit, so we enter the exit state.
setNextState(STATE_EXIT);
break;
case 6:
//Show the credits screen.
setNextState(STATE_CREDITS);
break;
case 7:
//Show the statistics screen.
setNextState(STATE_STATISTICS);
break;
}
}
//We also need to quit the menu when escape is pressed.
if(inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_EXIT);
}
//Check if we need to quit, if so we enter the exit state.
if(event.type==SDL_QUIT){
setNextState(STATE_EXIT);
}
}
void Menu::logic(ImageManager&, SDL_Renderer&){
animation++;
if(animation>10)
animation=-10;
}
void Menu::render(ImageManager&, SDL_Renderer& renderer){
//Draw background.
objThemes.getBackground(true)->draw(renderer);
objThemes.getBackground(true)->updateAnimation();
//Draw the title.
{
int titleWidth, titleHeight = 0;
SDL_QueryTexture(titleTexture.get(), NULL, NULL, &titleWidth, &titleHeight);
const SDL_Rect rect = SDL_Rect{(SCREEN_WIDTH-titleWidth)/2, 40, titleWidth, titleHeight};
SDL_RenderCopy(&renderer, titleTexture.get(), NULL, &rect);
}
// Position where we start drawing the menu entries from.
const int menuStartY = std::max(SCREEN_HEIGHT - 200, 0) / 2;
//Draw the menu entries.
for(unsigned int i=0;i<5;i++){
SDL_Rect dstRect = rectFromTexture(0, 0, *entries[i]);
dstRect.x = std::max(SCREEN_WIDTH - dstRect.w, 0) / 2;
dstRect.y = menuStartY + 64*i+(64-dstRect.h) / 2;
SDL_RenderCopy(&renderer, entries[i].get(), NULL, &dstRect);
}
//Check if an option is selected/highlighted.
if(highlight>0 && highlight<=5){
// Width of highlighted entry.
const int highlightWidth = rectFromTexture(0, 0, *entries[highlight - 1]).w;
const int leftOfHighlight = (SCREEN_WIDTH-highlightWidth)/2;
const SDL_Rect leftSize = rectFromTexture(0, 0, *entries[5]);
const int rightHeight = rectFromTexture(0, 0, *entries[6]).h;
// How much to offset the arrows to create the animation.
const int animationX = (25-abs(animation)/2);
// The common value of both arrow's y positions.
const int yCommon = menuStartY-64+64*highlight;
//Draw the '>' sign, which is entry 5.
int x=leftOfHighlight-animationX-leftSize.w;
int y=yCommon+(64-leftSize.h)/2;
applyTexture(x, y, *entries[5], renderer);
//Draw the '<' sign, which is entry 6.
x=leftOfHighlight+highlightWidth+animationX;
y=yCommon+(64-rightHeight)/2;
applyTexture(x, y, *entries[6], renderer);
}
//Check if an icon is selected/highlighted and draw tooltip
if(highlight==6 || highlight==7){
SDL_Texture* texture;
if(highlight==6) {
texture = creditsTooltip.get();
} else {
texture = statisticsTooltip.get();
}
const SDL_Rect textureSize = rectFromTexture(*texture);
drawGUIBox(-2,SCREEN_HEIGHT-textureSize.h-2,textureSize.w+4,textureSize.h+4,renderer,0xFFFFFFFF);
applyTexture(0, SCREEN_HEIGHT - textureSize.h, *texture, renderer);
}
//Draw border of icon if it's keyboard only mode.
if (isKeyboardOnly) {
if (highlight == 6) {
drawGUIBox(SCREEN_WIDTH - 100, SCREEN_HEIGHT - 52, 40, 40, renderer, 0xFFFFFF40);
}
if (highlight == 7) {
drawGUIBox(SCREEN_WIDTH - 52, SCREEN_HEIGHT - 52, 40, 40, renderer, 0xFFFFFF40);
}
}
//Draw icons.
applyTexture(SCREEN_WIDTH-96,SCREEN_HEIGHT-48,*creditsIcon,renderer);
applyTexture(SCREEN_WIDTH-48,SCREEN_HEIGHT-48,*statisticsIcon,renderer);
}
void Menu::resize(ImageManager &, SDL_Renderer&){}
-
-/////////////////////////OPTIONS_MENU//////////////////////////////////
-
-//Some variables for the options.
-static bool fullscreen,internet,fade,quickrec;
-static string themeName,languageName;
-static int lastLang,lastRes;
-
-static bool useProxy;
-static string internetProxy;
-
-static bool restartFlag;
-
-static _res currentRes;
-static vector<_res> resolutionList;
-
-Options::Options(ImageManager& imageManager,SDL_Renderer& renderer){
- //Render the title.
- title=textureFromText(renderer, *fontTitle, _("Settings"), objThemes.getTextColor(false));
-
- //Initialize variables.
- lastJumpSound=0;
- clearIconHower=false;
-
- //Load icon image and tooltip text.
- clearIcon=imageManager.loadTexture(getDataPath()+"gfx/menu/clear-progress.png",renderer);
- /// TRANSLATORS: Used for button which clear any level progress like unlocked levels and highscores.
- clearTooltip=textureFromText(renderer, *fontText, _("Clear Progress"), objThemes.getTextColor(true));
-
- //Set some default settings.
- fullscreen=getSettings()->getBoolValue("fullscreen");
- languageName=getSettings()->getValue("lang");
- themeName=processFileName(getSettings()->getValue("theme"));
- internet=getSettings()->getBoolValue("internet");
- internetProxy=getSettings()->getValue("internet-proxy");
- useProxy=!internetProxy.empty();
- fade=getSettings()->getBoolValue("fading");
- quickrec=getSettings()->getBoolValue("quickrecord");
-
- //Set the restartFlag false.
- restartFlag=false;
-
- //Now create the gui.
- createGUI(imageManager,renderer);
-}
-
-Options::~Options(){
- //Delete the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
-}
-
-void Options::createGUI(ImageManager& imageManager,SDL_Renderer& renderer){
- //Variables for positioning
- const int columnW=SCREEN_WIDTH*0.3;
- const int column1X=SCREEN_WIDTH*0.15;
- const int column2X=SCREEN_WIDTH*0.55;
- const int lineHeight=40;
-
- //Create the root element of the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
- GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
-
- //Single line list for different tabs.
- GUISingleLineListBox* listBox=new GUISingleLineListBox(imageManager,renderer,(SCREEN_WIDTH-500)/2,104,500,32);
- listBox->addItem(_("General"));
- listBox->addItem(_("Controls"));
- listBox->value=0;
- listBox->name="lstTabs";
- listBox->eventCallback=this;
- GUIObjectRoot->addChild(listBox);
-
- //Create general tab.
- tabGeneral=new GUIObject(imageManager,renderer,0,150,SCREEN_WIDTH,SCREEN_HEIGHT);
- GUIObjectRoot->addChild(tabGeneral);
-
- //Now we create GUIObjects for every option.
- GUIObject* obj=new GUILabel(imageManager,renderer,column1X,0,columnW,36,_("Music"));
- tabGeneral->addChild(obj);
-
- musicSlider=new GUISlider(imageManager,renderer,column2X,0,columnW,36,atoi(getSettings()->getValue("music").c_str()),0,128,15);
- musicSlider->name="sldMusic";
- musicSlider->eventCallback=this;
- tabGeneral->addChild(musicSlider);
-
- obj=new GUILabel(imageManager,renderer,column1X,lineHeight,columnW,36,_("Sound"));
- tabGeneral->addChild(obj);
-
- soundSlider=new GUISlider(imageManager,renderer,column2X,lineHeight,columnW,36,atoi(getSettings()->getValue("sound").c_str()),0,128,15);
- soundSlider->name="sldSound";
- soundSlider->eventCallback=this;
- tabGeneral->addChild(soundSlider);
-
- obj=new GUILabel(imageManager,renderer,column1X,2*lineHeight,columnW,36,_("Resolution"));
- obj->name="lstResolution";
- tabGeneral->addChild(obj);
-
- //Create list with many different resolutions.
- resolutions = new GUISingleLineListBox(imageManager,renderer,column2X,2*lineHeight,columnW,36);
- resolutions->value=-1;
-
- //Only get the resolution list if it hasn't been done before.
- if(resolutionList.empty()){
- resolutionList=getResolutionList();
- }
-
- //Get current resolution from config file. Thus it can be user defined.
- currentRes.w=atoi(getSettings()->getValue("width").c_str());
- currentRes.h=atoi(getSettings()->getValue("height").c_str());
-
- for(int i=0; i<(int)resolutionList.size();i++){
- //Create a string from width and height and then add it to list.
- ostringstream out;
- out << resolutionList[i].w << "x" << resolutionList[i].h;
- resolutions->addItem(out.str());
-
- //Check if current resolution matches, select it.
- if(resolutionList[i].w==currentRes.w && resolutionList[i].h==currentRes.h){
- resolutions->value=i;
- }
- }
-
- //Add current resolution if it isn't already in the list.
- if(resolutions->value==-1){
- ostringstream out;
- out << currentRes.w << "x" << currentRes.h;
- resolutions->addItem(out.str());
- resolutions->value=resolutions->item.size()-1;
- }
- lastRes=resolutions->value;
-
- tabGeneral->addChild(resolutions);
-
- obj=new GUILabel(imageManager,renderer,column1X,3*lineHeight,columnW,36,_("Language"));
- tabGeneral->addChild(obj);
-
- //Create GUI list with available languages.
- langs = new GUISingleLineListBox(imageManager,renderer,column2X,3*lineHeight,columnW,36);
- langs->name="lstLanguages";
-
- /// TRANSLATORS: as detect user's language automatically
- langs->addItem("",_("Auto-Detect"));
- langs->addItem("en","English");
-
- //Get a list of every available language.
- set<tinygettext::Language> languages = dictionaryManager->get_languages();
- for (set<tinygettext::Language>::iterator s0 = languages.begin(); s0 != languages.end(); ++s0){
- //If language in loop is the same in config file, then select it
- if(getSettings()->getValue("lang")==s0->str()){
- lastLang=distance(languages.begin(),s0)+2;
- }
- //Add language in loop to list and listbox.
- langs->addItem(s0->str(),s0->get_name());
- }
-
- //If Auto or English are selected.
- if(getSettings()->getValue("lang")==""){
- lastLang=0;
- }else if(getSettings()->getValue("lang")=="en"){
- lastLang=1;
- }
-
- langs->value=lastLang;
- tabGeneral->addChild(langs);
-
- obj=new GUILabel(imageManager,renderer,column1X,4*lineHeight,columnW,36,_("Theme"));
- obj->name="theme";
- tabGeneral->addChild(obj);
-
- //Create the theme option gui element.
- theme=new GUISingleLineListBox(imageManager,renderer,column2X,4*lineHeight,columnW,36);
- theme->name="lstTheme";
-
- //Vector containing the theme locations and names.
- vector<pair<string,string> > themes;
- vector<string> v=enumAllDirs(getUserPath(USER_DATA)+"themes/");
- for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
- string location=getUserPath(USER_DATA)+"themes/"+*i;
- themes.push_back(pair<string,string>(location,*i));
- }
- vector<string> v2=enumAllDirs(getDataPath()+"themes/");
- for(vector<string>::iterator i=v2.begin(); i!=v2.end(); ++i){
- string location=getDataPath()+"themes/"+*i;
- themes.push_back(pair<string,string>(location,*i));
- }
-
- //Try to find the configured theme so we can display it.
- int value=-1;
- for(vector<pair<string,string> >::iterator i=themes.begin(); i!=themes.end(); ++i){
- if(i->first==themeName) {
- value=i-themes.begin();
- }
- }
- theme->addItems(themes);
- if(value==-1)
- value=theme->item.size()-1;
- theme->value=value;
- //NOTE: We call the event handling method to correctly set the themename.
- GUIEventCallback_OnEvent(imageManager,renderer,"lstTheme",theme,GUIEventChange);
- theme->eventCallback=this;
- tabGeneral->addChild(theme);
-
- //Proxy settings.
- obj=new GUILabel(imageManager,renderer,column1X,5*lineHeight,columnW,36,_("Internet proxy"));
- obj->name="chkProxy";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
- obj=new GUITextBox(imageManager,renderer,column2X,5*lineHeight,columnW,36,internetProxy.c_str());
- obj->name="txtProxy";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column1X,6*lineHeight,columnW,36,_("Fullscreen"),fullscreen?1:0);
- obj->name="chkFullscreen";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column2X,6*lineHeight,columnW,36,_("Internet"),internet?1:0);
- obj->name="chkInternet";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column2X,7*lineHeight,columnW,36,_("Fade transition"),fade?1:0);
- obj->name="chkFade";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- obj=new GUICheckBox(imageManager,renderer,column1X,7*lineHeight,columnW,36,_("Quick record"),quickrec?1:0);
- obj->name="chkQuickRec";
- obj->eventCallback=this;
- tabGeneral->addChild(obj);
-
- //Create the controls tab.
- tabControls=inputMgr.showConfig(imageManager,renderer,SCREEN_HEIGHT-210);
- tabControls->top=140;
- tabControls->visible=false;
- GUIObjectRoot->addChild(tabControls);
-
- //Save original keys.
- for(int i=0;i<INPUTMGR_MAX;i++){
- tmpKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,false);
- tmpAlternativeKeys[i]=inputMgr.getKeyCode((InputManagerKeys)i,true);
- }
-
- //Create buttons.
- GUIObject*b1=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.3,SCREEN_HEIGHT-60,-1,36,_("Cancel"),0,true,true,GUIGravityCenter);
- b1->name="cmdBack";
- b1->eventCallback=this;
- GUIObjectRoot->addChild(b1);
-
- GUIObject* b2=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.7,SCREEN_HEIGHT-60,-1,36,_("Save Changes"),0,true,true,GUIGravityCenter);
- b2->name="cmdSave";
- b2->eventCallback=this;
- GUIObjectRoot->addChild(b2);
-}
-
-static string convertInt(int i){
- stringstream ss;
- ss << i;
- return ss.str();
-}
-
-void Options::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
- //Check what type of event it was.
- if(eventType==GUIEventClick){
- if(name=="cmdBack"){
- //Reset the key changes.
- for(int i=0;i<INPUTMGR_MAX;i++){
- inputMgr.setKeyCode((InputManagerKeys)i,tmpKeys[i],false);
- inputMgr.setKeyCode((InputManagerKeys)i,tmpAlternativeKeys[i],true);
- }
-
- //Reset the music volume.
- getMusicManager()->setVolume(atoi(getSettings()->getValue("music").c_str()));
- Mix_Volume(-1,atoi(getSettings()->getValue("sound").c_str()));
-
- //And goto the main menu.
- setNextState(STATE_MENU);
- }else if(name=="cmdSave"){
- //Save is pressed thus save
- char s[64];
- sprintf(s,"%d",soundSlider->value);
- getSettings()->setValue("sound",s);
- sprintf(s,"%d",musicSlider->value);
- getSettings()->setValue("music",s);
- getMusicManager()->setEnabled(musicSlider->value>0);
- Mix_Volume(-1,soundSlider->value);
- getSettings()->setValue("fullscreen",fullscreen?"1":"0");
- getSettings()->setValue("internet",internet?"1":"0");
- getSettings()->setValue("theme",themeName);
- getSettings()->setValue("fading",fade?"1":"0");
- getSettings()->setValue("quickrecord",quickrec?"1":"0");
- //Before loading the theme remove the previous one from the stack.
- objThemes.removeTheme();
- loadTheme(imageManager,renderer,themeName);
- if(!useProxy)
- internetProxy.clear();
- getSettings()->setValue("internet-proxy",internetProxy);
- getSettings()->setValue("lang",langs->getName());
-
- //Is resolution from the list or is it user defined in config file
- if(resolutions->value<(int)resolutionList.size()){
- getSettings()->setValue("width",convertInt(resolutionList[resolutions->value].w));
- getSettings()->setValue("height",convertInt(resolutionList[resolutions->value].h));
- }else{
- getSettings()->setValue("width",convertInt(currentRes.w));
- getSettings()->setValue("height",convertInt(currentRes.h));
- }
-
- //Save the key configuration.
- inputMgr.saveConfig();
-
- //Save the settings.
- saveSettings();
-
- //Before we return check if some .
- if(restartFlag || resolutions->value!=lastRes){
- //The resolution changed so we need to recreate the screen.
- if(!createScreen()){
- //Screen creation failed so set to safe settings.
- getSettings()->setValue("fullscreen","0");
- getSettings()->setValue("width",convertInt(resolutionList[lastRes].w));
- getSettings()->setValue("height",convertInt(resolutionList[lastRes].h));
-
- if(!createScreen()){
- //Everything fails so quit.
- setNextState(STATE_EXIT);
- return;
- }
- }
-
- //The screen is created, now load the (menu) theme.
- if(!loadTheme(imageManager,renderer,"")){
- //Loading the theme failed so quit.
- setNextState(STATE_EXIT);
- return;
- }
- }
-
- if(langs->value!=lastLang){
- //We set the language.
- language=langs->getName();
- dictionaryManager->set_language(tinygettext::Language::from_name(language));
- getLevelPackManager()->updateLanguage();
-
- //And reload the font.
- if(!loadFonts()){
- //Loading failed so quit.
- setNextState(STATE_EXIT);
- return;
- }
- }
-
- //Now return to the main menu.
- setNextState(STATE_MENU);
- }else if(name=="chkFullscreen"){
- fullscreen=obj->value?true:false;
-
- //Check if fullscreen changed.
- if(fullscreen==getSettings()->getBoolValue("fullscreen")){
- //We disable the restart message flag.
- restartFlag=false;
- }else{
- //We set the restart message flag.
- restartFlag=true;
- }
-
- }else if(name=="chkInternet"){
- internet=obj->value?true:false;
- }else if(name=="chkProxy"){
- useProxy=obj->value?true:false;
- }else if(name=="chkFade"){
- fade=obj->value?true:false;
- }else if(name=="chkQuickRec"){
- quickrec=obj->value?true:false;
- }
- }
- if(name=="lstTheme"){
- if(theme!=NULL && theme->value>=0 && theme->value<(int)theme->item.size()){
- //Convert the themeName to contain %DATA%, etc...
- themeName=compressFileName(theme->item[theme->value].first);
- }
- }else if(name=="txtProxy"){
- internetProxy=obj->caption;
-
- //Check if the internetProxy field is empty.
- useProxy=!internetProxy.empty();
- }else if(name=="sldMusic"){
- getMusicManager()->setEnabled(musicSlider->value>0);
- getMusicManager()->setVolume(musicSlider->value);
- }else if(name=="sldSound"){
- Mix_Volume(-1,soundSlider->value);
- if(lastJumpSound==0){
- getSoundManager()->playSound("jump");
- lastJumpSound=15;
- }
- }
- if(name=="lstTabs"){
- if(obj->value==0){
- tabGeneral->visible=true;
- tabControls->visible=false;
- }else{
- tabGeneral->visible=false;
- tabControls->visible=true;
- }
- }
-}
-
-void Options::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
- //Get the x and y location of the mouse.
- int x,y;
- SDL_GetMouseState(&x,&y);
-
- //Check icon.
- if(event.type==SDL_MOUSEMOTION || event.type==SDL_MOUSEBUTTONDOWN){
- if(y>=SCREEN_HEIGHT-56&&y<SCREEN_HEIGHT-8&&x>=SCREEN_WIDTH-56)
- clearIconHower=true;
- else
- clearIconHower=false;
- }
-
- if(event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT && clearIconHower){
- if(msgBox(imageManager,renderer,_("Do you really want to reset level progress?"),MsgBoxYesNo,_("Warning"))==MsgBoxYes){
- //We delete the progress folder.
-#ifdef WIN32
- removeDirectory((getUserPath()+"progress").c_str());
- createDirectory((getUserPath()+"progress").c_str());
-#else
- removeDirectory((getUserPath(USER_DATA)+"/progress").c_str());
- createDirectory((getUserPath(USER_DATA)+"/progress").c_str());
-#endif
- //Reset statistics.
- statsMgr.reloadCompletedLevelsAndAchievements();
- }
- }
-
- //Check if we need to quit, if so enter the exit state.
- if(event.type==SDL_QUIT){
- setNextState(STATE_EXIT);
- }
-
- //Check if the escape button is pressed, if so go back to the main menu.
- if (inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE) && (tabControls == NULL || !tabControls->visible)) {
- setNextState(STATE_MENU);
- }
-}
-
-void Options::logic(ImageManager&, SDL_Renderer&){
- //Increase the lastJumpSound variable if needed.
- if(lastJumpSound!=0){
- lastJumpSound--;
- }
-}
-
-void Options::render(ImageManager&, SDL_Renderer& renderer){
- //Draw background.
- objThemes.getBackground(true)->draw(renderer);
- objThemes.getBackground(true)->updateAnimation();
-
- //Now render the title.
- drawTitleTexture(SCREEN_WIDTH, *title, renderer);
-
- //Check if an icon is selected/highlighted and draw tooltip
- if(clearIconHower){
- const SDL_Rect texSize = rectFromTexture(*clearTooltip);
- drawGUIBox(-2,SCREEN_HEIGHT-texSize.h-2,texSize.w+4,texSize.h+4,renderer,0xFFFFFFFF);
- applyTexture(0,SCREEN_HEIGHT-texSize.h,clearTooltip,renderer);
- }
-
- //Draw icon.
- applyTexture(SCREEN_WIDTH-48,SCREEN_HEIGHT-48,*clearIcon,renderer);
-
- //NOTE: The rendering of the GUI is done in Main.
-}
-
-void Options::resize(ImageManager& imageManager, SDL_Renderer& renderer){
- //Recreate the gui to fit the new resolution.
- createGUI(imageManager,renderer);
-}
-
-/////////////////////////CREDITS_MENU//////////////////////////////////
-
-Credits::Credits(ImageManager& imageManager,SDL_Renderer& renderer){
- //Render the title.
- title=textureFromText(renderer, *fontTitle,_("Credits"),objThemes.getTextColor(false));
-
- //Vector that will hold every line of the credits.
- vector<string> credits;
-
- //Open the AUTHORS file and read every line.
- {
- ifstream fin((getDataPath()+"/../AUTHORS").c_str());
- if(!fin.is_open()) {
- cerr<<"ERROR: Unable to open the AUTHORS file."<<endl;
- credits.push_back("ERROR: Unable to open the AUTHORS file.");
- credits.push_back("");
- }
-
- //Loop the lines of the file.
- string line;
- while(getline(fin,line)){
- credits.push_back(line);
- }
- }
-
- //Enter a new line between the two files.
- credits.push_back("");
-
- //Open the Credits.text file and read every line.
- {
- ifstream fin((getDataPath()+"/Credits.txt").c_str());
- if(!fin.is_open()) {
- cerr<<"ERROR: Unable to open the Credits.txt file."<<endl;
- credits.push_back("ERROR: Unable to open the Credits.txt file.");
- credits.push_back("");
- }
-
- //Loop the lines of the file.
- string line;
- while(getline(fin,line)){
- credits.push_back(line);
-
- //NOTE: Some sections point to other credits files.
- if(line=="music/") {
- vector<string> musicCredits=getMusicManager()->createCredits();
- credits.insert(credits.end(),musicCredits.begin(),musicCredits.end());
- }
- }
- }
-
- //Create the root element of the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
- GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
-
- //Create back button.
- backButton=new GUIButton(imageManager,renderer,SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,36,_("Back"),0,true,true,GUIGravityCenter);
- backButton->name="cmdBack";
- backButton->eventCallback=this;
- GUIObjectRoot->addChild(backButton);
-
- //Create a text area for credits.
- textArea=new GUITextArea(imageManager,renderer,SCREEN_WIDTH*0.05,114,SCREEN_WIDTH*0.9,SCREEN_HEIGHT-200);
- textArea->setFont(fontMono);
- textArea->setStringArray(renderer, std::move(credits));
- textArea->editable=false;
- textArea->extractHyperlinks();
- GUIObjectRoot->addChild(textArea);
-}
-
-Credits::~Credits(){
- //Delete the GUI.
- if(GUIObjectRoot){
- delete GUIObjectRoot;
- GUIObjectRoot=NULL;
- }
-}
-
-void Credits::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
- //Check what type of event it was.
- if(eventType==GUIEventClick){
- if(name=="cmdBack"){
- //Goto the main menu.
- setNextState(STATE_MENU);
- }
- }
-}
-
-void Credits::handleEvents(ImageManager&, SDL_Renderer&){
- //Check if we need to quit, if so enter the exit state.
- if(event.type==SDL_QUIT){
- setNextState(STATE_EXIT);
- }
-
- //Check movement
- if (inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(20, 0);
- } else if (inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(-20, 0);
- } else if (inputMgr.isKeyDownEvent(INPUTMGR_UP)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(0, -1);
- } else if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN)){
- isKeyboardOnly = true;
- textArea->scrollScrollbar(0, 1);
- }
-
- //Check if the escape button is pressed, if so go back to the main menu.
- if(inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
- setNextState(STATE_MENU);
- }
-}
-
-void Credits::logic(ImageManager&, SDL_Renderer&){}
-
-void Credits::render(ImageManager&,SDL_Renderer &renderer){
- //Draw background.
- objThemes.getBackground(true)->draw(renderer);
- objThemes.getBackground(true)->updateAnimation();
-
- //Now render the title.
- drawTitleTexture(SCREEN_WIDTH, *title, renderer);
-
- //NOTE: The rendering of the GUI is done in Main.
-}
-
-void Credits::resize(ImageManager&, SDL_Renderer&){
- //Resize and position widgets.
- GUIObjectRoot->width=SCREEN_WIDTH;
- GUIObjectRoot->height=SCREEN_HEIGHT;
-
- backButton->left=SCREEN_WIDTH/2;
- backButton->top=SCREEN_HEIGHT-60;
-
- textArea->left=SCREEN_WIDTH*0.05;
- textArea->width=SCREEN_WIDTH*0.9;
- textArea->height=SCREEN_HEIGHT-200;
- textArea->resize();
-}
diff --git a/src/TitleMenu.h b/src/TitleMenu.h
index 02a53d2..8efca4a 100644
--- a/src/TitleMenu.h
+++ b/src/TitleMenu.h
@@ -1,159 +1,67 @@
/*
* Copyright (C) 2011-2013 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TITLE_MENU_H
#define TITLE_MENU_H
#include <array>
#include <SDL.h>
#include "GameState.h"
-//Included for the Options menu.
#include "Render.h"
-#include "GUIObject.h"
-#include "GUIListBox.h"
-#include "GUISlider.h"
-#include "GUITextArea.h"
-#include "InputManager.h"
#include "ImageManager.h"
//The Main menu.
class Menu : public GameState{
private:
//The title of the main menu.
SharedTexture titleTexture;
//Array containg pointers the five main menu entries.
//The last two are the '>' and '<' characters.
std::array<TexturePtr, 7> entries;
//The icon and for the statistics menu.
SharedTexture statisticsIcon;
TexturePtr statisticsTooltip;
//The icon for the credits menu.
SharedTexture creditsIcon;
TexturePtr creditsTooltip;
//Integer used for animations.
int animation;
//Integer containing the highlighted/selected menu option.
int highlight;
public:
//Constructor.
Menu(ImageManager& imageManager, SDL_Renderer &renderer);
//Destructor.
~Menu();
//Inherited from GameState.
void handleEvents(ImageManager& imageManager, SDL_Renderer& renderer) override;
void logic(ImageManager&, SDL_Renderer&) override;
void render(ImageManager&, SDL_Renderer& renderer) override;
void resize(ImageManager&, SDL_Renderer&) override;
};
-//The Options menu.
-class Options : public GameState, private GUIEventCallback{
-private:
- //The title of the options menu.
- TexturePtr title;
-
- //Icon.
- SharedTexture clearIcon;
- bool clearIconHower;
- TexturePtr clearTooltip;
-
- //Slider used to set the music volume
- GUISlider* musicSlider;
- //Slider used to set the sound volume
- GUISlider* soundSlider;
-
- //Integer to keep track of the time passed since last playing the test sound.
- int lastJumpSound;
-
- //ListBox containing the themes the user can choose out.
- GUISingleLineListBox* theme;
-
- //Available languages
- GUISingleLineListBox* langs;
-
- //Resolution list
- GUISingleLineListBox* resolutions;
-
- //Containers for different tabs.
- GUIObject* tabGeneral;
- GUIObject* tabControls;
-
- //Keys.
- InputManagerKeyCode tmpKeys[INPUTMGR_MAX], tmpAlternativeKeys[INPUTMGR_MAX];
-
- //GUI events are handled here.
- //name: The name of the element that invoked the event.
- //obj: Pointer to the object that invoked the event.
- //eventType: Integer containing the type of event.
- void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
-
-public:
- //Constructor.
- Options(ImageManager& imageManager,SDL_Renderer& renderer);
- //Destructor.
- ~Options();
-
- //Method that will create the GUI for the options menu.
- void createGUI(ImageManager &imageManager, SDL_Renderer &renderer);
-
- //Inherited from GameState.
- void handleEvents(ImageManager& imageManager, SDL_Renderer& renderer) override;
- void logic(ImageManager&, SDL_Renderer&) override;
- void render(ImageManager&, SDL_Renderer& renderer) override;
- void resize(ImageManager &imageManager, SDL_Renderer&renderer) override;
-};
-
-//The Credits menu.
-class Credits : public GameState, private GUIEventCallback{
-private:
- //The title of the credits menu.
- TexturePtr title;
-
- //Widgets.
- GUITextArea* textArea;
- GUIObject* backButton;
-
- //GUI events are handled here.
- //name: The name of the element that invoked the event.
- //obj: Pointer to the object that invoked the event.
- //eventType: Integer containing the type of event.
- void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
-
-public:
- //Constructor.
- Credits(ImageManager& imageManager, SDL_Renderer &renderer);
- //Destructor.
- ~Credits();
-
- //Inherited from GameState.
- void handleEvents(ImageManager&, SDL_Renderer&) override;
- void logic(ImageManager&, SDL_Renderer&) override;
- void render(ImageManager&, SDL_Renderer& renderer) override;
- void resize(ImageManager &imageManager, SDL_Renderer& renderer) override;
-};
-
#endif

File Metadata

Mime Type
text/x-diff
Expires
Fri, May 15, 10:14 PM (2 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
63980
Default Alt Text
(157 KB)

Event Timeline