Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F118156
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
20 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/LevelSelect.cpp b/src/LevelSelect.cpp
index 66766b6..73b8658 100644
--- a/src/LevelSelect.cpp
+++ b/src/LevelSelect.cpp
@@ -1,448 +1,433 @@
/*
* 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;
+ text << (number + 1);
- //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");
+ init(renderer, text.str(), box, number);
}
-void Number::init(SDL_Renderer& renderer,std::string text,SDL_Rect box,int number_){
+void Number::init(SDL_Renderer& renderer,const std::string& text,SDL_Rect box,int number){
//First set the number and update our status.
- this->number=number_;
+ this->number = number;
- //Create the text image.
- image = textureFromText(renderer,*fontGUI,text.c_str(),objThemes.getTextColor(true));
+ //Create the text image. Also check which font to use.
+ image = textureFromText(renderer,
+ (text.size() >= 3) ? (*fontGUISmall) : (*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);
+ applyTexture(box.x + 25 - (textureWidth(*image) / 2), box.y + 22 - (textureHeight(*image) / 2) - 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;
if (!numbers.empty()) {
selectNumber(imageManager, renderer, 0, false);
numbers[0].selected = true;
}
}
}
}
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 (isKeyboardOnly && section == 2 && inputMgr.isKeyDownEvent(INPUTMGR_SELECT) && selectedNumber) {
int n = selectedNumber->getNumber();
if (n >= 0) {
selectNumber(imageManager, renderer, n, true);
}
}
//Check if escape is pressed.
if(inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
//Check for scrolling down and up.
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;
}
}
}
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) {
levelpacks->state = (section == 1) ? 0x100 : 0;
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 f9359c1..1d81b29 100644
--- a/src/LevelSelect.h
+++ b/src/LevelSelect.h
@@ -1,176 +1,177 @@
/*
* 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);
+ //number: The number. Default is -1 (i.e. the caption doesn't represents a number).
+ void init(SDL_Renderer& renderer, const 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
Details
Attached
Mime Type
text/x-diff
Expires
Fri, May 15, 6:32 PM (1 h, 53 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
63950
Default Alt Text
(20 KB)
Attached To
Mode
R79 meandmyshadow
Attached
Detach File
Event Timeline