Setup framework for scrollbar and buttons in ScrollableWindowComponent. Fixed a bug where disabled buttons would not increment selection check loop. CreateMenu function instead of creating pointer and returning, so windows can add stuff to menus easily.

This commit is contained in:
sigonasr2 2023-10-15 12:58:39 -05:00
parent b08002e61b
commit ff3f4ba1c0
13 changed files with 86 additions and 48 deletions

View File

@ -1066,7 +1066,7 @@ void Crawler::RenderHud(){
if("debug_player_info"_I){ if("debug_player_info"_I){
DrawShadowStringDecal({0,128},player->GetPos().str()); DrawShadowStringDecal({0,128},player->GetPos().str());
DrawShadowStringDecal({0,136},"Spd: "+std::to_string(player->GetMoveSpdMult())); DrawShadowStringDecal({0,136},"Spd: "+std::to_string(player->GetMoveSpdMult()));
DrawShadowStringDecal({0,4},"Selection: "+Menu::menus[INVENTORY]->selection.str()); DrawShadowStringDecal({0,1},"Selection: "+Menu::menus[INVENTORY]->selection.str());
DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY]->buttonHoldTime)); DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY]->buttonHoldTime));
} }
} }
@ -1752,9 +1752,17 @@ void Crawler::InitializeGraphics(){
for(auto&val:DATA["Images"].GetKeys()){ for(auto&val:DATA["Images"].GetKeys()){
std::string key=val.first; std::string key=val.first;
std::string imgFile=DATA["Images"][key].GetString(); std::string imgFile=DATA["Images"][key].GetString(0);
std::cout<<"Loading image "+imgFile+"..."<<std::endl; std::cout<<"Loading image "+imgFile+"..."<<std::endl;
if(!GFX.count(imgFile)&&GFX[imgFile].Load("GFX_Prefix"_S+imgFile,nullptr,false,false)!=rcode::OK){ bool filtering=false;
bool clamping=false;
if(DATA["Images"][key].GetValueCount()>1){
filtering=bool(DATA["Images"][key].GetInt(1));
}
if(DATA["Images"][key].GetValueCount()>2){
clamping=bool(DATA["Images"][key].GetInt(2));
}
if(!GFX.count(imgFile)&&GFX[imgFile].Load("GFX_Prefix"_S+imgFile,nullptr,filtering,clamping)!=rcode::OK){
std::cout<<" WARNING! Failed to load "+imgFile+"!"; std::cout<<" WARNING! Failed to load "+imgFile+"!";
throw; throw;
} }

View File

@ -11,7 +11,7 @@
INCLUDE_GFX INCLUDE_GFX
typedef Attribute A; typedef Attribute A;
Menu*Menu::InitializeInventoryWindow(){ void Menu::InitializeInventoryWindow(){
constexpr int invWidth=5; constexpr int invWidth=5;
constexpr int initialInvHeight=3; constexpr int initialInvHeight=3;
@ -19,11 +19,11 @@ Menu*Menu::InitializeInventoryWindow(){
constexpr int buttonSize=24; constexpr int buttonSize=24;
constexpr int totalSpacing=buttonSize+itemSpacing; constexpr int totalSpacing=buttonSize+itemSpacing;
vf2d windowSize={totalSpacing*invWidth-itemSpacing+1,totalSpacing*(3+1)-itemSpacing+24}; vf2d windowSize={totalSpacing*invWidth-itemSpacing+2+24,totalSpacing*(3+1)-itemSpacing+24}; //Need space for the button.
Menu*inventoryWindow=new Menu(CENTERED,windowSize); Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,windowSize);
ScrollableWindowComponent*inventory=new ScrollableWindowComponent(INVENTORY,{{0,0},{windowSize.x,totalSpacing*3-itemSpacing}},nullptr,[](MenuFuncData data){}); ScrollableWindowComponent*inventory=new ScrollableWindowComponent(INVENTORY,{{1,0},{windowSize.x,totalSpacing*3-itemSpacing}},nullptr,[](MenuFuncData data){});
inventoryWindow->AddComponent("inventory",inventory); inventoryWindow->AddComponent("inventory",inventory);
MenuFunc useItemFunc=[](MenuFuncData data){ MenuFunc useItemFunc=[](MenuFuncData data){
@ -43,6 +43,4 @@ Menu*Menu::InitializeInventoryWindow(){
inventoryWindow->AddComponent("itemName",itemNameLabel); inventoryWindow->AddComponent("itemName",itemNameLabel);
MenuLabel*itemDescriptionLabel=new MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,initialInvHeight*totalSpacing+itemSpacing},{windowSize.x-4,windowSize.y-108}),"",true,true}; MenuLabel*itemDescriptionLabel=new MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,initialInvHeight*totalSpacing+itemSpacing},{windowSize.x-4,windowSize.y-108}),"",true,true};
inventoryWindow->AddComponent("itemDescription",itemDescriptionLabel); inventoryWindow->AddComponent("itemDescription",itemDescriptionLabel);
return inventoryWindow;
} }

View File

@ -15,8 +15,6 @@ extern vi2d WINDOW_SIZE;
typedef Attribute A; typedef Attribute A;
Menu::Menu(){}
Menu::Menu(vf2d pos,vf2d size) Menu::Menu(vf2d pos,vf2d size)
:pos(pos==CENTERED?WINDOW_SIZE/2-size/2:vi2d{pos}),size(size){ :pos(pos==CENTERED?WINDOW_SIZE/2-size/2:vi2d{pos}),size(size){
r.Create(size.x,size.y); r.Create(size.x,size.y);
@ -25,19 +23,28 @@ Menu::Menu(vf2d pos,vf2d size)
void Menu::InitializeMenus(){ void Menu::InitializeMenus(){
stack.reserve(32); stack.reserve(32);
menus[TEST]=InitializeTestMenu(); InitializeTestMenu();
menus[TEST_2]=InitializeTestSubMenu(); InitializeTestSubMenu();
menus[INVENTORY]=InitializeInventoryWindow(); InitializeInventoryWindow();
for(MenuType type=TEST;type<MenuType::ENUM_END;type=MenuType(int(type+1))){ for(MenuType type=TEST;type<MenuType::ENUM_END;type=MenuType(int(type+1))){
if(menus.count(type)==0){ if(menus.count(type)==0){
std::cout<<"WARNING! Menu Type "<<type<<" does not exist!"<<std::endl; std::cout<<"WARNING! Menu Type "<<type<<" does not exist!"<<std::endl;
throw; throw;
} }
for(auto&key:menus[type]->components){
MenuComponent*component=key.second;
component->AfterCreate();
}
menus[type]->components.SetInitialized(); //Lock all known components to prevent invalid access. menus[type]->components.SetInitialized(); //Lock all known components to prevent invalid access.
} }
} }
Menu*Menu::CreateMenu(MenuType type,vf2d pos,vf2d size){
menus[type]=new Menu(pos,size);
return menus.at(type);
}
void Menu::AddComponent(std::string key,MenuComponent*button){ void Menu::AddComponent(std::string key,MenuComponent*button){
if(button->selectable){ if(button->selectable){
buttons[button->rect.pos.y].push_back(button); buttons[button->rect.pos.y].push_back(button);
@ -59,13 +66,16 @@ void Menu::CheckClickAndPerformMenuSelect(Crawler*game){
void Menu::HoverMenuSelect(Crawler*game){ void Menu::HoverMenuSelect(Crawler*game){
if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return; if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return;
if(buttons[selection.y][selection.x]->draggable) if(buttons[selection.y][selection.x]->draggable){
if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F)CheckClickAndPerformMenuSelect(game); if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){
else{ CheckClickAndPerformMenuSelect(game);
}else{
draggingComponent=buttons[selection.y][selection.x]->PickUpDraggableItem(); draggingComponent=buttons[selection.y][selection.x]->PickUpDraggableItem();
buttonHoldTime=0; buttonHoldTime=0;
} }
else CheckClickAndPerformMenuSelect(game); }else{
CheckClickAndPerformMenuSelect(game);
}
} }
void Menu::MenuSelect(Crawler*game){ void Menu::MenuSelect(Crawler*game){
@ -110,8 +120,8 @@ void Menu::Update(Crawler*game){
selection.y=key.first; selection.y=key.first;
selection.x=index; selection.x=index;
} }
index++;
} }
index++;
} }
} }
} }
@ -161,6 +171,11 @@ void Menu::Draw(Crawler*game){
Pixel::Mode prevMode=game->GetPixelMode(); Pixel::Mode prevMode=game->GetPixelMode();
game->SetPixelMode(Pixel::MASK); game->SetPixelMode(Pixel::MASK);
game->Clear(BLANK); game->Clear(BLANK);
for(auto&component:displayComponents){
if(component->renderInMain){
component->_Draw(game,{0,0},this==Menu::stack.back());
}
}
for(auto&key:buttons){ for(auto&key:buttons){
for(auto&button:key.second){ for(auto&button:key.second){
if(button->renderInMain){ if(button->renderInMain){
@ -168,15 +183,15 @@ void Menu::Draw(Crawler*game){
} }
} }
} }
for(auto&component:displayComponents){
if(component->renderInMain){
component->_Draw(game,{0,0},this==Menu::stack.back());
}
}
game->SetPixelMode(prevMode); game->SetPixelMode(prevMode);
game->SetDrawTarget(nullptr); game->SetDrawTarget(nullptr);
r.Decal()->Update(); r.Decal()->Update();
game->DrawDecal(pos,r.Decal()); game->DrawDecal(pos,r.Decal());
for(auto&component:displayComponents){
if(component->renderInMain){
component->_DrawDecal(game,pos,this==Menu::stack.back());
}
}
for(auto&key:buttons){ for(auto&key:buttons){
for(auto&button:key.second){ for(auto&button:key.second){
if(button->renderInMain){ if(button->renderInMain){
@ -184,11 +199,6 @@ void Menu::Draw(Crawler*game){
} }
} }
} }
for(auto&component:displayComponents){
if(component->renderInMain){
component->_DrawDecal(game,pos,this==Menu::stack.back());
}
}
if(GetCurrentTheme().IsScaled()){ if(GetCurrentTheme().IsScaled()){
DrawScaledWindowBorder(game,pos); DrawScaledWindowBorder(game,pos);
@ -364,7 +374,9 @@ void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
} }
} }
if(prevSelection!=selection){ if(prevSelection!=selection){
if(selection!=vi2d{-1,-1}&&buttons[selection.y][selection.x]->disabled)selection=prevSelection; if(selection!=vi2d{-1,-1}&&buttons[selection.y][selection.x]->disabled){
selection=prevSelection;
}
// If the new selection of a button on this frame is disabled for some reason, we need to go back to what we had selected before. // If the new selection of a button on this frame is disabled for some reason, we need to go back to what we had selected before.
} }
} }

View File

@ -34,8 +34,9 @@ class Menu:IAttributable{
MenuComponent*draggingComponent=nullptr; MenuComponent*draggingComponent=nullptr;
Renderable r,overlay; Renderable r,overlay;
public: public:
Menu(); //The constructor is private. Use CreateMenu() instead!
Menu(vf2d pos,vf2d size); Menu()=default;
virtual ~Menu()=default;
void AddComponent(std::string key,MenuComponent*button); void AddComponent(std::string key,MenuComponent*button);
void Update(Crawler*game); void Update(Crawler*game);
void Draw(Crawler*game); void Draw(Crawler*game);
@ -51,12 +52,15 @@ public:
vf2d size; //Size in tiles (24x24), every menu will be tile-based vf2d size; //Size in tiles (24x24), every menu will be tile-based
private: private:
Menu(vf2d pos,vf2d size);
void HoverMenuSelect(Crawler*game); void HoverMenuSelect(Crawler*game);
void MenuSelect(Crawler*game); void MenuSelect(Crawler*game);
void CheckClickAndPerformMenuSelect(Crawler*game); void CheckClickAndPerformMenuSelect(Crawler*game);
static Menu*InitializeTestMenu(); //Mandatory before any menu operations! This creates and sets up the menu in memory.
static Menu*InitializeTestSubMenu(); static Menu*CreateMenu(MenuType type,vf2d pos,vf2d size);
static Menu*InitializeInventoryWindow(); static void InitializeTestMenu();
static void InitializeTestSubMenu();
static void InitializeInventoryWindow();
//X (0-3), Y (0-2) for specific 9-patch tile (tiled version). //X (0-3), Y (0-2) for specific 9-patch tile (tiled version).
static Renderable&GetPatchPart(int x,int y); static Renderable&GetPatchPart(int x,int y);

View File

@ -7,6 +7,8 @@ MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string
MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,bool selectable) MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,bool selectable)
:parentMenu(parent),rect(rect),label(label),menuDest(menuDest),onClick(onClick),hoverEffect(0),selectable(selectable){} :parentMenu(parent),rect(rect),label(label),menuDest(menuDest),onClick(onClick),hoverEffect(0),selectable(selectable){}
void MenuComponent::AfterCreate(){}
void MenuComponent::Update(Crawler*game){ void MenuComponent::Update(Crawler*game){
if(hovered){ if(hovered){
hoverEffect=std::min("ThemeGlobal.HighlightTime"_F,hoverEffect+game->GetElapsedTime()); hoverEffect=std::min("ThemeGlobal.HighlightTime"_F,hoverEffect+game->GetElapsedTime());

View File

@ -27,6 +27,7 @@ protected:
virtual void Draw(Crawler*game,vf2d parentPos,bool focused); virtual void Draw(Crawler*game,vf2d parentPos,bool focused);
virtual void DrawDecal(Crawler*game,vf2d parentPos,bool focused); virtual void DrawDecal(Crawler*game,vf2d parentPos,bool focused);
virtual bool GetHoverState(Crawler*game,MenuComponent*child); virtual bool GetHoverState(Crawler*game,MenuComponent*child);
virtual void AfterCreate(); //Called after the creation of all menus finish.
public: public:
MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuFunc onClick,bool selectable=true); MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuFunc onClick,bool selectable=true);
MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,bool selectable=true); MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,bool selectable=true);

View File

@ -9,6 +9,8 @@ class ScrollableWindowComponent:public MenuComponent{
protected: protected:
Renderable r; Renderable r;
std::vector<MenuComponent*>components; std::vector<MenuComponent*>components;
MenuComponent*upButton=nullptr;
MenuComponent*downButton=nullptr;
geom2d::rect<float>bounds; //It's for the scrollbar. geom2d::rect<float>bounds; //It's for the scrollbar.
private: private:
inline bool OnScreen(MenuComponent*component){ inline bool OnScreen(MenuComponent*component){
@ -19,6 +21,17 @@ public:
:MenuComponent(parent,rect,"",onClick,false){ :MenuComponent(parent,rect,"",onClick,false){
r.Create(rect.size.x,rect.size.y); r.Create(rect.size.x,rect.size.y);
} }
virtual inline ~ScrollableWindowComponent(){
}
private:
virtual inline void AfterCreate()override{
upButton=new MenuComponent(parentMenu,{vf2d{rect.size.x-12,0},{12,12}},"^",[](MenuFuncData dat){std::cout<<"Clicked"<<std::endl;});
downButton=new MenuComponent(parentMenu,{rect.size-vf2d{12,12},{12,12}},"v",[](MenuFuncData dat){});
Menu::menus[parentMenu]->AddComponent("scrollableWindowButton"+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton);
Menu::menus[parentMenu]->AddComponent("scrollableWindowButton"+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton);
}
protected: protected:
virtual inline void Update(Crawler*game)override{ virtual inline void Update(Crawler*game)override{
MenuComponent::Update(game); MenuComponent::Update(game);
@ -42,20 +55,23 @@ protected:
game->SetDrawTarget(r.Sprite()); game->SetDrawTarget(r.Sprite());
game->Clear(BLANK); game->Clear(BLANK);
for(MenuComponent*component:components){ for(MenuComponent*component:components){
component->_Draw(game,V(A::SCROLL_OFFSET),focused); component->_Draw(game,rect.pos+V(A::SCROLL_OFFSET),focused);
} }
game->SetDrawTarget(prevDrawTarget); game->SetDrawTarget(prevDrawTarget);
game->DrawSprite(parentPos,r.Sprite()); game->DrawSprite(parentPos,r.Sprite());
} }
virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{ virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{
MenuComponent::DrawDecal(game,parentPos,focused); MenuComponent::DrawDecal(game,parentPos,focused);
game->DrawRectDecal(parentPos,rect.size); game->DrawRectDecal(rect.pos+parentPos,rect.size);
for(MenuComponent*component:components){ for(MenuComponent*component:components){
component->_DrawDecal(game,parentPos+V(A::SCROLL_OFFSET),focused); component->_DrawDecal(game,rect.pos+parentPos+V(A::SCROLL_OFFSET),focused);
} }
game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-12,0},{12,12});
game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-12,12},{12,rect.size.y-24});
game->DrawRectDecal(rect.pos+parentPos+rect.size-vf2d{12,12},{12,12});
} }
virtual bool GetHoverState(Crawler*game,MenuComponent*child)override{ virtual bool GetHoverState(Crawler*game,MenuComponent*child)override{
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+child->rect.pos+V(A::SCROLL_OFFSET),child->rect.size},game->GetMousePos()); return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos+V(A::SCROLL_OFFSET),child->rect.size},game->GetMousePos());
} }
public: public:
void inline AddComponent(Menu*parentMenu,std::string key,MenuComponent*button){ void inline AddComponent(Menu*parentMenu,std::string key,MenuComponent*button){

View File

@ -1,8 +1,8 @@
#include "Crawler.h" #include "Crawler.h"
#include "MenuComponent.h" #include "MenuComponent.h"
Menu*Menu::InitializeTestMenu(){ void Menu::InitializeTestMenu(){
Menu*testMenu=new Menu(CENTERED,{24*8,24*6}); Menu*testMenu=CreateMenu(TEST,CENTERED,{24*8,24*6});
MenuFunc quitWindow=[](MenuFuncData data){ MenuFunc quitWindow=[](MenuFuncData data){
data.menu.stack.clear(); data.menu.stack.clear();
@ -22,5 +22,4 @@ Menu*Menu::InitializeTestMenu(){
testMenu->AddComponent("Open SubMenu",new MenuComponent(TEST,{{24*2,24*4.5},{24*4,24*1}},"Open Another\n Menu",TEST_2,doNothing)); testMenu->AddComponent("Open SubMenu",new MenuComponent(TEST,{{24*2,24*4.5},{24*4,24*1}},"Open Another\n Menu",TEST_2,doNothing));
return testMenu;
} }

View File

@ -8,8 +8,8 @@
INCLUDE_GFX INCLUDE_GFX
typedef Attribute A; typedef Attribute A;
Menu*Menu::InitializeTestSubMenu(){ void Menu::InitializeTestSubMenu(){
Menu*testSubMenu=new Menu({30,30},{24*4,24*5}); Menu*testSubMenu=CreateMenu(TEST_2,{30,30},{24*4,24*5});
MenuFunc goBack=[](MenuFuncData data){ MenuFunc goBack=[](MenuFuncData data){
data.menu.stack.pop_back(); data.menu.stack.pop_back();
@ -61,6 +61,4 @@ Menu*Menu::InitializeTestSubMenu(){
}; };
testSubMenu->AddComponent("NEXT_THEME",new MenuComponent(TEST_2,{{24*3.5,24*3},{24*1,24*1}},">",themeNext)); testSubMenu->AddComponent("NEXT_THEME",new MenuComponent(TEST_2,{{24*3.5,24*3},{24*1,24*1}},">",themeNext));
return testSubMenu;
} }

View File

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 2026 #define VERSION_BUILD 2066
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

View File

@ -55,7 +55,7 @@ debug_access_options = 0
debug_map_load_info = 0 debug_map_load_info = 0
# Shows extra info about the player on the HUD # Shows extra info about the player on the HUD
debug_player_info = 0 debug_player_info = 1
# Shows collision boxes of tiles. # Shows collision boxes of tiles.
debug_collision_boxes = 0 debug_collision_boxes = 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB