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.

pull/28/head
sigonasr2 1 year ago
parent b08002e61b
commit ff3f4ba1c0
  1. 14
      Crawler/Crawler.cpp
  2. 10
      Crawler/InventoryWindow.cpp
  3. 54
      Crawler/Menu.cpp
  4. 14
      Crawler/Menu.h
  5. 2
      Crawler/MenuComponent.cpp
  6. 1
      Crawler/MenuComponent.h
  7. 24
      Crawler/ScrollableWindowComponent.h
  8. 5
      Crawler/TestMenu.cpp
  9. 6
      Crawler/TestSubMenu.cpp
  10. 2
      Crawler/Version.h
  11. 2
      Crawler/assets/config/configuration.txt
  12. BIN
      Crawler/assets/knight_full3.png
  13. BIN
      Crawler/assets/knight_full_render1.png

@ -1066,7 +1066,7 @@ void Crawler::RenderHud(){
if("debug_player_info"_I){
DrawShadowStringDecal({0,128},player->GetPos().str());
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));
}
}
@ -1752,9 +1752,17 @@ void Crawler::InitializeGraphics(){
for(auto&val:DATA["Images"].GetKeys()){
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;
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+"!";
throw;
}

@ -11,7 +11,7 @@
INCLUDE_GFX
typedef Attribute A;
Menu*Menu::InitializeInventoryWindow(){
void Menu::InitializeInventoryWindow(){
constexpr int invWidth=5;
constexpr int initialInvHeight=3;
@ -19,11 +19,11 @@ Menu*Menu::InitializeInventoryWindow(){
constexpr int buttonSize=24;
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);
MenuFunc useItemFunc=[](MenuFuncData data){
@ -43,6 +43,4 @@ Menu*Menu::InitializeInventoryWindow(){
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};
inventoryWindow->AddComponent("itemDescription",itemDescriptionLabel);
return inventoryWindow;
}

@ -15,8 +15,6 @@ extern vi2d WINDOW_SIZE;
typedef Attribute A;
Menu::Menu(){}
Menu::Menu(vf2d pos,vf2d size)
:pos(pos==CENTERED?WINDOW_SIZE/2-size/2:vi2d{pos}),size(size){
r.Create(size.x,size.y);
@ -25,19 +23,28 @@ Menu::Menu(vf2d pos,vf2d size)
void Menu::InitializeMenus(){
stack.reserve(32);
menus[TEST]=InitializeTestMenu();
menus[TEST_2]=InitializeTestSubMenu();
menus[INVENTORY]=InitializeInventoryWindow();
InitializeTestMenu();
InitializeTestSubMenu();
InitializeInventoryWindow();
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;
}
for(auto&key:menus[type]->components){
MenuComponent*component=key.second;
component->AfterCreate();
}
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){
if(button->selectable){
buttons[button->rect.pos.y].push_back(button);
@ -59,13 +66,16 @@ void Menu::CheckClickAndPerformMenuSelect(Crawler*game){
void Menu::HoverMenuSelect(Crawler*game){
if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return;
if(buttons[selection.y][selection.x]->draggable)
if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F)CheckClickAndPerformMenuSelect(game);
else{
if(buttons[selection.y][selection.x]->draggable){
if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){
CheckClickAndPerformMenuSelect(game);
}else{
draggingComponent=buttons[selection.y][selection.x]->PickUpDraggableItem();
buttonHoldTime=0;
}
else CheckClickAndPerformMenuSelect(game);
}else{
CheckClickAndPerformMenuSelect(game);
}
}
void Menu::MenuSelect(Crawler*game){
@ -110,8 +120,8 @@ void Menu::Update(Crawler*game){
selection.y=key.first;
selection.x=index;
}
index++;
}
index++;
}
}
}
@ -161,6 +171,11 @@ void Menu::Draw(Crawler*game){
Pixel::Mode prevMode=game->GetPixelMode();
game->SetPixelMode(Pixel::MASK);
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&button:key.second){
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->SetDrawTarget(nullptr);
r.Decal()->Update();
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&button:key.second){
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()){
DrawScaledWindowBorder(game,pos);
@ -364,7 +374,9 @@ void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
}
}
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.
}
}

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

@ -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)
:parentMenu(parent),rect(rect),label(label),menuDest(menuDest),onClick(onClick),hoverEffect(0),selectable(selectable){}
void MenuComponent::AfterCreate(){}
void MenuComponent::Update(Crawler*game){
if(hovered){
hoverEffect=std::min("ThemeGlobal.HighlightTime"_F,hoverEffect+game->GetElapsedTime());

@ -27,6 +27,7 @@ protected:
virtual void Draw(Crawler*game,vf2d parentPos,bool focused);
virtual void DrawDecal(Crawler*game,vf2d parentPos,bool focused);
virtual bool GetHoverState(Crawler*game,MenuComponent*child);
virtual void AfterCreate(); //Called after the creation of all menus finish.
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,MenuType menuDest,MenuFunc onClick,bool selectable=true);

@ -9,6 +9,8 @@ class ScrollableWindowComponent:public MenuComponent{
protected:
Renderable r;
std::vector<MenuComponent*>components;
MenuComponent*upButton=nullptr;
MenuComponent*downButton=nullptr;
geom2d::rect<float>bounds; //It's for the scrollbar.
private:
inline bool OnScreen(MenuComponent*component){
@ -19,6 +21,17 @@ public:
:MenuComponent(parent,rect,"",onClick,false){
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:
virtual inline void Update(Crawler*game)override{
MenuComponent::Update(game);
@ -42,20 +55,23 @@ protected:
game->SetDrawTarget(r.Sprite());
game->Clear(BLANK);
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->DrawSprite(parentPos,r.Sprite());
}
virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{
MenuComponent::DrawDecal(game,parentPos,focused);
game->DrawRectDecal(parentPos,rect.size);
game->DrawRectDecal(rect.pos+parentPos,rect.size);
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{
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:
void inline AddComponent(Menu*parentMenu,std::string key,MenuComponent*button){

@ -1,8 +1,8 @@
#include "Crawler.h"
#include "MenuComponent.h"
Menu*Menu::InitializeTestMenu(){
Menu*testMenu=new Menu(CENTERED,{24*8,24*6});
void Menu::InitializeTestMenu(){
Menu*testMenu=CreateMenu(TEST,CENTERED,{24*8,24*6});
MenuFunc quitWindow=[](MenuFuncData data){
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));
return testMenu;
}

@ -8,8 +8,8 @@
INCLUDE_GFX
typedef Attribute A;
Menu*Menu::InitializeTestSubMenu(){
Menu*testSubMenu=new Menu({30,30},{24*4,24*5});
void Menu::InitializeTestSubMenu(){
Menu*testSubMenu=CreateMenu(TEST_2,{30,30},{24*4,24*5});
MenuFunc goBack=[](MenuFuncData data){
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));
return testSubMenu;
}

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

@ -55,7 +55,7 @@ debug_access_options = 0
debug_map_load_info = 0
# Shows extra info about the player on the HUD
debug_player_info = 0
debug_player_info = 1
# Shows collision boxes of tiles.
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

Loading…
Cancel
Save