|
|
|
#include "Crawler.h"
|
|
|
|
#include "Menu.h"
|
|
|
|
|
|
|
|
bool Menu::MOUSE_NAVIGATION=true;
|
|
|
|
std::vector<Menu*>Menu::stack;
|
|
|
|
std::map<MenuType,Menu>Menu::menus;
|
|
|
|
|
|
|
|
Menu::Menu(){}
|
|
|
|
|
|
|
|
Menu::Menu(vf2d size)
|
|
|
|
:size(size){}
|
|
|
|
|
|
|
|
void Menu::InitializeMenus(){
|
|
|
|
stack.reserve(32);
|
|
|
|
menus[TEST]=InitializeTestMenu();
|
|
|
|
menus[TEST_2]=InitializeTestSubMenu();
|
|
|
|
|
|
|
|
for(MenuType type=TEST;type<MenuType::ENUM_END;type=MenuType(int(type+1))){
|
|
|
|
if(menus.count(type)==0){
|
|
|
|
std::cout<<"WARNING! Menu Type "<<type<<" does not exist!"<<std::endl;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Menu::AddButton(const MenuButton&button){
|
|
|
|
buttons[button.rect.pos.y].push_back(button);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Menu::MenuSelect(Crawler*game){
|
|
|
|
if(selection==vi2d{-1,-1})return;
|
|
|
|
buttons[selection.y][selection.x].onClick(*this,game);
|
|
|
|
if(buttons[selection.y][selection.x].menuDest!=MenuType::ENUM_END){
|
|
|
|
if(stack.size()<32){
|
|
|
|
stack.push_back(&menus[buttons[selection.y][selection.x].menuDest]);//Navigate to the next menu.
|
|
|
|
}else{
|
|
|
|
std::cout<<"WARNING! Exceeded menu stack size limit!"<<std::endl;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Menu::Update(Crawler*game){
|
|
|
|
vf2d upperLeftPos=game->GetScreenSize()/2-size/2;
|
|
|
|
|
|
|
|
for(auto&key:buttons){
|
|
|
|
for(auto&button:key.second){
|
|
|
|
button.hovered=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!MOUSE_NAVIGATION){
|
|
|
|
if(selection!=vi2d{-1,-1})buttons[selection.y][selection.x].hovered=true;
|
|
|
|
}else{
|
|
|
|
for(auto&key:buttons){
|
|
|
|
for(auto&button:key.second){
|
|
|
|
if(geom2d::overlaps(geom2d::rect<float>{button.rect.pos+upperLeftPos,button.rect.size},game->GetMousePos())){
|
|
|
|
button.hovered=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KeyboardButtonNavigation(game);
|
|
|
|
if(game->GetMouse(0).bPressed||game->GetKey(ENTER).bPressed||game->GetKey(SPACE).bPressed){
|
|
|
|
MOUSE_NAVIGATION=game->GetMouse(0).bPressed; //If a click occurs we use mouse controls.
|
|
|
|
if(!MOUSE_NAVIGATION){
|
|
|
|
MenuSelect(game);
|
|
|
|
//Key presses automatically highlight the first button if it's not highlighted.
|
|
|
|
if(selection==vi2d{-1,-1}&&buttons.size()>0){
|
|
|
|
//Find the first possible button entry in the map...
|
|
|
|
int firstInd=-1;
|
|
|
|
for(auto&key:buttons){
|
|
|
|
if(buttons[key.first].size()>0){
|
|
|
|
firstInd=key.first;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(firstInd!=-1){ //This means we found a valid menu item. If we didn't find one don't highlight any menu item...
|
|
|
|
selection={0,firstInd};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}else{//Mouse click.
|
|
|
|
selection={-1,-1};
|
|
|
|
for(auto&key:buttons){
|
|
|
|
int index=0;
|
|
|
|
for(auto&button:key.second){
|
|
|
|
if(geom2d::overlaps(geom2d::rect<float>{button.rect.pos+upperLeftPos,button.rect.size},game->GetMousePos())){
|
|
|
|
selection={index,key.first};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MenuSelect(game);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(auto&key:buttons){
|
|
|
|
for(auto&button:key.second){
|
|
|
|
button.Update(game);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void Menu::Draw(Crawler*game){
|
|
|
|
vf2d upperLeftPos=game->GetScreenSize()/2-size/2;
|
|
|
|
game->FillRectDecal(upperLeftPos,size,VERY_DARK_BLUE);
|
|
|
|
for(auto&key:buttons){
|
|
|
|
for(auto&button:key.second){
|
|
|
|
button.Draw(game,upperLeftPos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void Menu::OpenMenu(MenuType menu){
|
|
|
|
stack.clear();
|
|
|
|
stack.push_back(&(menus[menu]));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Menu::KeyboardButtonNavigation(Crawler*game){
|
|
|
|
if(game->GetKey(RIGHT).bPressed){
|
|
|
|
if(selection==vi2d{-1,-1})return;
|
|
|
|
MOUSE_NAVIGATION=false;
|
|
|
|
selection.x=(selection.x+1)%buttons[selection.y].size();
|
|
|
|
}
|
|
|
|
if(game->GetKey(LEFT).bPressed){
|
|
|
|
if(selection==vi2d{-1,-1})return;
|
|
|
|
selection.x--;
|
|
|
|
if(selection.x<0)selection.x+=buttons[selection.y].size();
|
|
|
|
}
|
|
|
|
if(game->GetKey(DOWN).bPressed||game->GetKey(UP).bPressed){
|
|
|
|
if(game->GetKey(DOWN).bPressed){
|
|
|
|
MOUSE_NAVIGATION=false;
|
|
|
|
bool found=false;
|
|
|
|
bool selectedItem=false;
|
|
|
|
if(selection==vi2d{-1,-1}){
|
|
|
|
//Highlight first item.
|
|
|
|
for(auto&key:buttons){
|
|
|
|
selection.y=key.first;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
for(auto&key:buttons){
|
|
|
|
if(found){ //Once we discover the previous element, the next element becomes our next selection.
|
|
|
|
selection.y=key.first;
|
|
|
|
selectedItem=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(key.first==selection.y){
|
|
|
|
found=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!selectedItem){ //This means we need to loop around instead and pick the first one.
|
|
|
|
for(auto&key:buttons){
|
|
|
|
selection.y=key.first;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(game->GetKey(UP).bPressed){
|
|
|
|
MOUSE_NAVIGATION=false;
|
|
|
|
|
|
|
|
if(selection==vi2d{-1,-1}){
|
|
|
|
//Highlight last item.
|
|
|
|
for(auto&key:buttons){
|
|
|
|
selection.y=key.first;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
int prevInd=-1;
|
|
|
|
for(auto&key:buttons){
|
|
|
|
if(key.first==selection.y){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prevInd=key.first;
|
|
|
|
}
|
|
|
|
if(prevInd!=-1){
|
|
|
|
selection.y=prevInd;
|
|
|
|
}else{ //Since we didn't find it, it means we're at the top of the list or the list is empty. Go to the last element and use that one.
|
|
|
|
int lastInd=-1;
|
|
|
|
for(auto&key:buttons){
|
|
|
|
lastInd=key.first;
|
|
|
|
}
|
|
|
|
selection.y=lastInd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//In both cases, we should clamp the X index to make sure it's still valid.
|
|
|
|
if(selection.y!=-1){
|
|
|
|
selection.x=std::clamp(selection.x,0,int(buttons[selection.y].size())-1);
|
|
|
|
}else{
|
|
|
|
selection.x=-1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|