git repos / blockattack-game

source/code/MenuSystem.cpp

browsing at commit = 1b710a1eed37f7072bb5b5c69695469353635a5a

raw · blame · history

/*
===========================================================================
blockattack - Block Attack - Rise of the Blocks
Copyright (C) 2005-2012 Poul Sander

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see http://www.gnu.org/licenses/

Source information and contacts persons can be found at
http://www.blockattack.net
===========================================================================
*/


#include "MenuSystem.h"
#include "common.h"
#include "global.hpp"
#include "gamecontroller.h"

static int mousex;
static int mousey;

using std::string;
using std::cerr;
using std::cout;
using std::vector;

const char* const menu_marked = "menu_marked";
const char* const menu_unmarked = "menu_unmarked";

ButtonGfx standardButton;

void ButtonGfx::setSurfaces() {
	this->xsize = spriteHolder->GetSprite(menu_marked).GetWidth();
	this->ysize = spriteHolder->GetSprite(menu_marked).GetHeight();
	if (verboseLevel) {
		cout << "Surfaces set, size: " << this->xsize << " , " << this->ysize << "\n";
	}
}

Button::Button() {
	gfx = &standardButton;
	label = "";
	marked = false;
	action = nullptr;
	popOnRun = false;
}

Button::~Button() {
}

Button::Button(const Button& b) {
	gfx = b.gfx;
	label = b.label;
	marked = b.marked;
	action = b.action;
	popOnRun = false;
}

void Button::setLabel(const string& text) {
	label = text;
}

void Button::setAction(void (*action2run)(Button*)) {
	action = action2run;
}

bool Button::isClicked(int x,int y) {
	if ( x >= this->x && y >= this->y && x<= this->x+gfx->xsize && y <= this->y + gfx->ysize) {
		return true;
	}
	return false;
}

void Button::doAction() {
	if (action) {
		action(this);
		return;
	}
	cerr << "Warning: button \"" << label << "\" has no action assigned!";
}

void Button::drawToScreen() {
#if DEBUG
	//cout << "Painting button: " << label << " at: " << x << "," << y << "\n";
#endif
	if (marked) {
		spriteHolder->GetSprite(menu_marked).Draw(screen, SDL_GetTicks(), x, y);
	}
	else {
		spriteHolder->GetSprite(menu_unmarked).Draw(screen, SDL_GetTicks(), x, y);
	}
	
	gfx->thefont->draw(screen, x+gfx->xsize/2,y+gfx->ysize/2-gfx->thefont->getHeight("%s", label.c_str())/2, NFont::CENTER, "%s", label.c_str());
}

void Button::setPopOnRun(bool popOnRun) {
	this->popOnRun = popOnRun;
}

bool Button::isPopOnRun() const {
	return popOnRun;
}

void Button::setGfx(ButtonGfx* gfx) {
	this->gfx = gfx;
}

int Button::getHeight() const {
	return this->gfx->ysize;
}

int Button::getWidth() const {
	return this->gfx->xsize;
}

void Menu::drawSelf() {
	DrawBackground(screen);
	vector<Button*>::iterator it;
	for (it = buttons.begin(); it < buttons.end(); it++) {
		(*it)->drawToScreen();
	}
	exit.drawToScreen();
	standardButton.thefont->draw(screen, 50, 50, "%s", title.c_str());
	mouse.Draw(screen, SDL_GetTicks(), mousex, mousey);
}


void Menu::placeButtons() {
	int nextY = 100;
	int X = 50;
	for (Button* it : buttons) {
		X = (xsize - it->getWidth())/2;
		it->x = X;
		it->y = nextY;
		nextY += it->getHeight()+10;
	}
	exit.x = X;
	exit.y = nextY;
}

void Menu::addButton(Button* b) {
	buttons.push_back(b);
	b->marked = false;
	placeButtons();
}

Menu::Menu(SDL_Renderer* screen) {
	this->screen = screen;
	buttons = vector<Button*>(10);
	isSubmenu = true;
	exit.setLabel( _("Back") );
}

Menu::Menu(SDL_Renderer* screen,bool submenu) {
	this->screen = screen;
	buttons = vector<Button*>(0);
	isSubmenu = submenu;
	if (isSubmenu) {
		exit.setLabel( _("Back") );
	}
	else {
		exit.setLabel( _("Exit") );
	}
}

Menu::Menu(SDL_Renderer* screen, const string& title, bool submenu) {
	this->screen = screen;
	buttons = vector<Button*>(0);
	isSubmenu = submenu;
	this->title = title;
	if (isSubmenu) {
		exit.setLabel(_("Back") );
	}
	else {
		exit.setLabel(_("Exit") );
	}
}

bool isUpEvent(const SDL_Event& event) {
	if ( event.type == SDL_KEYDOWN ) {
		if (event.key.keysym.sym == SDLK_UP) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERBUTTONDOWN) {
		if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP ) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERAXISMOTION  && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ) {
		checkDeadZone(event);
		const SDL_ControllerAxisEvent& a = event.caxis;
		if (getDeadZone(a.which, a.axis)) {
			if (event.caxis.value < -deadZoneLimit) {
				setDeadZone(a.which,a.axis,false);
				return true;
			}
		}
	}
	return false;
}

bool isDownEvent(const SDL_Event& event) {
	if ( event.type == SDL_KEYDOWN ) {
		if (event.key.keysym.sym == SDLK_DOWN) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERBUTTONDOWN) {
		if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN ) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERAXISMOTION  && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ) {
		checkDeadZone(event);
		const SDL_ControllerAxisEvent& a = event.caxis;
		if (getDeadZone(a.which, a.axis)) {
			if (event.caxis.value > deadZoneLimit) {
				setDeadZone(a.which,a.axis,false);
				return true;
			}
		}
	}
	return false;
}

bool isLeftEvent(const SDL_Event& event) {
	if ( event.type == SDL_KEYDOWN ) {
		if (event.key.keysym.sym == SDLK_LEFT) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERBUTTONDOWN) {
		if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT ) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERAXISMOTION  && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
		checkDeadZone(event);
		const SDL_ControllerAxisEvent& a = event.caxis;
		if (getDeadZone(a.which, a.axis)) {
			if (event.caxis.value < -deadZoneLimit) {
				setDeadZone(a.which,a.axis,false);
				return true;
			}
		}
	}
	return false;
}

bool isRightEvent(const SDL_Event& event) {
	if ( event.type == SDL_KEYDOWN ) {
		if (event.key.keysym.sym == SDLK_RIGHT) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERBUTTONDOWN) {
		if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT ) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERAXISMOTION  && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
		checkDeadZone(event);
		const SDL_ControllerAxisEvent& a = event.caxis;
		if (getDeadZone(a.which, a.axis)) {
			if (event.caxis.value > deadZoneLimit) {
				setDeadZone(a.which,a.axis,false);
				return true;
			}
		}
	}
	return false;
}

bool isEscapeEvent(const SDL_Event& event) {
	if ( event.type == SDL_KEYDOWN ) {
		if ( event.key.keysym.sym == SDLK_ESCAPE ) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERBUTTONDOWN) {
		if (event.cbutton.button == SDL_CONTROLLER_BUTTON_Y ) {
			return true;
		}
	}
	return false;
}

bool isConfirmEvent(const SDL_Event& event) {
	if ( event.type == SDL_KEYDOWN ) {
		if (event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER ) {
			return true;
		}
	}
	if (event.type == SDL_CONTROLLERBUTTONDOWN) {
		if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A || event.cbutton.button == SDL_CONTROLLER_BUTTON_B ) {
			return true;
		}
	}
	return false;
}

void Menu::run() {
	running = true;
	bool bMouseUp = false;
	long oldmousex = mousex;
	long oldmousey = mousey;
	while (running && !Config::getInstance()->isShuttingDown()) {
		if (!(highPriority)) {
			SDL_Delay(10);
		}
		SDL_Event event;
		while ( SDL_PollEvent(&event) ) {
			if ( event.type == SDL_QUIT ) {
				Config::getInstance()->setShuttingDown(5);
				running = false;
			}

			if (isUpEvent(event)) {
				marked--;
				if (marked<0) {
					marked = buttons.size();    //not -1, since exit is after the last element in the list
				}
			}

			if (isDownEvent(event)) {
				marked++;
				if (marked> (int)buttons.size()) {
					marked = 0;
				}
			}

			if (isEscapeEvent(event) && isSubmenu) {
				running = false;
			}

			if (isConfirmEvent(event)) {
				if (marked < (int)buttons.size()) {
					buttons.at(marked)->doAction();
					if (buttons.at(marked)->isPopOnRun()) {
						running = false;
					}
				}
				if (marked == (int)buttons.size()) {
					running = false;
				}
			}

		}

		for (int i=0; i<(int)buttons.size(); i++) {
			buttons.at(i)->marked = (i == marked);
		}
		exit.marked = (marked == (int)buttons.size());
		Uint8 buttonState = SDL_GetMouseState(&mousex,&mousey);
		// If the mouse button is released, make bMouseUp equal true
		if ( (buttonState&SDL_BUTTON(1))==0) {
			bMouseUp=true;
		}

		if (abs(mousex-oldmousex)>5 || abs(mousey-oldmousey)>5) {
			for (int i=0; i< (int)buttons.size(); ++i) {
				if (buttons.at(i)->isClicked(mousex,mousey)) {
					marked = i;
				}
			}
			if (exit.isClicked(mousex,mousey)) {
				marked = buttons.size();
			}
			oldmousex = mousex;
			oldmousey = mousey;
		}

		//mouse clicked
		if ( (buttonState&SDL_BUTTON(1) )==SDL_BUTTON(1) && bMouseUp) {
			bMouseUp = false;
			for (int i=0; i< (int)buttons.size(); ++i) {
				if (buttons.at(i)->isClicked(mousex,mousey)) {
					buttons.at(i)->doAction();
					if (buttons.at(i)->isPopOnRun()) {
						running = false;
					}
					mousex = 0;
				}
			}
			if (exit.isClicked(mousex,mousey)) {
				running = false;
			}
		}
		placeButtons();
		drawSelf();
		SDL_RenderPresent(screen);
	}
}