Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
42 KB
Referenced Files
None
Subscribers
None
diff --git a/src/LevelInfoRender.cpp b/src/LevelInfoRender.cpp
index bc6b4c5..39ac1cb 100644
--- a/src/LevelInfoRender.cpp
+++ b/src/LevelInfoRender.cpp
@@ -1,69 +1,69 @@
#include "Functions.h"
#include "LevelInfoRender.h"
LevelInfoRender::LevelInfoRender(ImageManager &imageManager, SDL_Renderer &renderer, const std::string& dataPath, TTF_Font &font, SDL_Color textColor)
{
playButton=imageManager.loadTexture(dataPath+"gfx/playbutton.png",renderer);
timeIcon=imageManager.loadTexture(dataPath+"gfx/time.png",renderer);
recordingsIcon=imageManager.loadTexture(dataPath+"gfx/recordings.png",renderer);
//Skip doing this here as it will be called LevelPlaySelect::refresh which is called by it's constructor anyhow.
//resetText(renderer, font, textColor);
}
void LevelInfoRender::resetText(SDL_Renderer &renderer, TTF_Font &font, SDL_Color textColor) {
auto tex = [&](const char* text){
return textureFromText(renderer,font,text,textColor);
};
levelDescription=tex(_("Choose a level"));
timeText=tex(_("Time:"));
recordingsText=tex(_("Recordings:"));
levelTime=tex("- / -");
levelRecs=tex("- / -");
}
void LevelInfoRender::update(SDL_Renderer &renderer, TTF_Font &font, SDL_Color textColor,
const std::string &description, const std::string& time, const std::string& recordings) {
auto tex = [&](const std::string& text){
return textureFromText(renderer,font,text.c_str(),textColor);
};
if(description.empty()) {
levelDescription=nullptr;
} else {
levelDescription=tex(description);
}
levelTime=tex(time);
levelRecs=tex(recordings);
}
void LevelInfoRender::render(SDL_Renderer &renderer) {
//Avoid crashing if this is somehow not initialized.
if(!timeText) {
return;
}
int w=0,h=0;
SDL_GetRendererOutputSize(&renderer,&w,&h);
if(levelDescription) {
applyTexture(100,h-130+(50-textureHeight(*levelDescription))/2,levelDescription, renderer);
}
//Draw time the icon.
- applyTexture(w-405,h-130+3,timeIcon,renderer);
+ applyTexture(w-405,h-130+6,timeIcon,renderer);
//Now draw the text (title).
- applyTexture(w-380,h-130+3,timeText,renderer);
+ applyTexture(w-380,h-130+6,timeText,renderer);
//Now draw the second text (value).
- applyTexture(w-textureWidth(*levelTime)-80,h-130+3,levelTime,renderer);
+ applyTexture(w-textureWidth(*levelTime)-80,h-130+6,levelTime,renderer);
//Draw the icon.
- applyTexture(w-405,h-98+(6)/2,recordingsIcon,renderer);
+ applyTexture(w-405,h-98+6,recordingsIcon,renderer);
//Now draw the text (title).
- applyTexture(w-380,h-98+(32-textureHeight(*recordingsText))/2,
- recordingsText,renderer);
- //Now draw the second text (value).
- applyTexture(w-textureWidth(*levelRecs)-80,h-98+(30-textureHeight(*levelRecs))/2,levelRecs,renderer);
+ applyTexture(w-380,h-98+6,recordingsText,renderer);
+
+ //Now draw the second text (value).
+ applyTexture(w-textureWidth(*levelRecs)-80,h-98+6,levelRecs,renderer);
}
diff --git a/src/LevelPlaySelect.cpp b/src/LevelPlaySelect.cpp
index 67df690..95052cf 100644
--- a/src/LevelPlaySelect.cpp
+++ b/src/LevelPlaySelect.cpp
@@ -1,425 +1,472 @@
/*
* 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 "LevelPlaySelect.h"
#include "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "LevelSelect.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#include "InputManager.h"
#include "ThemeManager.h"
#include "Game.h"
#include <stdio.h>
#include <string>
#include <sstream>
#include <iostream>
/////////////////////LEVEL SELECT/////////////////////
LevelPlaySelect::LevelPlaySelect(ImageManager& imageManager, SDL_Renderer& renderer)
:LevelSelect(imageManager,renderer,_("Select Level")),
levelInfoRender(imageManager,renderer,getDataPath(),*fontText,objThemes.getTextColor(false)){
//Load the play button if needed.
playButtonImage=imageManager.loadTexture(getDataPath()+"gfx/playbutton.png", renderer);
//Create the gui.
createGUI(imageManager,renderer, true);
//Show level list
refresh(imageManager,renderer);
}
LevelPlaySelect::~LevelPlaySelect(){
play=NULL;
//Clear the selected level.
if(selectedNumber!=NULL){
delete selectedNumber;
selectedNumber=NULL;
}
}
void LevelPlaySelect::createGUI(ImageManager& imageManager,SDL_Renderer &renderer, bool initial){
//Create the play button.
if(initial){
play=new GUIButton(imageManager,renderer,SCREEN_WIDTH-240,SCREEN_HEIGHT-60,240,32,_("Play"));
}else{
play->left=SCREEN_WIDTH-240;
play->top=SCREEN_HEIGHT-60;
}
play->name="cmdPlay";
play->eventCallback=this;
play->enabled=false;
if(initial)
GUIObjectRoot->addChild(play);
}
void LevelPlaySelect::refresh(ImageManager& imageManager, SDL_Renderer& renderer, bool /*change*/){
const int m=levels->getLevelCount();
numbers.clear();
levelInfoRender.resetText(renderer, *fontText, objThemes.getTextColor(false));
//Create the non selected number.
if (selectedNumber == NULL){
selectedNumber = new Number(imageManager, renderer);
}
SDL_Rect box={40,SCREEN_HEIGHT-130,50,50};
selectedNumber->init(renderer," ",box);
selectedNumber->setLocked(true);
selectedNumber->setMedal(0);
bestTimeFilePath.clear();
bestRecordingFilePath.clear();
//Disable the play button.
play->enabled=false;
for(int n=0; n<m; n++){
numbers.emplace_back(imageManager, renderer);
}
for(int n=0; n<m; n++){
SDL_Rect box={(n%LEVELS_PER_ROW)*64+static_cast<int>(SCREEN_WIDTH*0.2)/2,(n/LEVELS_PER_ROW)*64+184,0,0};
numbers[n].init(renderer,n,box);
numbers[n].setLocked(levels->getLocked(n));
int medal=levels->getLevel(n)->won;
if(medal){
if(levels->getLevel(n)->targetTime<0 || levels->getLevel(n)->time<=levels->getLevel(n)->targetTime)
medal++;
if(levels->getLevel(n)->targetRecordings<0 || levels->getLevel(n)->recordings<=levels->getLevel(n)->targetRecordings)
medal++;
}
numbers[n].setMedal(medal);
}
if(m>LEVELS_DISPLAYED_IN_SCREEN){
levelScrollBar->maxValue=(m-LEVELS_DISPLAYED_IN_SCREEN+(LEVELS_PER_ROW-1))/LEVELS_PER_ROW;
levelScrollBar->visible=true;
}else{
levelScrollBar->maxValue=0;
levelScrollBar->visible=false;
}
if(!levels->levelpackDescription.empty())
levelpackDescription->caption=_CC(levels->getDictionaryManager(),levels->levelpackDescription);
else
levelpackDescription->caption="";
}
void LevelPlaySelect::selectNumber(ImageManager& imageManager, SDL_Renderer& renderer, unsigned int number,bool selected){
if (selected) {
if (number >= 0 && number < levels->getLevelCount()) {
levels->setCurrentLevel(number);
setNextState(STATE_GAME);
}
}else{
displayLevelInfo(imageManager, renderer,number);
}
}
void LevelPlaySelect::checkMouse(ImageManager &imageManager, SDL_Renderer &renderer){
int x,y;
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
//Check if we should replay the record.
if(selectedNumber!=NULL){
SDL_Rect mouse={x,y,0,0};
if(!bestTimeFilePath.empty()){
SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-130,372,32};
if(checkCollision(box,mouse)){
Game::recordFile=bestTimeFilePath;
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_GAME);
return;
}
}
if(!bestRecordingFilePath.empty()){
SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-98,372,32};
if(checkCollision(box,mouse)){
Game::recordFile=bestRecordingFilePath;
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_GAME);
return;
}
}
}
//Call the base method from the super class.
LevelSelect::checkMouse(imageManager, renderer);
}
void LevelPlaySelect::displayLevelInfo(ImageManager& imageManager, SDL_Renderer& renderer, int number){
//Update currently selected level
if(selectedNumber==NULL){
selectedNumber=new Number(imageManager, renderer);
}
SDL_Rect box={40,SCREEN_HEIGHT-130,50,50};
if (number >= 0 && number < levels->getLevelCount()) {
selectedNumber->init(renderer, number, box);
selectedNumber->setLocked(false);
//Show level medal
int medal = levels->getLevel(number)->won;
int time = levels->getLevel(number)->time;
int targetTime = levels->getLevel(number)->targetTime;
int recordings = levels->getLevel(number)->recordings;
int targetRecordings = levels->getLevel(number)->targetRecordings;
if (medal){
if (targetTime < 0){
medal = -1;
} else{
if (targetTime < 0 || time <= targetTime)
medal++;
if (targetRecordings < 0 || recordings <= targetRecordings)
medal++;
}
}
selectedNumber->setMedal(medal);
std::string levelTime;
std::string levelRecs;
//Show best time and recordings
if (medal){
char s[64];
if (time > 0)
if (targetTime>0)
sprintf(s, "%-.2fs / %-.2fs", time / 40.0f, targetTime / 40.0f);
else
sprintf(s, "%-.2fs / -", time / 40.0f);
else
s[0] = '\0';
levelTime = s;
if (recordings >= 0)
if (targetRecordings >= 0)
sprintf(s, "%5d / %d", recordings, targetRecordings);
else
sprintf(s, "%5d / -", recordings);
else
s[0] = '\0';
levelRecs = s;
} else{
levelTime = "- / -";
levelRecs = "- / -";
}
//Show the play button.
play->enabled = true;
//Check if there is auto record file
levels->getLevelAutoSaveRecordPath(number, bestTimeFilePath, bestRecordingFilePath, false);
if (!bestTimeFilePath.empty()){
FILE *f;
f = fopen(bestTimeFilePath.c_str(), "rb");
if (f == NULL){
bestTimeFilePath.clear();
} else{
fclose(f);
}
}
if (!bestRecordingFilePath.empty()){
FILE *f;
f = fopen(bestRecordingFilePath.c_str(), "rb");
if (f == NULL){
bestRecordingFilePath.clear();
} else{
fclose(f);
}
}
//Show level description
const std::string& levelDescription = levels->getLevelName(number);
levelInfoRender.update(renderer, *fontText, objThemes.getTextColor(false),
levelDescription, levelTime, levelRecs);
} else {
levelInfoRender.resetText(renderer, *fontText, objThemes.getTextColor(false));
selectedNumber->init(renderer, " ", box);
selectedNumber->setLocked(true);
selectedNumber->setMedal(0);
bestTimeFilePath.clear();
bestRecordingFilePath.clear();
//Disable the play button.
play->enabled = false;
}
}
+void LevelPlaySelect::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
+ //Call handleEvents() of base class.
+ LevelSelect::handleEvents(imageManager, renderer);
+
+ if (section == 3) {
+ //Check focus movement
+ if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN) || inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
+ isKeyboardOnly = true;
+ section2++;
+ } else if (inputMgr.isKeyDownEvent(INPUTMGR_UP) || inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
+ isKeyboardOnly = true;
+ section2--;
+ }
+ if (section2 > 3) section2 = 1;
+ else if (section2 < 1) section2 = 3;
+
+ //Check if enter is pressed
+ if (inputMgr.isKeyUpEvent(INPUTMGR_SELECT) && selectedNumber) {
+ int n = selectedNumber->getNumber();
+ if (n >= 0) {
+ switch (section2) {
+ case 1:
+ if (!bestTimeFilePath.empty()) {
+ Game::recordFile = bestTimeFilePath;
+ levels->setCurrentLevel(n);
+ setNextState(STATE_GAME);
+ }
+ break;
+ case 2:
+ if (!bestRecordingFilePath.empty()) {
+ Game::recordFile = bestRecordingFilePath;
+ levels->setCurrentLevel(n);
+ setNextState(STATE_GAME);
+ }
+ break;
+ case 3:
+ selectNumber(imageManager, renderer, n, true);
+ break;
+ }
+ }
+ }
+ }
+}
+
void LevelPlaySelect::render(ImageManager& imageManager, SDL_Renderer &renderer){
//First let the levelselect render.
LevelSelect::render(imageManager,renderer);
int x,y,dy=0;
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
//Show currently selected level (if any)
if(selectedNumber!=NULL){
selectedNumber->show(renderer, 0);
- levelInfoRender.render(renderer);
-
//Only show the replay button if the level is completed (won).
if(selectedNumber->getNumber()>=0 && selectedNumber->getNumber()<levels->getLevelCount()) {
if(levels->getLevel(selectedNumber->getNumber())->won){
if(!bestTimeFilePath.empty()){
SDL_Rect r={0,0,32,32};
const SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-130,372,32};
- if(checkCollision(box,mouse)){
- r.x=32;
- SDL_SetRenderDrawColor(&renderer, 0xFF,0xCC,0xCC,0xCC);
- SDL_RenderDrawRect(&renderer, &box);
+ if (isKeyboardOnly ? (section == 3 && section2 == 1) : checkCollision(box, mouse)){
+ r.x = 32;
+ drawGUIBox(box.x, box.y, box.w, box.h, renderer, 0xFFFFFF40);
}
const SDL_Rect dstRect = {SCREEN_WIDTH-80,SCREEN_HEIGHT-130,r.w,r.h};
SDL_RenderCopy(&renderer,playButtonImage.get(),&r, &dstRect);
}
if(!bestRecordingFilePath.empty()){
SDL_Rect r={0,0,32,32};
const SDL_Rect box={SCREEN_WIDTH-420,SCREEN_HEIGHT-98,372,32};
- if(checkCollision(box,mouse)){
- r.x=32;
- SDL_SetRenderDrawColor(&renderer, 0xFF,0xCC,0xCC,0xCC);
- SDL_RenderDrawRect(&renderer, &box);
+ if (isKeyboardOnly ? (section == 3 && section2 == 2) : checkCollision(box, mouse)){
+ r.x = 32;
+ drawGUIBox(box.x, box.y, box.w, box.h, renderer, 0xFFFFFF40);
}
const SDL_Rect dstRect = {SCREEN_WIDTH-80,SCREEN_HEIGHT-98,r.w,r.h};
SDL_RenderCopy(&renderer,playButtonImage.get(),&r, &dstRect);
}
}
}
+
+ levelInfoRender.render(renderer);
+ }
+
+ //Draw highlight for play button.
+ if (isKeyboardOnly && section == 3 && section2 == 3) {
+ drawGUIBox(SCREEN_WIDTH - 200, SCREEN_HEIGHT - 64, 160, 40, renderer, 0xFFFFFF40);
}
}
void LevelPlaySelect::renderTooltip(SDL_Renderer &renderer, unsigned int number, int dy){
if (!toolTip.name || toolTip.number != number) {
const int SLEN = 64;
char s[SLEN];
//Render the name of the level.
toolTip.name = textureFromText(renderer, *fontText, _CC(levels->getDictionaryManager(), levels->getLevelName(number)), objThemes.getTextColor(true));
toolTip.time=nullptr;
toolTip.recordings=nullptr;
toolTip.number=number;
//The time it took.
if(levels->getLevel(number)->time>0){
SDL_snprintf(s,SLEN,"%-.2fs",levels->getLevel(number)->time/40.0f);
toolTip.time = textureFromText(renderer, *fontText, s, objThemes.getTextColor(true));
}
//The number of recordings it took.
if(levels->getLevel(number)->recordings>=0){
SDL_snprintf(s,SLEN,"%d",levels->getLevel(number)->recordings);
toolTip.recordings = textureFromText(renderer, *fontText, s, objThemes.getTextColor(true));
}
}
const SDL_Rect nameSize = rectFromTexture(*toolTip.name);
//Now draw a square the size of the three texts combined.
SDL_Rect r=numbers[number].box;
r.y-=dy*64;
if(toolTip.time && toolTip.recordings){
const int recW = textureWidth(*toolTip.recordings);
const int timeW = textureWidth(*toolTip.time);
r.w=(nameSize.w)>(25+timeW+40+recW)?(nameSize.w):(25+timeW+40+recW);
r.h=nameSize.h+5+20;
}else{
r.w=nameSize.w;
r.h=nameSize.h;
}
//Make sure the tooltip doesn't go outside the window.
if(r.y>SCREEN_HEIGHT-200){
r.y-=nameSize.h+4;
}else{
r.y+=numbers[number].box.h+2;
}
if(r.x+r.w>SCREEN_WIDTH-50)
r.x=SCREEN_WIDTH-50-r.w;
//Draw a rectange
Uint32 color=0xFFFFFFFF;
drawGUIBox(r.x-5,r.y-5,r.w+10,r.h+10,renderer,color);
//Calc the position to draw.
SDL_Rect r2=r;
//Now we render the name if the surface isn't null.
if(toolTip.name){
//Draw the name.
applyTexture(r2.x, r2.y, toolTip.name, renderer);
}
//Increase the height to leave a gap between name and stats.
r2.y+=30;
if(toolTip.time){
//Now draw the time.
applyTexture(r2.x,r2.y,levelInfoRender.timeIcon,renderer);
r2.x+=25;
applyTexture(r2.x, r2.y, toolTip.time, renderer);
r2.x+=textureWidth(*toolTip.time)+15;
}
if(toolTip.recordings){
//Now draw the recordings.
applyTexture(r2.x,r2.y,levelInfoRender.recordingsIcon,renderer);
r2.x+=25;
applyTexture(r2.x, r2.y, toolTip.recordings, renderer);
}
}
void LevelPlaySelect::resize(ImageManager &imageManager, SDL_Renderer &renderer){
//Let the LevelSelect do his stuff.
LevelSelect::resize(imageManager, renderer);
//Now create our gui again.
createGUI(imageManager,renderer, false);
}
void LevelPlaySelect::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
//Let the level select handle his GUI events.
LevelSelect::GUIEventCallback_OnEvent(imageManager,renderer,name,obj,eventType);
//Check for the play button.
if(name=="cmdPlay"){
if(selectedNumber!=NULL){
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_GAME);
}
}
}
diff --git a/src/LevelPlaySelect.h b/src/LevelPlaySelect.h
index b03314e..3a2f438 100644
--- a/src/LevelPlaySelect.h
+++ b/src/LevelPlaySelect.h
@@ -1,80 +1,81 @@
/*
* Copyright (C) 2011-2012 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 LEVELPLAYSELECT_H
#define LEVELPLAYSELECT_H
#include "GameState.h"
#include "LevelSelect.h"
#include "LevelInfoRender.h"
#include "GameObjects.h"
#include "Player.h"
#include "GUIObject.h"
#include <vector>
#include <string>
//This is the LevelSelect state, here you can select levelpacks and levels.
class LevelPlaySelect : public LevelSelect{
private:
//Pointer to the play button, it is only shown when a level is selected.
GUIObject* play;
//Image of a play icon used as button to start replays.
SharedTexture playButtonImage;
//Textures to display level info.
LevelInfoRender levelInfoRender;
std::string bestTimeFilePath;
std::string bestRecordingFilePath;
//Method that will create the GUI elements.
//initial: Boolean if it is the first time the gui is created.
void createGUI(ImageManager& imageManager, SDL_Renderer& renderer, bool initial);
//display level info.
void displayLevelInfo(ImageManager &imageManager, SDL_Renderer &renderer, int number);
//Check where and if the mouse clicked on a number.
//If so it will start the level.
void checkMouse(ImageManager &imageManager, SDL_Renderer &renderer) override;
public:
//Constructor.
LevelPlaySelect(ImageManager &imageManager, SDL_Renderer &renderer);
//Destructor.
~LevelPlaySelect();
//Inherited from LevelSelect.
- void refresh(ImageManager &imageManager, SDL_Renderer &renderer, bool change=true) override;
+ void handleEvents(ImageManager& imageManager, SDL_Renderer& renderer) override;
+ void refresh(ImageManager &imageManager, SDL_Renderer &renderer, bool change = true) override;
void selectNumber(ImageManager &imageManager, SDL_Renderer &renderer, unsigned int number, bool selected) override;
//Inherited from GameState.
void render(ImageManager&imageManager, SDL_Renderer& renderer) override;
//Inherited from GameState.
void resize(ImageManager &imageManager, SDL_Renderer& renderer) override;
//Inherited from LevelSelect.
void renderTooltip(SDL_Renderer& renderer,unsigned int number,int dy) override;
//GUI events will be handled here.
void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType);
};
#endif
diff --git a/src/LevelSelect.cpp b/src/LevelSelect.cpp
index 22b5c33..ca4af9e 100644
--- a/src/LevelSelect.cpp
+++ b/src/LevelSelect.cpp
@@ -1,436 +1,450 @@
/*
* 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 "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "LevelSelect.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#include "InputManager.h"
#include <stdio.h>
#include <string>
#include <sstream>
#include <iostream>
#include "libs/tinyformat/tinyformat.h"
using namespace std;
////////////////////NUMBER////////////////////////
Number::Number(ImageManager& imageManager, SDL_Renderer& renderer){
image=NULL;
number=0;
medal=0;
selected=false;
locked=false;
//Set the default dimensions.
box.x=0;
box.y=0;
box.h=50;
box.w=50;
//Load the medals image.
medals=imageManager.loadTexture(getDataPath()+"gfx/medals.png", renderer);
//To make sure it can be added to a vector, stop here rather than generate a massive error.
static_assert(std::is_move_constructible<Number>::value, "Not move constructable!");
}
void Number::init(SDL_Renderer& renderer,int number,SDL_Rect box){
//First set the number and update our status.
this->number=number;
//Write our text, number+1 since the counting doens't start with 0, but with 1.
std::stringstream text;
number++;
text<<number;
//Create the text image.
//Also check which font to use, if the number is higher than 100 use the small font.
image = textureFromText(renderer,*fontGUI,text.str().c_str(),objThemes.getTextColor(true));
//Set the new location of the number.
this->box.x=box.x;
this->box.y=box.y;
//Load background blocks.
objThemes.getBlock(TYPE_BLOCK,true)->createInstance(&block);
block.changeState("unlocked");
objThemes.getBlock(TYPE_SHADOW_BLOCK,true)->createInstance(&blockLocked);
blockLocked.changeState("locked");
}
void Number::init(SDL_Renderer& renderer,std::string text,SDL_Rect box,int number_){
//First set the number and update our status.
this->number=number_;
//Create the text image.
image = textureFromText(renderer,*fontGUI,text.c_str(),objThemes.getTextColor(true));
//Set the new location of the number.
this->box.x=box.x;
this->box.y=box.y;
//Load background blocks.
objThemes.getBlock(TYPE_BLOCK,true)->createInstance(&block);
block.changeState("unlocked");
objThemes.getBlock(TYPE_SHADOW_BLOCK,true)->createInstance(&blockLocked);
blockLocked.changeState("locked");
}
void Number::show(SDL_Renderer& renderer, int dy){
//First draw the background, also apply the yOffset(dy).
if(!locked)
block.draw(renderer,box.x,box.y-dy);
else
blockLocked.draw(renderer,box.x,box.y-dy);
//Now draw the text image over the background.
//We draw it centered inside the box.
applyTexture(box.x+25-(textureWidth(*image)/2),box.y-dy,image,renderer);
//Draw the selection mark.
if(selected){
drawGUIBox(box.x,box.y-dy,50,50,renderer,0xFFFFFF23);
}
//Draw the medal.
if(medal>0&&medals){
const SDL_Rect srcRect={(medal-1)*30,0,30,30};
const SDL_Rect dstRect={box.x+30,(box.y+30)-dy,30,30};
SDL_RenderCopy(&renderer,medals.get(),&srcRect,&dstRect);
}
}
void Number::setLocked(bool locked){
this->locked=locked;
}
void Number::setMedal(int medal){
this->medal=medal;
}
/////////////////////LEVEL SELECT/////////////////////
LevelSelect::LevelSelect(ImageManager& imageManager,SDL_Renderer& renderer, const char* titleText, LevelPackManager::LevelPackLists packType){
//clear the selected level
selectedNumber=NULL;
//Calculate the LEVELS_PER_ROW and LEVEL_ROWS if they aren't calculated already.
calcRows();
//Render the title.
title=textureFromText(renderer,*fontTitle,titleText,objThemes.getTextColor(false));
//create GUI (test only)
GUIObject* obj;
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
GUIObjectRoot=new GUIObject(imageManager,renderer,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//the level select scroll bar
levelScrollBar=new GUIScrollBar(imageManager,renderer,SCREEN_WIDTH*0.9,184,16,SCREEN_HEIGHT-344,ScrollBarVertical,0,0,0,1,4,true,false);
GUIObjectRoot->addChild(levelScrollBar);
//level pack description
levelpackDescription=new GUILabel(imageManager,renderer,0,140,SCREEN_WIDTH,32,"",0,true,true,GUIGravityCenter);
GUIObjectRoot->addChild(levelpackDescription);
levelpacks=new GUISingleLineListBox(imageManager,renderer,(SCREEN_WIDTH-500)/2,104,500,32);
levelpacks->name="cmdLvlPack";
levelpacks->eventCallback=this;
vector<pair<string,string> > v=getLevelPackManager()->enumLevelPacks(packType);
levelpacks->addItems(v);
levelpacks->value=0;
//Check if we can find the lastlevelpack.
for(vector<pair<string,string> >::iterator i=v.begin(); i!=v.end(); ++i){
if(i->first==getSettings()->getValue("lastlevelpack")){
levelpacks->value=i-v.begin();
}
}
//Load the progress.
levels=getLevelPackManager()->getLevelPack(v[levelpacks->value].first);
levels->loadProgress();
//And add the levelpack single line listbox to the GUIObjectRoot.
GUIObjectRoot->addChild(levelpacks);
obj=new GUIButton(imageManager,renderer,20,20,-1,32,_("Back"));
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->addChild(obj);
section=1;
+ section2 = 1;
}
LevelSelect::~LevelSelect(){
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
levelScrollBar=NULL;
levelpackDescription=NULL;
selectedNumber=NULL;
}
void LevelSelect::calcRows(){
//Calculate the number of rows and the number of levels per row.
LEVELS_PER_ROW=(SCREEN_WIDTH*0.8)/64;
int LEVEL_ROWS=(SCREEN_HEIGHT-344)/64;
LEVELS_DISPLAYED_IN_SCREEN=LEVELS_PER_ROW*LEVEL_ROWS;
}
void LevelSelect::selectNumberKeyboard(ImageManager& imageManager, SDL_Renderer& renderer, int x,int y){
isKeyboardOnly = true;
if(section==2){
//Move selection
int realNumber=-1;
if(selectedNumber)
realNumber=selectedNumber->getNumber()+x+(y*LEVELS_PER_ROW);
int delta = (x + y < 0) ? -1 : 1;
for (;;) {
//If selection is outside of the map grid, change section
if (realNumber<0 || realNumber>(int)numbers.size() - 1){
section = 1;
for (int i = 0; i < (int)numbers.size(); i++){
numbers[i].selected = false;
}
selectNumber(imageManager, renderer, -1, false);
break;
} else {
//If not, move selection
if (!numbers[realNumber].getLocked()){
for (int i = 0; i < (int)numbers.size(); i++){
numbers[i].selected = (i == realNumber);
}
selectNumber(imageManager, renderer, realNumber, false);
break;
}
}
realNumber += delta;
}
}else if(section==1){
if (x != 0) {
//Loop through levelpacks and update GUI
levelpacks->value += x;
if (levelpacks->value<0){
levelpacks->value = levelpacks->item.size() - 1;
} else if (levelpacks->value>(int)levelpacks->item.size() - 1){
levelpacks->value = 0;
}
GUIEventCallback_OnEvent(imageManager, renderer, "cmdLvlPack", static_cast<GUIObject*>(levelpacks), 0);
}
//If down is pressed, change section
if(y==1){
section=2;
- selectNumber(imageManager,renderer,0,false);
- numbers[0].selected=true;
+ if (!numbers.empty()) {
+ selectNumber(imageManager, renderer, 0, false);
+ numbers[0].selected = true;
+ }
}
- }else{
- section=clamp(section+y,0,2);
}
}
void LevelSelect::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
//Check for an SDL_QUIT event.
if(event.type==SDL_QUIT){
setNextState(STATE_EXIT);
}
//Check for a mouse click.
if(event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT){
checkMouse(imageManager, renderer);
}
//Check focus movement
if(inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
selectNumberKeyboard(imageManager, renderer, 1,0);
}else if(inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
selectNumberKeyboard(imageManager, renderer, -1,0);
}else if(inputMgr.isKeyDownEvent(INPUTMGR_UP)){
selectNumberKeyboard(imageManager, renderer, 0,-1);
}else if(inputMgr.isKeyDownEvent(INPUTMGR_DOWN)){
selectNumberKeyboard(imageManager, renderer, 0,1);
}
+
+ if (inputMgr.isKeyDownEvent(INPUTMGR_TAB)) {
+ isKeyboardOnly = true;
+
+ int mod = SDL_GetModState();
+
+ section += (mod & KMOD_SHIFT) ? -1 : 1;
+ if (section < 1) section = 3;
+ else if (section > 3) section = 1;
+
+ if (section == 2 && (selectedNumber == NULL || selectedNumber->getNumber() < 0) && !numbers.empty()) {
+ selectNumber(imageManager, renderer, 0, false);
+ numbers[0].selected = true;
+ }
+ }
//Check if enter is pressed
- if(section==2 && inputMgr.isKeyUpEvent(INPUTMGR_SELECT)){
- selectNumber(imageManager,renderer,selectedNumber->getNumber(),true);
+ if (section == 2 && inputMgr.isKeyUpEvent(INPUTMGR_SELECT) && selectedNumber) {
+ int n = selectedNumber->getNumber();
+ if (n >= 0) {
+ selectNumber(imageManager, renderer, n, true);
+ }
}
//Check if escape is pressed.
if(inputMgr.isKeyUpEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
//Check for scrolling down and up.
-// if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELDOWN && levelScrollBar){
- if(event.type==SDL_MOUSEWHEEL && levelScrollBar){
- if(levelScrollBar->value<levelScrollBar->maxValue) {
- //TODO - tweak the scroll amount
- levelScrollBar->value += event.wheel.y;
- if(levelScrollBar->value < 0) {
- levelScrollBar->value = 0;
- }
- }
+ if (event.type == SDL_MOUSEWHEEL && levelScrollBar){
+ //TODO - tweak the scroll amount
+ levelScrollBar->value += event.wheel.y > 0 ? -1 : 1;
+ if (levelScrollBar->value > levelScrollBar->maxValue) {
+ levelScrollBar->value = levelScrollBar->maxValue;
+ }
+ if (levelScrollBar->value < 0) {
+ levelScrollBar->value = 0;
+ }
}
-// return;
-// }else if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELUP && levelScrollBar){
-// if(levelScrollBar->value>0) levelScrollBar->value--;
-// return;
-// }
}
void LevelSelect::checkMouse(ImageManager &imageManager, SDL_Renderer &renderer){
int x,y,dy=0,m=numbers.size();
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
//Check if there's a scrollbar, if so get the value.
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
if(m>dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN)
m=dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN;
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
for(int n=dy*LEVELS_PER_ROW; n<m; n++){
if(!numbers[n].getLocked()){
if(checkCollision(mouse,numbers[n].box)==true){
if(numbers[n].selected){
selectNumber(imageManager, renderer, n,true);
}else{
//Select current level
for(int i=0;i<levels->getLevelCount();i++){
numbers[i].selected=(i==n);
}
selectNumber(imageManager, renderer,n,false);
}
section=2;
break;
}
}
}
}
void LevelSelect::logic(ImageManager&, SDL_Renderer&){}
void LevelSelect::render(ImageManager&, SDL_Renderer& renderer){
int x,y,dy=0,m=numbers.size();
int idx=-1;
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
if(m>dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN)
m=dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN;
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
//Draw background.
objThemes.getBackground(true)->draw(renderer);
objThemes.getBackground(true)->updateAnimation();
//Draw the title.
drawTitleTexture(SCREEN_WIDTH, *title, renderer);
//Draw highlight and do some calculations in keyboard-only mode.
int realNumber = -1;
if (isKeyboardOnly) {
if (section == 1) {
drawGUIBox((SCREEN_WIDTH - 508) / 2, 100, 508, 36, renderer, 0xFFFFFF40);
}
if (selectedNumber)
realNumber = selectedNumber->getNumber();
}
//Loop through the level blocks and draw them.
for(int n=dy*LEVELS_PER_ROW;n<m;n++){
numbers[n].show(renderer,dy*64);
if (!numbers[n].getLocked()) {
if (isKeyboardOnly) {
if (realNumber == n) idx = n;
} else {
if (checkCollision(mouse, numbers[n].box)) idx = n;
}
}
}
//Show the tool tip text.
if(idx>=0){
renderTooltip(renderer,idx,dy);
}
}
void LevelSelect::resize(ImageManager& imageManager,SDL_Renderer& renderer){
calcRows();
refresh(imageManager,renderer,false);
//NOTE: We don't need to recreate the listbox and the back button, only resize the list.
levelpacks->left=(SCREEN_WIDTH-500)/2;
levelpackDescription->width = SCREEN_WIDTH;
}
void LevelSelect::GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType){
if(name=="cmdLvlPack"){
getSettings()->setValue("lastlevelpack",static_cast<GUISingleLineListBox*>(obj)->item[obj->value].first);
}else if(name=="cmdBack"){
setNextState(STATE_MENU);
return;
}else{
return;
}
//new: reset the level list scroll bar
if(levelScrollBar)
levelScrollBar->value=0;
levels=getLevelPackManager()->getLevelPack(static_cast<GUISingleLineListBox*>(obj)->item[obj->value].first);
//Load the progress file.
levels->loadProgress();
//And refresh the numbers.
refresh(imageManager, renderer);
//invalidate the tooltip
toolTip.number = -1;
}
diff --git a/src/LevelSelect.h b/src/LevelSelect.h
index 1545cc6..f9359c1 100644
--- a/src/LevelSelect.h
+++ b/src/LevelSelect.h
@@ -1,172 +1,176 @@
/*
* Copyright (C) 2011-2012 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 LEVELSELECT_H
#define LEVELSELECT_H
#include "GameState.h"
#include "GameObjects.h"
#include "GUIObject.h"
#include "LevelPackManager.h"
#include <vector>
#include <string>
class GUIScrollBar;
class GUISingleLineListBox;
//Class that represents a level in the levelselect menu.
class Number{
private:
//The background image of the number.
ThemeBlockInstance block;
//The background image of the number when it's locked.
ThemeBlockInstance blockLocked;
//The (text) image of the number.
SharedTexture image;
//Image containing the three stars a player can earn.
SharedTexture medals;
//The number (or text).
int number;
//Integer containing the medal the player got.
//0 = none, 1 = bronze, 2 = silver, 3 = gold
int medal;
//Boolean if the number is locked or not.
bool locked;
public:
//The location and size of the number.
SDL_Rect box;
//If the Number is selected then we draw something indicates it.
bool selected;
//Constructor.
Number(ImageManager &imageManager, SDL_Renderer &renderer);
//Method used for initialising the number.
//number: The number.
//box: The location and size of the number.
void init(SDL_Renderer &renderer, int number, SDL_Rect box);
//Method used for initialising the number.
//text: The caption of the number.
//box: The location and size of the number.
void init(SDL_Renderer& renderer,std::string text,SDL_Rect box,int number_=-1);
//get current number.
inline int getNumber(){return number;}
//Method used to set the locked status of the number.
//locked: Boolean if it should be locked or not.
void setLocked(bool locked=true);
//Method used to retrieve the locked status of the number.
//Returns: True if the number is locked.
inline bool getLocked(){return locked;}
//Method used to set the medal for this number.
//medal: The new medal for this number.
void setMedal(int medal);
//Method that is used to draw the number.
//dy: The y offset.
void show(SDL_Renderer &renderer, int dy);
};
struct ToolTip {
TexturePtr name;
TexturePtr time;
TexturePtr recordings;
size_t number;
};
//This is the LevelSelect state, here you can select levelpacks and levels.
class LevelSelect : public GameState,public GUIEventCallback{
protected:
//Surface containing the title.
TexturePtr title;
ToolTip toolTip;
//Vector containing the numbers.
std::vector<Number> numbers;
//Contains selected level number (displayed at bottom left corner).
//If it's NULL then nothing selected.
Number* selectedNumber;
//Pointer to the scrollbar.
GUIScrollBar* levelScrollBar;
//Pointer to the description.
GUIObject* levelpackDescription;
//Pointer to the levelpack list.
GUISingleLineListBox* levelpacks;
//Check where and if the mouse clicked on a number.
//If so select that number.
virtual void checkMouse(ImageManager& imageManager, SDL_Renderer& renderer);
//Selected section for keyboard/gamepad control
+ //1=level pack selection 2=level selection 3=LevelPlaySelect/LevelEditSelect specific
int section;
+ //LevelPlaySelect/LevelEditSelect specific selected section. Only used when section==3.
+ int section2;
+
//The number of blocks in a row.
int LEVELS_PER_ROW;
//The number of levels displayed on screen at once.
int LEVELS_DISPLAYED_IN_SCREEN;
public:
//Constructor.
//titleText: The title that is shown at the top of the screen.
//packType: The type of levelpacks that should be listed (See LevelPackManager.h).
LevelSelect(ImageManager& imageManager, SDL_Renderer &renderer, const char* titleText, LevelPackManager::LevelPackLists packType=LevelPackManager::ALL_PACKS);
//Destructor.
virtual ~LevelSelect();
//Method that will calculate the number of rows and the number of levels per row.
void calcRows();
//Method used to update the numbers and the scrollbar.
//change: Boolean if the levelpack changed, if not only the numbers need to be replaced.
virtual void refresh(ImageManager& imageManager, SDL_Renderer& renderer, bool change=true)=0;
//Method that is called when a number is selected.
//number: The selected number.
//selected: Boolean if the number was already selected.
virtual void selectNumber(ImageManager &imageManager, SDL_Renderer &renderer, unsigned int number,bool selected)=0;
//Used for keyboard/gamepad navigation
void selectNumberKeyboard(ImageManager &imageManager, SDL_Renderer &renderer, int x, int y);
//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;
//Method that is called to render the tooltip.
//number: The number that the tooltip should be drawn for.
//dy: The y offset of the number, used to draw the tooltip in the right place.
virtual void renderTooltip(SDL_Renderer& renderer,unsigned int number,int dy)=0;
//GUI events will be handled here.
virtual void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType)=0;
};
#endif

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 16, 11:32 AM (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
64151
Default Alt Text
(42 KB)

Event Timeline