GUI template/macro usage refactor.

pull/28/head
sigonasr2 12 months ago
parent a1caeff702
commit e744112206
  1. 3
      Crawler/CREDITS
  2. 4
      Crawler/CharacterAbilityPreviewComponent.h
  3. 36
      Crawler/CharacterInfoWindow.cpp
  4. 274
      Crawler/CharacterMenuWindow.cpp
  5. 4
      Crawler/CharacterRotatingDisplay.h
  6. 49
      Crawler/ClassSelectionWindow.cpp
  7. 6
      Crawler/Crawler.cpp
  8. 6
      Crawler/Crawler.vcxproj
  9. 9
      Crawler/Crawler.vcxproj.filters
  10. 7
      Crawler/EncountersSpawnListScrollableWindowComponent.h
  11. 4
      Crawler/EquipSlotButton.h
  12. 22
      Crawler/InventoryConsumableWindow.cpp
  13. 7
      Crawler/InventoryScrollableWindowComponent.h
  14. 49
      Crawler/InventoryWindow.cpp
  15. 25
      Crawler/ItemLoadoutWindow.cpp
  16. 48
      Crawler/LevelCompleteWindow.cpp
  17. 62
      Crawler/Menu.cpp
  18. 98
      Crawler/Menu.h
  19. 4
      Crawler/MenuAnimatedIconButton.h
  20. 4
      Crawler/MenuAnimatedIconToggleButton.h
  21. 8
      Crawler/MenuComponent.cpp
  22. 4
      Crawler/MenuComponent.h
  23. 8
      Crawler/MenuIconButton.h
  24. 6
      Crawler/MenuItemButton.h
  25. 8
      Crawler/MenuItemItemButton.h
  26. 4
      Crawler/MenuLabel.h
  27. 27
      Crawler/OverworldMapLevelWindow.cpp
  28. 24
      Crawler/OverworldMenuWindow.cpp
  29. 8
      Crawler/PopupMenuLabel.h
  30. 24
      Crawler/ScrollableWindowComponent.h
  31. 4
      Crawler/SpawnEncounterLabel.h
  32. 4
      Crawler/StatLabel.h
  33. 104
      Crawler/TestSubMenu.cpp
  34. 2
      Crawler/Version.h

@ -1,3 +1,6 @@
The inspiration that started it all, Pokemon-based Nico Yazawa sprite:
https://www.deviantart.com/kirbysmith/art/Nico-Yazawa-Love-Live-Pokemon-Sprites-548007023
*** Minifantasy - Tiny Overworld v1.0 ***
Minifantasy is an original idea by Krishna Palacio

@ -50,8 +50,8 @@ INCLUDE_GFX
class CharacterAbilityPreviewComponent:public MenuLabel{
Ability*ability;
public:
inline CharacterAbilityPreviewComponent(MenuType parent,geom2d::rect<float>rect,Ability*ability)
:MenuLabel(parent,rect,"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND),ability(ability){}
inline CharacterAbilityPreviewComponent(geom2d::rect<float>rect,Ability*ability)
:MenuLabel(rect,"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND),ability(ability){}
protected:
virtual void inline Update(Crawler*game)override{
MenuLabel::Update(game);

@ -53,39 +53,23 @@ void Menu::InitializeClassInfoWindow(){
Menu*classSelectionWindow=Menu::menus[CLASS_SELECTION];
ClassInfo data=classutils::GetClassInfo(classSelectionWindow->S(A::CLASS_SELECTION));
MenuLabel*label=NEW MenuLabel(CLASS_INFO,{{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
auto label=classInfoWindow->ADD("Class Name",MenuLabel)({{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
classInfoWindow->AddComponent("Class Name",label);
CharacterRotatingDisplay*classDisplay=NEW CharacterRotatingDisplay(CLASS_INFO,{{15,48},{72,120}},GFX[data.classFullImgName].Decal());
classInfoWindow->AddComponent("Rotating Character Display",classDisplay);
classInfoWindow->ADD("Rotating Character Display",CharacterRotatingDisplay)({{15,48},{72,120}},GFX[data.classFullImgName].Decal())END;
vf2d healthDisplayLabelPos={classInfoWindow->size.x/3,label->GetPos().y+24};
vf2d labelSize={2*classInfoWindow->size.x/3-1,16};
MenuLabel*baseStatsLabel=NEW MenuLabel(CLASS_INFO,{{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE);
MenuLabel*healthDisplayLabel=NEW MenuLabel(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE);
MenuLabel*atkDisplayLabel=NEW MenuLabel(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE);
classInfoWindow->AddComponent("Base Stats Text",baseStatsLabel);
classInfoWindow->AddComponent("Health Display Text",healthDisplayLabel);
classInfoWindow->AddComponent("Attack Display Text",atkDisplayLabel);
classInfoWindow->ADD("Base Stats Text",MenuLabel)({{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
classInfoWindow->ADD("Health Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
classInfoWindow->ADD("Attack Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
vf2d abilityIconOffsets = {0,32};
CharacterAbilityPreviewComponent*ability1=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1);
CharacterAbilityPreviewComponent*ability2=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2);
CharacterAbilityPreviewComponent*ability3=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3);
CharacterAbilityPreviewComponent*rightClickAbility=NEW CharacterAbilityPreviewComponent(CLASS_INFO,{healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility);
classInfoWindow->AddComponent("Ability 1 Display",ability1);
classInfoWindow->AddComponent("Ability 2 Display",ability2);
classInfoWindow->AddComponent("Ability 3 Display",ability3);
classInfoWindow->AddComponent("Right Click Ability Display",rightClickAbility);
MenuComponent*backButton=NEW MenuComponent(CLASS_INFO,{{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;});
classInfoWindow->ADD("Ability 1 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1)END;
classInfoWindow->ADD("Ability 2 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2)END;
classInfoWindow->ADD("Ability 3 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3)END;
classInfoWindow->ADD("Right Click Ability Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility)END;
classInfoWindow->AddComponent("Back Button",backButton);
classInfoWindow->ADD("Back Button",MenuComponent)({{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
}

@ -56,15 +56,10 @@ void Menu::InitializeCharacterMenuWindow(){
vf2d windowSize=game->GetScreenSize()-vf2d{52,52};
Menu*characterMenuWindow=CreateMenu(CHARACTER_MENU,CENTERED,windowSize);
MenuLabel*characterLabel=NEW MenuLabel(CHARACTER_MENU,{{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
characterLabel->decal=true;
MenuComponent*equipSlotOutline=NEW MenuComponent(CHARACTER_MENU,{{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
CharacterRotatingDisplay*charDisplay=NEW CharacterRotatingDisplay(CHARACTER_MENU,{{135,28},{90,windowSize.y-37}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal());
characterMenuWindow->AddComponent("Character Label",characterLabel);
characterMenuWindow->AddComponent("Equip Slot Outline",equipSlotOutline);
characterMenuWindow->AddComponent("Character Rotating Display",charDisplay);
characterMenuWindow->ADD("Character Label",MenuLabel)({{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END
->decal=true;
characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)({{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)({{135,28},{90,windowSize.y-37}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END;
const static std::array<ItemAttribute,7>displayAttrs{
ItemAttribute::health,
@ -76,33 +71,31 @@ void Menu::InitializeCharacterMenuWindow(){
ItemAttribute::critDmgPct,
};
MenuComponent*equipSelectionOutline=NEW MenuComponent(CHARACTER_MENU,{{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
ScrollableWindowComponent*equipmentList=NEW ScrollableWindowComponent(CHARACTER_MENU,{{123,28},{120,windowSize.y-37-24}});
MenuComponent*equipSelectionBottomOutline=NEW MenuComponent(CHARACTER_MENU,{{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuComponent*equipSelectionSelectButton=NEW MenuComponent(CHARACTER_MENU,{{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select",[](MenuFuncData data){
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(false);
Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(false);
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
}
equipmentWindowOpened=false;
return true;
});
equipSelectionSelectButton->decal=true;
equipSelectionOutline->Enable(false);
equipmentList->Enable(false);
equipSelectionBottomOutline->Enable(false);
equipSelectionSelectButton->Enable(false);
characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)({{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
->Enable(false);
characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)({{123,28},{120,windowSize.y-37-24}})DEPTH -1 END
->Enable(false);
characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)({{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
->Enable(false);
auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)({{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select",
[](MenuFuncData data){
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(false);
Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(false);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(false);
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
}
equipmentWindowOpened=false;
return true;
})END;
characterMenuWindow->AddComponent("Equip Selection Outline",equipSelectionOutline);
characterMenuWindow->AddComponent("Equip List",equipmentList,-1);
characterMenuWindow->AddComponent("Equip Selection Bottom Outline",equipSelectionBottomOutline);
characterMenuWindow->AddComponent("Equip Selection Select Button",equipSelectionSelectButton);
equipSelectionSelectButton->decal=true;
equipSelectionSelectButton->Enable(false);
const static auto GetLabelText=[](ItemAttribute attribute){
AttributeData data=ItemAttributable::GetDisplayInfo(attribute);
@ -126,139 +119,128 @@ void Menu::InitializeCharacterMenuWindow(){
}
const static std::array<std::string,8>slotNames{"Helmet","Weapon","Armor","Gloves","Pants","Shoes","Ring 1","Ring 2"};
EquipSlot slot=EquipSlot(equipSlot);
EquipSlotButton*equipmentSlot=NEW EquipSlotButton(CHARACTER_MENU,{{x,y+28},{24,24}},slot,MenuType::ENUM_END,
[&](MenuFuncData data){
EquipSlot slot=EquipSlot(data.component->I(Attribute::EQUIP_TYPE));
std::vector<Item>&equips=Inventory::get("Equipment");
std::vector<Item>&accessories=Inventory::get("Accessories");
std::vector<Item>availableEquipment;
std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](Item&it){
return it.GetEquipSlot()&slot;
});
std::copy_if(accessories.begin(),accessories.end(),std::back_inserter(availableEquipment),[&](Item&it){
return it.GetEquipSlot()&slot;
});
ScrollableWindowComponent*equipList=Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List");
equipList->RemoveAllComponents();
for(int counter=0;Item&it:availableEquipment){
float xOffset=(counter%3)*26;
Item&itemInvRef=Inventory::GetItem(it.Name());
MenuItemItemButton*equip=NEW MenuItemItemButton(CHARACTER_MENU,{{2+xOffset,2},{24,24}},itemInvRef,MenuType::ENUM_END,[](MenuFuncData data){
MenuItemItemButton*comp=(MenuItemItemButton*)data.component;
Inventory::EquipItem(comp->GetItem(),EquipSlot(comp->I(Attribute::EQUIP_TYPE)));
for(MenuComponent*button:((ScrollableWindowComponent*)data.parentComponent)->GetComponents()){
MenuItemItemButton*comp=(MenuItemItemButton*)button;
comp->SetSelected(false);
}
comp->SetSelected(true);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
}
MenuItemItemButton*equipButton=Component<MenuItemItemButton>(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent->I(A::INDEXED_THEME)]);
equipButton->SetItem(comp->GetItem());
return true;
},[&](MenuFuncData data){
MenuItemItemButton*button=(MenuItemItemButton*)data.component;
Item&buttonItem=button->GetItem();
std::vector<int>statsBeforeEquip;
EquipSlot slot=EquipSlot(button->I(Attribute::EQUIP_TYPE));
for(ItemAttribute attribute:displayAttrs){
statsBeforeEquip.push_back(game->GetPlayer()->GetStat(attribute));
}
Item*equippedItem=Inventory::GetEquip(slot);
Inventory::EquipItem(buttonItem,slot);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
int statChangeAmt=game->GetPlayer()->GetStat(attribute)-statsBeforeEquip[counter];
statDisplayLabel->SetStatChangeAmt(statChangeAmt);
counter++;
}
Inventory::UnequipItem(slot);
if(*equippedItem!=Item::BLANK){
Inventory::EquipItem(*equippedItem,slot);
}
return true;
},[](MenuFuncData data){
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
counter++;
auto equipmentSlot=characterMenuWindow->ADD("Equip Slot "+slotNames[i],EquipSlotButton)({{x,y+28},{24,24}},slot,MenuType::ENUM_END,
[&](MenuFuncData data){
EquipSlot slot=EquipSlot(data.component->I(Attribute::EQUIP_TYPE));
std::vector<Item>&equips=Inventory::get("Equipment");
std::vector<Item>&accessories=Inventory::get("Accessories");
std::vector<Item>availableEquipment;
std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](Item&it){
return it.GetEquipSlot()&slot;
});
std::copy_if(accessories.begin(),accessories.end(),std::back_inserter(availableEquipment),[&](Item&it){
return it.GetEquipSlot()&slot;
});
ScrollableWindowComponent*equipList=Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List");
equipList->RemoveAllComponents();
for(int counter=0;Item&it:availableEquipment){
float xOffset=(counter%3)*26;
Item&itemInvRef=Inventory::GetItem(it.Name());
auto equip=equipList->ADD("Equip Item "+std::to_string(counter),MenuItemItemButton)({{2+xOffset,2},{24,24}},itemInvRef,MenuType::ENUM_END,
[](MenuFuncData data){
MenuItemItemButton*comp=(MenuItemItemButton*)data.component;
Inventory::EquipItem(comp->GetItem(),EquipSlot(comp->I(Attribute::EQUIP_TYPE)));
for(MenuComponent*button:((ScrollableWindowComponent*)data.parentComponent)->GetComponents()){
MenuItemItemButton*comp=(MenuItemItemButton*)button;
comp->SetSelected(false);
}
comp->SetSelected(true);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
}
MenuItemItemButton*equipButton=Component<MenuItemItemButton>(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent->I(A::INDEXED_THEME)]);
equipButton->SetItem(comp->GetItem());
return true;
},[&](MenuFuncData data){
MenuItemItemButton*button=(MenuItemItemButton*)data.component;
Item&buttonItem=button->GetItem();
std::vector<int>statsBeforeEquip;
EquipSlot slot=EquipSlot(button->I(Attribute::EQUIP_TYPE));
for(ItemAttribute attribute:displayAttrs){
statsBeforeEquip.push_back(game->GetPlayer()->GetStat(attribute));
}
Item*equippedItem=Inventory::GetEquip(slot);
Inventory::EquipItem(buttonItem,slot);
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
int statChangeAmt=game->GetPlayer()->GetStat(attribute)-statsBeforeEquip[counter];
statDisplayLabel->SetStatChangeAmt(statChangeAmt);
counter++;
}
Inventory::UnequipItem(slot);
if(*equippedItem!=Item::BLANK){
Inventory::EquipItem(*equippedItem,slot);
}
return true;
},[](MenuFuncData data){
for(int counter=0;ItemAttribute attribute:displayAttrs){
StatLabel*statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label");
statDisplayLabel->SetStatChangeAmt(0);
counter++;
}
return true;
},"Item Name","Item Description")END;
equip->I(Attribute::EQUIP_TYPE)=int(slot);
if(Inventory::GetEquip(slot)==&itemInvRef){
equip->SetSelected(true);
}
return true;
},"Item Name","Item Description");
equip->I(Attribute::EQUIP_TYPE)=int(slot);
if(Inventory::GetEquip(slot)==&itemInvRef){
equip->SetSelected(true);
equip->SetCompactDescriptions(false);
counter++;
}
equip->SetCompactDescriptions(false);
equipList->AddComponent(Menu::menus[CHARACTER_MENU],"Equip Item "+std::to_string(counter),equip);
counter++;
}
equipList->I(Attribute::INDEXED_THEME)=data.component->I(Attribute::INDEXED_THEME);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(true);
equipList->Enable(true);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(true);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(true);
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(false);
equipmentWindowOpened=true;
return true;
},[](MenuFuncData data){//On Mouse Hover
if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""){
equipList->I(Attribute::INDEXED_THEME)=data.component->I(Attribute::INDEXED_THEME);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(true);
equipList->Enable(true);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(true);
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Select Button")->Enable(true);
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(false);
}
return true;
},[](MenuFuncData data){//On Mouse Out
if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""&&!equipmentWindowOpened){
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true);
}
return true;
},"Item Equip Name","Item Equip Description");
PopupMenuLabel*equipmentLabel=NEW PopupMenuLabel(CHARACTER_MENU,{{labelX,labelY},{29,16}},slotNames[i],{0.5,1},ComponentAttr::SHADOW);
equipmentWindowOpened=true;
return true;
},[](MenuFuncData data){//On Mouse Hover
if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""){
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(false);
}
return true;
},[](MenuFuncData data){//On Mouse Out
if(Component<MenuLabel>(data.component->parentMenu,"Item Equip Description")->GetLabel()!=""&&!equipmentWindowOpened){
Component<CharacterRotatingDisplay>(data.component->parentMenu,"Character Rotating Display")->Enable(true);
}
return true;
},"Item Equip Name","Item Equip Description")END;
equipmentSlot->I(Attribute::EQUIP_TYPE)=int(slot);
equipmentSlot->I(Attribute::INDEXED_THEME)=i;
equipmentSlot->SetShowQuantity(false);
equipmentSlot->SetCompactDescriptions(false);
equipSlot<<=1;
characterMenuWindow->AddComponent("Equip Slot "+slotNames[i],equipmentSlot);
characterMenuWindow->AddComponent("Equip Label "+slotNames[i],equipmentLabel);
characterMenuWindow->ADD("Equip Label "+slotNames[i],PopupMenuLabel)({{labelX,labelY},{29,16}},slotNames[i],{0.5,1},ComponentAttr::SHADOW)END;
Menu::AddEquipStatListener(equipmentSlot);
}
MenuComponent*statDisplayOutline=NEW MenuComponent(CHARACTER_MENU,{{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
characterMenuWindow->AddComponent("Stat Display Outline",statDisplayOutline);
characterMenuWindow->ADD("Stat Display Outline",MenuComponent)({{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
int yOffset=0;
for(ItemAttribute attribute:displayAttrs){
std::string attrStr=GetLabelText(attribute);
StatLabel*attrLabel=NEW StatLabel(CHARACTER_MENU,{{245,28+2+float(yOffset)},{62,18}},attribute,1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
yOffset+=20;
AttributeData data=ItemAttributable::GetDisplayInfo(attribute);
characterMenuWindow->AddComponent("Attribute "+data.name+" Label",attrLabel);
auto attrLabel=characterMenuWindow->ADD("Attribute "+data.name+" Label",StatLabel)({{245,28+2+float(yOffset)},{62,18}},attribute,1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
Menu::AddEquipStatListener(attrLabel);
yOffset+=20;
}
MenuComponent*backButton=NEW MenuComponent(CHARACTER_MENU,{{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;});
backButton->decal=true;
characterMenuWindow->AddComponent("Back button",backButton);
characterMenuWindow->ADD("Back button",MenuComponent)({{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END
->decal=true;
MenuLabel*itemNameDisplay=NEW MenuLabel(CHARACTER_MENU,{{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW);
MenuLabel*itemDescriptionDisplay=NEW MenuLabel(CHARACTER_MENU,{{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW);
auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)({{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
auto itemDescriptionDisplay=characterMenuWindow->ADD("Item Description",MenuLabel)({{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
characterMenuWindow->ADD("Item Equip Name",MenuLabel)({{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
characterMenuWindow->ADD("Item Equip Description",MenuLabel)({{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
itemNameDisplay->decal=true;
itemDescriptionDisplay->decal=true;
itemNameDisplay->decal=itemDescriptionDisplay->decal=true;
itemNameDisplay->Enable(false);
itemDescriptionDisplay->Enable(false);
MenuLabel*itemNameDisplayEquip=NEW MenuLabel(CHARACTER_MENU,{{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW);
MenuLabel*itemDescriptionDisplayEquip=NEW MenuLabel(CHARACTER_MENU,{{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW);
characterMenuWindow->AddComponent("Item Name",itemNameDisplay);
characterMenuWindow->AddComponent("Item Description",itemDescriptionDisplay);
characterMenuWindow->AddComponent("Item Equip Name",itemNameDisplayEquip);
characterMenuWindow->AddComponent("Item Equip Description",itemDescriptionDisplayEquip);
}

@ -49,8 +49,8 @@ protected:
float rotatingFactor=7;
float perspectiveFactor=6;
public:
inline CharacterRotatingDisplay(MenuType parent,geom2d::rect<float>rect,Decal*icon)
:MenuComponent(parent,rect,"",DO_NOTHING),icon(icon){}
inline CharacterRotatingDisplay(geom2d::rect<float>rect,Decal*icon)
:MenuComponent(rect,"",DO_NOTHING),icon(icon){}
inline void SetIcon(Decal*icon){
this->icon=icon;
}

@ -53,25 +53,21 @@ void Menu::InitializeClassSelectionWindow(){
vf2d outlineSize=classSelectionWindow->size-vf2d{13,13};
MenuLabel*classSelectionLabel=NEW MenuLabel(CLASS_SELECTION,{{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
classSelectionWindow->AddComponent("Class Selection Title Label",classSelectionLabel);
classSelectionWindow->ADD("Class Selection Title Label",MenuLabel)({{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
MenuLabel*outline=NEW MenuLabel(CLASS_SELECTION,{{4,4},outlineSize},"",1,ComponentAttr::OUTLINE);
classSelectionWindow->AddComponent("Outline Border",outline);
auto outline=classSelectionWindow->ADD("Outline Border",MenuLabel)({{4,4},outlineSize},"",1,ComponentAttr::OUTLINE)END;
vf2d navigationButtonSize={24*2.5f,16};
MenuComponent*backButton=NEW MenuComponent(CLASS_SELECTION,{{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;});
classSelectionWindow->AddComponent("Back Button",backButton);
MenuComponent*confirmButton=NEW MenuComponent(CLASS_SELECTION,{{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){
classSelectionWindow->ADD("Back Button",MenuComponent)({{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
classSelectionWindow->ADD("Confirm",MenuComponent)({{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){
std::string selectedClass=data.component->S(A::CLASS_SELECTION);
data.game->ChangePlayerClass(classutils::StringToClass(selectedClass));
GameState::ChangeState(States::OVERWORLD_MAP);
return true;
});
confirmButton->disabled=true;
classSelectionWindow->AddComponent("Confirm",confirmButton);
})END
->disabled=true;
vf2d buttonPadding={2,2};
vf2d buttonSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/9-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug.
@ -111,26 +107,27 @@ void Menu::InitializeClassSelectionWindow(){
buttonStartPos.y+(buttonSize.y+buttonPadding.y+2*outlineSize.y/9)*float(i/3),
};
vf2d backgroundSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/3-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug.
MenuLabel*backgroundOutline=NEW MenuLabel(CLASS_SELECTION,{backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
MenuLabel*classLabel=NEW MenuLabel(CLASS_SELECTION,{backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW);
MenuAnimatedIconToggleButton*classSprite=NEW MenuAnimatedIconToggleButton(CLASS_SELECTION,{backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){
data.menu.components["Confirm"]->Enable(true);
data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
return true;
});
toggleGroup.push_back(classSprite);
MenuComponent*classButton=NEW MenuComponent(CLASS_SELECTION,{offsetPos,buttonSize},"Info",CLASS_INFO,
classSelectionWindow->ADD(className+" Background",MenuLabel)({backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
classSelectionWindow->ADD(className+" Button",MenuComponent)({offsetPos,buttonSize},"Info",CLASS_INFO,
[](MenuFuncData data){
data.menu.S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
delete Menu::menus[CLASS_INFO];
Menu::InitializeClassInfoWindow();
return true;
});
classSprite->S(A::CLASS_SELECTION)=classButton->S(A::CLASS_SELECTION)=className;
classSelectionWindow->AddComponent(className+" Background",backgroundOutline);
classSelectionWindow->AddComponent(className+" Button",classButton);
classSelectionWindow->AddComponent(className+" Label",classLabel);
classSelectionWindow->AddComponent(className+" Icon",classSprite);
})END
->S(A::CLASS_SELECTION)=className;
classSelectionWindow->ADD(className+" Label",MenuLabel)({backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW)END;
auto classSprite=classSelectionWindow->ADD(className+" Icon",MenuAnimatedIconToggleButton)({backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){
data.menu.components["Confirm"]->Enable(true);
data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
return true;
})END;
classSprite->S(A::CLASS_SELECTION)=className;
toggleGroup.push_back(classSprite);
}
for(IToggleable*item:toggleGroup){

@ -445,7 +445,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
}
if(GetKey(I).bPressed){
Menu::OpenMenu(INVENTORY);
Menu::OpenMenu(INVENTORY_CONSUMABLES);
}
if(GetKey(O).bPressed){
ItemDrop::SpawnItem(&ITEM_DATA.at("Green Slime Remains"),player->GetPos(),player->OnUpperLevel());
@ -1232,8 +1232,8 @@ void Crawler::RenderHud(){
DrawShadowStringDecal({0,128},player->GetPos().str());
DrawShadowStringDecal({0,136},"Spd: "+std::to_string(player->GetMoveSpdMult()));
DrawShadowStringDecal({0,92},"Loadout Slot 1 Qty: "+std::to_string(GetLoadoutItem(0).Amt()));
DrawShadowStringDecal({0,1},"Selection: "+Menu::menus[INVENTORY]->selection.str());
DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY]->buttonHoldTime));
DrawShadowStringDecal({0,1},"Selection: "+Menu::menus[INVENTORY_CONSUMABLES]->selection.str());
DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY_CONSUMABLES]->buttonHoldTime));
}}
void Crawler::RenderCooldowns(){

@ -411,6 +411,10 @@
<ClCompile Include="FireBolt.cpp" />
<ClCompile Include="GameState.cpp" />
<ClCompile Include="InventoryConsumableWindow.cpp" />
<ClCompile Include="InventoryWindow.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Item.cpp" />
<ClCompile Include="ItemDrop.cpp" />
<ClCompile Include="ItemLoadoutWindow.cpp" />
@ -450,8 +454,6 @@
<ClCompile Include="State_OverworldMap.cpp" />
<ClCompile Include="State_Story.cpp" />
<ClCompile Include="Test.cpp" />
<ClCompile Include="TestMenu.cpp" />
<ClCompile Include="TestSubMenu.cpp" />
<ClCompile Include="Thief.cpp" />
<ClCompile Include="Trapper.cpp" />
<ClCompile Include="Turret.cpp" />

@ -410,12 +410,6 @@
<ClCompile Include="MenuComponent.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
<ClCompile Include="TestMenu.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
<ClCompile Include="TestSubMenu.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
<ClCompile Include="State_GameRun.cpp">
<Filter>Source Files\Game States</Filter>
</ClCompile>
@ -491,6 +485,9 @@
<ClCompile Include="AttributableStat.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="InventoryWindow.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

@ -50,8 +50,8 @@ INCLUDE_LEVEL_NAMES
class EncountersSpawnListScrollableWindowComponent:public ScrollableWindowComponent{
protected:
public:
inline EncountersSpawnListScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(parent,rect,attributes){}
inline EncountersSpawnListScrollableWindowComponent(geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(rect,attributes){}
virtual inline void UpdateSpawns(std::vector<int>&spawns){
Menu::menus.at(parentMenu)->components.erase_if([&](auto key){
if(key.first.starts_with("Spawn ")){
@ -64,8 +64,7 @@ public:
vf2d parentPos=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->pos;
vf2d parentSize=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->size;
for(int spawn:spawns){
SpawnEncounterLabel*spawnLabel=NEW SpawnEncounterLabel(OVERWORLD_LEVEL_SELECT,{vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn-1).GetDisplayName(),spawn-1);
AddComponent(Menu::menus.at(OVERWORLD_LEVEL_SELECT),"Spawn "+std::to_string(spawn),spawnLabel);
ADD("Spawn "+std::to_string(spawn),SpawnEncounterLabel)({vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn-1).GetDisplayName(),spawn-1)END;
offsetY+=14;
}
}

@ -47,8 +47,8 @@ class EquipSlotButton:public MenuItemItemButton{
private:
EquipSlot slot;
public:
inline EquipSlotButton(MenuType parent,geom2d::rect<float>rect,EquipSlot slot,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="")
:MenuItemItemButton(parent,rect,Item::BLANK,menuDest,onClick,onHover,onMouseOut,itemNameLabelName,itemDescriptionLabelName),slot(slot){}
inline EquipSlotButton(geom2d::rect<float>rect,EquipSlot slot,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="")
:MenuItemItemButton(rect,Item::BLANK,menuDest,onClick,onHover,onMouseOut,itemNameLabelName,itemDescriptionLabelName),slot(slot){}
inline void OnEquipStatsUpdate()override{
Item&equip=*Inventory::GetEquip(slot);
if(!equip.IsBlank()){

@ -55,11 +55,11 @@ void Menu::InitializeConsumableInventoryWindow(){
vf2d windowSize={float(totalSpacing*invWidth-itemSpacing+2+24),float(totalSpacing*(3+1)-itemSpacing+64)}; //Need space for the button.
Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,windowSize);
Menu*inventoryWindow=CreateMenu(INVENTORY_CONSUMABLES,CENTERED,windowSize);
inventoryWindow->I(A::LOADOUT_SLOT)=0;
InventoryScrollableWindowComponent*inventory=NEW InventoryScrollableWindowComponent(INVENTORY,{{1,20},{windowSize.x,float(totalSpacing*3-itemSpacing)}},"Consumables","itemName","itemDescription",
inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{1,20},{windowSize.x,float(totalSpacing*3-itemSpacing)}},"Consumables","itemName","itemDescription",
[&](MenuFuncData data){
MenuItemButton*button=(MenuItemButton*)data.component;
data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT));
@ -80,21 +80,13 @@ void Menu::InitializeConsumableInventoryWindow(){
button->selected=data.menu.I(A::LOADOUT_SLOT);
data.game->SetLoadoutItem(button->selected,button->GetItem().Name());
return true;
});
inventoryWindow->AddComponent("inventory",inventory);
})END;
//We don't have to actually populate the inventory list because now when an item gets added, it will automatically add the correct component in for us.
MenuLabel*inventoryTypeLabel=NEW MenuLabel(INVENTORY,{{0,0},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE);
inventoryWindow->AddComponent("Inventory Type Label",inventoryTypeLabel);
MenuLabel*itemNameLabel=NEW MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,float(initialInvHeight*totalSpacing+itemSpacing-16)},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW};
inventoryWindow->AddComponent("itemName",itemNameLabel);
inventoryWindow->ADD("Inventory Type Label",MenuLabel)({{0,0},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
inventoryWindow->ADD("itemName",MenuLabel)(geom2d::rect<float>(vf2d{2,float(initialInvHeight*totalSpacing+itemSpacing-16)},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END;
float itemDescriptionLabelY=float(initialInvHeight*totalSpacing+itemSpacing);
MenuLabel*itemDescriptionLabel=NEW MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,itemDescriptionLabelY},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW};
inventoryWindow->AddComponent("itemDescription",itemDescriptionLabel);
MenuComponent*okButton=NEW MenuComponent(INVENTORY,{{windowSize.x/2-24,itemDescriptionLabelY+56},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;});
inventoryWindow->ADD("itemDescription",MenuLabel)(geom2d::rect<float>(vf2d{2,itemDescriptionLabelY},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END;
inventoryWindow->AddComponent("OK Button",okButton);
inventoryWindow->ADD("OK Button",MenuComponent)({{windowSize.x/2-24,itemDescriptionLabelY+56},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
}

@ -53,8 +53,8 @@ private:
protected:
ITCategory inventoryType;
public:
inline InventoryScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ITCategory invType,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(parent,rect,attributes),inventoryType(invType),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),
inline InventoryScrollableWindowComponent(geom2d::rect<float>rect,ITCategory invType,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(rect,attributes),inventoryType(invType),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),
inventoryButtonClickAction(inventoryButtonClickAction),inventoryButtonsActive(inventoryButtonsActive){
Menu::AddInventoryListener(this,invType);
}
@ -105,8 +105,7 @@ protected:
int buttonSize="ThemeGlobal.InventoryButtonSize"_I;
int totalSpacing="ThemeGlobal.InventoryItemSpacing"_I+buttonSize;
MenuItemButton*button=NEW MenuItemButton{parentMenu,{{float(totalSpacing*x),float(totalSpacing*y)},{float(buttonSize),float(buttonSize)}},Inventory::get(cat),itemIndex,inventoryButtonClickAction,parentMenu,itemNameLabelName,itemDescriptionLabelName,inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE};
AddComponent(Menu::menus[parentMenu],"item_"+cat+"_"+std::to_string(itemIndex),button);
ADD("item_"+cat+"_"+std::to_string(itemIndex),MenuItemButton)({{float(totalSpacing*x),float(totalSpacing*y)},{float(buttonSize),float(buttonSize)}},Inventory::get(cat),itemIndex,inventoryButtonClickAction,parentMenu,itemNameLabelName,itemDescriptionLabelName,inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE)END;
}else
if(components.size()>invSize){ //There are empty spots, so let's clean up.
RemoveEmptySlots();

@ -30,35 +30,32 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2023 The FreeType
Portions of this software are copyright © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "Crawler.h"
#include "MenuComponent.h"
void Menu::InitializeTestMenu(){
Menu*testMenu=CreateMenu(TEST,CENTERED,{24*8,24*6});
MenuFunc quitWindow=[](MenuFuncData data){
data.menu.stack.clear();
return true;
};
testMenu->AddComponent("Close",NEW MenuComponent(TEST,{{24*1,24*1},{24*2,24*1}},"Close",quitWindow));
MenuFunc doNothing=[](MenuFuncData data){return true;};
testMenu->AddComponent("Test",NEW MenuComponent(TEST,{{24*4,24*1},{24*3,24*1}},"Test",doNothing));
MenuFunc HurtPlayer=[](MenuFuncData data){
data.game->GetPlayer()->Hurt(20,data.game->GetPlayer()->OnUpperLevel(),data.game->GetPlayer()->GetZ());
return true;
};
testMenu->AddComponent("Hurt Player",NEW MenuComponent(TEST,{{24*4,24*3},{24*3,24*1}},"Hurt Player",HurtPlayer));
testMenu->AddComponent("Open SubMenu",NEW MenuComponent(TEST,{{24*2,24*4.5},{24*4,24*1}},"Open Another\n Menu",TEST_2,doNothing));
#include "DEFINES.h"
#include "Menu.h"
#include "MenuLabel.h"
INCLUDE_game
using A=Attribute;
using enum ComponentAttr;
using ButtonAttr::UNSELECTABLE;
using ButtonAttr::UNSELECTABLE_VIA_KEYBOARD;
struct testStruct{
int val1;
int val2;
int val3;
testStruct(int val1,int val2,int val3){};
};
void Menu::InitializeInventoryWindow(){
Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,game->GetScreenSize()-vi2d{52,52});
inventoryWindow->ADD("Inventory Label",MenuLabel)({{0,0},{inventoryWindow->size.x-1,24}},"Inventory",2,SHADOW|OUTLINE|BACKGROUND)END;
inventoryWindow->ADD("Inventory Tabs",MenuComponent)({{0,28},{72,inventoryWindow->size.x-44}},"",DO_NOTHING,UNSELECTABLE)END;
}

@ -51,28 +51,17 @@ void Menu::InitializeItemLoadoutWindow(){
float itemLoadoutWindowWidth=(game->GetScreenSize().x-5.f);
MenuLabel*loadoutLabel=NEW MenuLabel(ITEM_LOADOUT,{{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE);
itemLoadoutWindow->AddComponent("Loadout Label",loadoutLabel);
itemLoadoutWindow->ADD("Loadout Label",MenuLabel)({{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
float buttonBorderPadding=64;
MenuItemItemButton*loadoutItem1=NEW MenuItemItemButton(ITEM_LOADOUT,{{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY,[](MenuFuncData data){Menu::menus.at(INVENTORY)->I(A::LOADOUT_SLOT)=0; return true;},"Item Name Label","Item Description");
MenuItemItemButton*loadoutItem2=NEW MenuItemItemButton(ITEM_LOADOUT,{{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY,[](MenuFuncData data){Menu::menus.at(INVENTORY)->I(A::LOADOUT_SLOT)=1;return true;},"Item Name Label","Item Description");
MenuItemItemButton*loadoutItem3=NEW MenuItemItemButton(ITEM_LOADOUT,{{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY,[](MenuFuncData data){Menu::menus.at(INVENTORY)->I(A::LOADOUT_SLOT)=2;return true;},"Item Name Label","Item Description");
//TODO: Make these two do something.
MenuLabel*itemNameLabel=NEW MenuLabel(ITEM_LOADOUT,{{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW);
MenuLabel*itemDescription=NEW MenuLabel(ITEM_LOADOUT,{{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW);
itemLoadoutWindow->AddComponent("Loadout Item 1",loadoutItem1);
itemLoadoutWindow->AddComponent("Loadout Item 2",loadoutItem2);
itemLoadoutWindow->AddComponent("Loadout Item 3",loadoutItem3);
itemLoadoutWindow->ADD("Loadout Item 1",MenuItemItemButton)({{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=0; return true;},"Item Name Label","Item Description")END;
itemLoadoutWindow->ADD("Loadout Item 2",MenuItemItemButton)({{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=1;return true;},"Item Name Label","Item Description")END;
itemLoadoutWindow->ADD("Loadout Item 3",MenuItemItemButton)({{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=2;return true;},"Item Name Label","Item Description")END;
itemLoadoutWindow->AddComponent("Item Name Label",itemNameLabel);
itemLoadoutWindow->AddComponent("Item Description",itemDescription);
itemLoadoutWindow->ADD("Item Name Label",MenuLabel)({{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW)END;
itemLoadoutWindow->ADD("Item Description",MenuLabel)({{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW)END;
MenuComponent*startLevelButton=NEW MenuComponent(ITEM_LOADOUT,{{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;});
itemLoadoutWindow->AddComponent("Start Level Button",startLevelButton);
itemLoadoutWindow->ADD("Start Level Button",MenuComponent)({{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END;
}

@ -51,25 +51,15 @@ void Menu::InitializeLevelCompleteWindow(){
Menu*levelCompleteWindow=Menu::CreateMenu(LEVEL_COMPLETE,windowSize.pos,windowSize.size);
MenuLabel*stageCompleteLabel=NEW MenuLabel(LEVEL_COMPLETE,{{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW);
levelCompleteWindow->ADD("Stage Complete Label",MenuLabel)({{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW)END;
levelCompleteWindow->AddComponent("Stage Complete Label",stageCompleteLabel);
levelCompleteWindow->ADD("Monster Loot Outline",MenuComponent)({{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
levelCompleteWindow->ADD("Monster Loot Label",MenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)({{0,44},{windowSize.size.x-80.f,60}},"Monster Loot","Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING)END;
MenuComponent*monsterLootOutline=NEW MenuComponent(LEVEL_COMPLETE,{{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuLabel*monsterLootLabel=NEW MenuLabel(LEVEL_COMPLETE,{{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE);
InventoryScrollableWindowComponent*monsterLootWindow=NEW InventoryScrollableWindowComponent(LEVEL_COMPLETE,{{0,44},{windowSize.size.x-80.f,60}},"Monster Loot","Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING);
levelCompleteWindow->AddComponent("Monster Loot Outline",monsterLootOutline);
levelCompleteWindow->AddComponent("Monster Loot Label",monsterLootLabel);
levelCompleteWindow->AddComponent("Monster Loot Window",monsterLootWindow);
MenuComponent*stageLootOutline=NEW MenuComponent(LEVEL_COMPLETE,{{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuLabel*stageLootLabel=NEW MenuLabel(LEVEL_COMPLETE,{{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE);
InventoryScrollableWindowComponent*stageLootWindow=NEW InventoryScrollableWindowComponent(LEVEL_COMPLETE,{{0,120},{windowSize.size.x-80.f,60}},"Stage Loot","Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING);
levelCompleteWindow->AddComponent("Stage Loot Outline",stageLootOutline);
levelCompleteWindow->AddComponent("Stage Loot Label",stageLootLabel);
levelCompleteWindow->AddComponent("Stage Loot Window",stageLootWindow);
levelCompleteWindow->ADD("Stage Loot Outline",MenuComponent)({{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
levelCompleteWindow->ADD("Stage Loot Label",MenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)({{0,120},{windowSize.size.x-80.f,60}},"Stage Loot","Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING)END;
auto nextButtonAction=[](MenuFuncData data){
Unlock::UnlockArea(State_OverworldMap::GetCurrentConnectionPoint().map);
@ -77,23 +67,13 @@ void Menu::InitializeLevelCompleteWindow(){
return true;
};
MenuComponent*detailsOutline=NEW MenuComponent(LEVEL_COMPLETE,{{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuLabel*detailsExpGain=NEW MenuLabel(LEVEL_COMPLETE,{{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
MenuComponent*nextButton=NEW MenuComponent(LEVEL_COMPLETE,{{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction);
levelCompleteWindow->AddComponent("Level Details Outline",detailsOutline);
levelCompleteWindow->AddComponent("Level EXP Gain Outline",detailsExpGain);
levelCompleteWindow->AddComponent("Next Button",nextButton);
PopupMenuLabel*monsterLootPopupItemName=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
PopupMenuLabel*monsterLootPopupItemDescription=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
levelCompleteWindow->AddComponent("Monster Loot Popup Item Name",monsterLootPopupItemName);
levelCompleteWindow->AddComponent("Monster Loot Popup Item Description",monsterLootPopupItemDescription);
levelCompleteWindow->ADD("Level Details Outline",MenuComponent)({{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
levelCompleteWindow->ADD("Level EXP Gain Outline",MenuLabel)({{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
levelCompleteWindow->ADD("Next Button",MenuComponent)({{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction)END;
PopupMenuLabel*stageLootPopupItemName=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
PopupMenuLabel*stageLootPopupItemDescription=NEW PopupMenuLabel(LEVEL_COMPLETE,{{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
levelCompleteWindow->ADD("Monster Loot Popup Item Name",PopupMenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
levelCompleteWindow->ADD("Monster Loot Popup Item Description",PopupMenuLabel)({{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
levelCompleteWindow->AddComponent("Stage Loot Popup Item Name",stageLootPopupItemName);
levelCompleteWindow->AddComponent("Stage Loot Popup Item Description",stageLootPopupItemDescription);
levelCompleteWindow->ADD("Stage Loot Popup Item Name",PopupMenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
levelCompleteWindow->ADD("Stage Loot Popup Item Description",PopupMenuLabel)({{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
}

@ -86,9 +86,8 @@ Menu::~Menu(){
}
void Menu::InitializeMenus(){
stack.reserve(32);
InitializeTestMenu();
InitializeTestSubMenu();
#define MAX_MENUS 32
stack.reserve(MAX_MENUS);
InitializeConsumableInventoryWindow();
InitializeClassSelectionWindow();
InitializeClassInfoWindow();
@ -98,8 +97,9 @@ void Menu::InitializeMenus(){
InitializeLevelCompleteWindow();
InitializeOverworldMenuWindow();
InitializeCharacterMenuWindow();
InitializeInventoryWindow();
for(MenuType type=TEST;type<MenuType::ENUM_END;type=MenuType(int(type+1))){
for(MenuType type=MenuType(int(MenuType::ENUM_START)+1);type<MenuType::ENUM_END;type=MenuType(int(type+1))){
if(menus.count(type)==0){
ERR("WARNING! Menu Type "<<type<<" does not exist!")
}
@ -110,6 +110,7 @@ void Menu::InitializeMenus(){
MenuComponent*component=value;
component->AfterCreate();
}
if(menus.size()>MAX_MENUS)ERR("WARNING! Exceeded maximum expected menu count of "<<MAX_MENUS<<"!");
}
if(Menu::unhandledComponents.size()>0){
@ -128,62 +129,11 @@ void Menu::InitializeMenus(){
Menu*Menu::CreateMenu(MenuType type,vf2d pos,vf2d size){
menus[type]=NEW Menu(pos,size);
menus[type]->type=type;
lastMenuTypeCreated=type;
return menus.at(type);
}
void Menu::AddComponent(std::string key,MenuComponent*button,int depth){
if(depth==DEFAULT_DEPTH){
button->depth=STARTING_DEPTH-componentCount;
}else{
button->depth=depth;
}
if(button->selectable){
buttons.Unlock();
if(buttons.count(int(button->rect.pos.y))){
buttons.at(int(button->rect.pos.y)).push_back(button);
}else{
buttons[int(button->rect.pos.y)].push_back(button);
}
if(button->selectableViaKeyboard){
keyboardButtons.Unlock();
if(keyboardButtons.count(int(button->rect.pos.y))){
keyboardButtons.at(int(button->rect.pos.y)).push_back(button);
}else{
keyboardButtons[int(button->rect.pos.y)].push_back(button);
}
}
//We must lock the values before calling sort. Sort seems to try and create new accesses.
buttons.SetInitialized();
keyboardButtons.SetInitialized();
//We make an assumption that menu components are supposed to be in left-to-right order. Sometimes we may add things out-of-order, so this fixes the problem by sorting the items afterwards.
std::sort(buttons[int(button->rect.pos.y)].begin(),buttons[int(button->rect.pos.y)].end(),[](MenuComponent*c1,MenuComponent*c2){
return c1->GetPos().x<c2->GetPos().x;
});
if(keyboardButtons.count(int(button->rect.pos.y))){ //Keyboard buttons may not necessarily contain this key...Let's be sure.
std::sort(keyboardButtons[int(button->rect.pos.y)].begin(),keyboardButtons[int(button->rect.pos.y)].end(),[](MenuComponent*c1,MenuComponent*c2){
return c1->GetPos().x<c2->GetPos().x;
});
}
}else{
displayComponents.push_back(button);
}
RecalculateComponentCount();
if(components.count(key)){
ERR("WARNING! Key "<<key<<" for this sub-menu already exists! Key names must be unique!")
}
button->name=key;
components.Unlock(); //It's possible we can add a component later on, so we will make sure we remove the lock first.
components[key]=button;
components.SetInitialized();
lastRegisteredComponent=key;
std::erase_if(Menu::unhandledComponents,[&](MenuComponent*b1){return b1==button;});
}
void Menu::CheckClickAndPerformMenuSelect(Crawler*game){
if(game->GetMouse(Mouse::LEFT).bReleased||game->GetKey(SPACE).bReleased||game->GetKey(ENTER).bReleased){
MenuSelect(game);

@ -47,13 +47,21 @@ class Crawler;
class MenuComponent;
class ScrollableWindowComponent;
//Add a component to a menu using this macro. Follow-up with END at the end of it.
#define ADD(key,componentType) AddComponent<componentType>(key,NEW componentType
#define END )
#define DEPTH ,
#define DEFAULT_DEPTH -999999
#define STARTING_DEPTH 999999
enum MenuType{
TEST,
TEST_2,
INVENTORY,
#pragma region Enum Start //DO NOT REMOVE
///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_START,///////////////////////////////
///////////////////////////////////////////////////////////
#pragma endregion
INVENTORY_CONSUMABLES,
CLASS_INFO,
CLASS_SELECTION,
MAIN_MENU,
@ -62,12 +70,26 @@ enum MenuType{
LEVEL_COMPLETE,
OVERWORLD_MENU,
CHARACTER_MENU,
INVENTORY,
#pragma region Enum End //DO NOT REMOVE
///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_END////////////////////////////////
///////////////////////////////////////////////////////////
#pragma endregion
};
class Menu:public IAttributable{
static void InitializeConsumableInventoryWindow();
static void InitializeClassInfoWindow();
static void InitializeClassSelectionWindow();
static void InitializeMainMenuWindow();
static void InitializeOverworldMapLevelWindow();
static void InitializeItemLoadoutWindow();
static void InitializeLevelCompleteWindow();
static void InitializeOverworldMenuWindow();
static void InitializeCharacterMenuWindow();
static void InitializeInventoryWindow();
friend class Crawler;
friend struct Player;
friend class ItemInfo;
@ -86,7 +108,62 @@ public:
//The constructor is private. Use CreateMenu() instead!
Menu()=default;
~Menu();
void AddComponent(std::string key,MenuComponent*button,int depth=DEFAULT_DEPTH);
//DO NOT USE DIRECTLY! You should be utilizing the ADD macro for adding components.
template<class T>
T*AddComponent(std::string componentKey,T*component,int depth=DEFAULT_DEPTH){
component->parentMenu=type;
if(depth==DEFAULT_DEPTH){
component->depth=STARTING_DEPTH-componentCount;
}else{
component->depth=depth;
}
if(component->selectable){
buttons.Unlock();
if(buttons.count(int(component->rect.pos.y))){
buttons.at(int(component->rect.pos.y)).push_back(component);
}else{
buttons[int(component->rect.pos.y)].push_back(component);
}
if(component->selectableViaKeyboard){
keyboardButtons.Unlock();
if(keyboardButtons.count(int(component->rect.pos.y))){
keyboardButtons.at(int(component->rect.pos.y)).push_back(component);
}else{
keyboardButtons[int(component->rect.pos.y)].push_back(component);
}
}
//We must lock the values before calling sort. Sort seems to try and create new accesses.
buttons.SetInitialized();
keyboardButtons.SetInitialized();
//We make an assumption that menu components are supposed to be in left-to-right order. Sometimes we may add things out-of-order, so this fixes the problem by sorting the items afterwards.
std::sort(buttons[int(component->rect.pos.y)].begin(),buttons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){
return c1->GetPos().x<c2->GetPos().x;
});
if(keyboardButtons.count(int(component->rect.pos.y))){ //Keyboard buttons may not necessarily contain this key...Let's be sure.
std::sort(keyboardButtons[int(component->rect.pos.y)].begin(),keyboardButtons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){
return c1->GetPos().x<c2->GetPos().x;
});
}
}else{
displayComponents.push_back(component);
}
RecalculateComponentCount();
if(components.count(componentKey)){
ERR("WARNING! Key "<<componentKey<<" for this sub-menu already exists! Key names must be unique!")
}
component->name=componentKey;
components.Unlock(); //It's possible we can add a component later on, so we will make sure we remove the lock first.
components[componentKey]=component;
components.SetInitialized();
lastRegisteredComponent=componentKey;
std::erase_if(Menu::unhandledComponents,[&](auto b1){return b1==component;});
return component;
}
void Update(Crawler*game);
void Draw(Crawler*game);
static void InitializeMenus();
@ -134,18 +211,6 @@ private:
//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 InitializeConsumableInventoryWindow();
static void InitializeClassInfoWindow();
static void InitializeClassSelectionWindow();
static void InitializeMainMenuWindow();
static void InitializeOverworldMapLevelWindow();
static void InitializeItemLoadoutWindow();
static void InitializeLevelCompleteWindow();
static void InitializeOverworldMenuWindow();
static void InitializeCharacterMenuWindow();
void KeyboardButtonNavigation(Crawler*game,vf2d menuPos);
static void DrawScaledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor);
static void DrawTiledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor);
@ -156,6 +221,7 @@ private:
bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton);
Pixel GetRenderColor();
MenuType type;
static bool MOUSE_NAVIGATION;
bool cover; //A black cover for when a menu pops up to fade out the stuff behind it.

@ -48,8 +48,8 @@ protected:
private:
float animationTime=0;
public:
inline MenuAnimatedIconButton(MenuType parent,geom2d::rect<float>rect,std::string animation,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(parent,rect,nullptr,onClick,attributes),animation(animation){}
inline MenuAnimatedIconButton(geom2d::rect<float>rect,std::string animation,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(rect,nullptr,onClick,attributes),animation(animation){}
protected:
virtual inline void Update(Crawler*game)override{
MenuIconButton::Update(game);

@ -49,8 +49,8 @@ protected:
private:
float animationTime=0;
public:
inline MenuAnimatedIconToggleButton(MenuType parent,geom2d::rect<float>rect,std::string animation,MenuFunc onClick)
:MenuAnimatedIconButton(parent,rect,animation,[](MenuFuncData data){
inline MenuAnimatedIconToggleButton(geom2d::rect<float>rect,std::string animation,MenuFunc onClick)
:MenuAnimatedIconButton(rect,animation,[](MenuFuncData data){
MenuAnimatedIconToggleButton*button=(MenuAnimatedIconToggleButton*)data.component;
button->Select();
button->_onClick(data);

@ -40,13 +40,13 @@ All rights reserved.
using A=Attribute;
MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes)
:parentMenu(parent),rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()){
MenuComponent::MenuComponent(geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes)
:rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()){
Menu::unhandledComponents.push_back(this);
}
MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes)
:MenuComponent(parent,rect,label,onClick,attributes){
MenuComponent::MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes)
:MenuComponent(rect,label,onClick,attributes){
//NOTE: This constructor also calls the other constructor above!
this->menuDest=menuDest;
}

@ -97,8 +97,8 @@ protected:
public:
MenuType parentMenu=MenuType::ENUM_END;
MenuComponent*parentComponent=nullptr;
MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
MenuComponent(geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
virtual ~MenuComponent();
vf2d GetPos();
//We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed.

@ -51,10 +51,10 @@ class MenuIconButton:public MenuComponent{
protected:
Decal*icon;
public:
inline MenuIconButton(MenuType parent,geom2d::rect<float>rect,Decal*icon,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuComponent(parent,rect,"",onClick,ButtonAttr(attributes)),icon(icon){}
inline MenuIconButton(MenuType parent,geom2d::rect<float>rect,Decal*icon,MenuType menuDest,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuComponent(parent,rect,"",menuDest,onClick,ButtonAttr(attributes)),icon(icon){}
inline MenuIconButton(geom2d::rect<float>rect,Decal*icon,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuComponent(rect,"",onClick,ButtonAttr(attributes)),icon(icon){}
inline MenuIconButton(geom2d::rect<float>rect,Decal*icon,MenuType menuDest,MenuFunc onClick,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuComponent(rect,"",menuDest,onClick,ButtonAttr(attributes)),icon(icon){}
protected:
virtual inline void Update(Crawler*game)override{
MenuComponent::Update(game);

@ -58,8 +58,8 @@ private:
std::string itemDescriptionLabelName;
public:
int selected=-1; //0-2 representing which loadout slot this item consumes. -1 means not selected.
inline MenuItemButton(MenuType parent,geom2d::rect<float>rect,std::vector<Item>&invRef,int invIndex,MenuFunc onClick,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(parent,rect,invRef.size()>invIndex?invRef[invIndex].Decal():nullptr,onClick,attributes),invRef(invRef),inventoryIndex(invIndex),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){
inline MenuItemButton(geom2d::rect<float>rect,std::vector<Item>&invRef,int invIndex,MenuFunc onClick,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE)
:MenuIconButton(rect,invRef.size()>invIndex?invRef[invIndex].Decal():nullptr,onClick,attributes),invRef(invRef),inventoryIndex(invIndex),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){
draggable=false;
valid=invRef.size()>invIndex;
}
@ -112,7 +112,7 @@ protected:
}
inline MenuComponent*PickUpDraggableItem()override final{
if(valid){
MenuItemButton*pickUp=NEW MenuItemButton(parentMenu,rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName);
MenuItemButton*pickUp=NEW MenuItemButton(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName);
valid=false;
return pickUp;
}else{

@ -62,13 +62,13 @@ private:
bool hideQty=false;
CompactText compact=COMPACT;
public:
inline MenuItemItemButton(MenuType parent,geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName)
:MenuIconButton(parent,rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(DO_NOTHING){
inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName)
:MenuIconButton(rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(DO_NOTHING){
draggable=false;
valid=!itemRef.IsBlank();
}
inline MenuItemItemButton(MenuType parent,geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="")
:MenuIconButton(parent,rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(onHover),onMouseOut(onMouseOut){
inline MenuItemItemButton(geom2d::rect<float>rect,Item&itemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="")
:MenuIconButton(rect,(!itemRef.IsBlank())?itemRef.Decal():nullptr,menuDest,onClick),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),onHover(onHover),onMouseOut(onMouseOut){
runHoverFunctions=true;
draggable=false;
valid=!itemRef.IsBlank();

@ -50,8 +50,8 @@ protected:
bool shadow=false;
bool centered=true;
public:
inline MenuLabel(MenuType parent,geom2d::rect<float>rect,std::string label,int scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuComponent(parent,rect,label,MenuFunc{},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD),scale(scale),centered(!(attributes&ComponentAttr::LEFT_ALIGN)),shadow(attributes&ComponentAttr::SHADOW){
inline MenuLabel(geom2d::rect<float>rect,std::string label,int scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuComponent(rect,label,MenuFunc{},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD),scale(scale),centered(!(attributes&ComponentAttr::LEFT_ALIGN)),shadow(attributes&ComponentAttr::SHADOW){
border=attributes&ComponentAttr::OUTLINE;
this->background=attributes&ComponentAttr::BACKGROUND;
showDefaultLabel=false;

@ -55,25 +55,14 @@ void Menu::InitializeOverworldMapLevelWindow(){
State_OverworldMap*overworldMap=(State_OverworldMap*)GameState::states[States::OVERWORLD_MAP]; //HACK ALERT!! We're going to make an assumption that we are in the overworld map state.
MenuLabel*chapterLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
MenuLabel*stageLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
MenuLabel*panel1Back=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE);
levelSelectWindow->ADD("Panel 1 Back",MenuLabel)({{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
levelSelectWindow->ADD("Chapter Label",MenuLabel)({{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
levelSelectWindow->ADD("Stage Label",MenuLabel)({{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
levelSelectWindow->AddComponent("Panel 1 Back",panel1Back);
levelSelectWindow->AddComponent("Chapter Label",chapterLabel);
levelSelectWindow->AddComponent("Stage Label",stageLabel);
levelSelectWindow->ADD("Panel 2 Back",MenuLabel)({{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END;
levelSelectWindow->ADD("Encounters Label",MenuLabel)({{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
levelSelectWindow->ADD("Spawns List",EncountersSpawnListScrollableWindowComponent)({{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND)END;
MenuLabel*encountersLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
EncountersSpawnListScrollableWindowComponent*spawns=NEW EncountersSpawnListScrollableWindowComponent(OVERWORLD_LEVEL_SELECT,{{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND);
MenuLabel*panel2Back=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE);
levelSelectWindow->AddComponent("Panel 2 Back",panel2Back);
levelSelectWindow->AddComponent("Encounters Label",encountersLabel);
levelSelectWindow->AddComponent("Spawns List",spawns);
MenuComponent*changeLoadoutButton=NEW MenuComponent(OVERWORLD_LEVEL_SELECT,{{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;});
MenuComponent*enterButton=NEW MenuComponent(OVERWORLD_LEVEL_SELECT,{{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;});
levelSelectWindow->AddComponent("Change Loadout Button",changeLoadoutButton);
levelSelectWindow->AddComponent("Enter Button",enterButton);
levelSelectWindow->ADD("Change Loadout Button",MenuComponent)({{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;})END;
levelSelectWindow->ADD("Enter Button",MenuComponent)({{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END;
}

@ -47,18 +47,14 @@ INCLUDE_GFX
void Menu::InitializeOverworldMenuWindow(){
Menu*overworldMenuWindow=CreateMenu(OVERWORLD_MENU,CENTERED,vi2d{96,164});
MenuComponent*resumeButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;});
MenuComponent*characterButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*1},{88,24}},"Character",[](MenuFuncData data){
Component<CharacterRotatingDisplay>(CHARACTER_MENU,"Character Rotating Display")->SetIcon(GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal());
Menu::OpenMenu(CHARACTER_MENU);
return true;});
MenuComponent*inventoryButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){/*Menu::OpenMenu(INVENTORY_MENU);*/return true;});
MenuComponent*settingsButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;});
MenuComponent*quitButton=NEW MenuComponent(OVERWORLD_MENU,{{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){game->EndGame();return true;});
overworldMenuWindow->AddComponent("Resume Button",resumeButton);
overworldMenuWindow->AddComponent("Character Button",characterButton);
overworldMenuWindow->AddComponent("Inventory Button",inventoryButton);
overworldMenuWindow->AddComponent("Settings Button",settingsButton);
overworldMenuWindow->AddComponent("Quit Button",quitButton);
overworldMenuWindow->ADD("Resume Button",MenuComponent)({{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
overworldMenuWindow->ADD("Character Button",MenuComponent)({{4,12+28*1},{88,24}},"Character",
[](MenuFuncData data){
Component<CharacterRotatingDisplay>(CHARACTER_MENU,"Character Rotating Display")->SetIcon(GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal());
Menu::OpenMenu(CHARACTER_MENU);
return true;
})END;
overworldMenuWindow->ADD("Inventory Button",MenuComponent)({{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){Menu::OpenMenu(INVENTORY);return true;})END;
overworldMenuWindow->ADD("Settings Button",MenuComponent)({{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;})END;
overworldMenuWindow->ADD("Quit Button",MenuComponent)({{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){game->EndGame();return true;})END;
}

@ -47,11 +47,11 @@ class PopupMenuLabel:public MenuLabel{
private:
vf2d scale;
public:
inline PopupMenuLabel(MenuType parent,geom2d::rect<float>rect,std::string label,float scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(parent,rect,label,1,attributes),scale({scale,scale}){
inline PopupMenuLabel(geom2d::rect<float>rect,std::string label,float scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(rect,label,1,attributes),scale({scale,scale}){
}
inline PopupMenuLabel(MenuType parent,geom2d::rect<float>rect,std::string label,vf2d scale={1,1},ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(parent,rect,label,1,attributes),scale(scale){
inline PopupMenuLabel(geom2d::rect<float>rect,std::string label,vf2d scale={1,1},ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(rect,label,1,attributes),scale(scale){
}
protected:
virtual void inline Update(Crawler*game)override{

@ -59,16 +59,11 @@ protected:
return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET)+vf2d{2,2},component->rect.size-vf2d{2,2}});
}
public:
inline ScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:MenuComponent(parent,rect,"",[](MenuFuncData data){return true;},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
inline ScrollableWindowComponent(geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:MenuComponent(rect,"",[](MenuFuncData data){return true;},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
background=attributes&ComponentAttr::BACKGROUND;
border=attributes&ComponentAttr::OUTLINE;
r.Create(uint32_t(rect.size.x),uint32_t(rect.size.y));
upButton=NEW MenuComponent(parentMenu,{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
downButton=NEW MenuComponent(parentMenu,{rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
//Let's use the internal name of this component to add unique names for sub-components.
Menu::menus[parentMenu]->AddComponent(name+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton,-1);
Menu::menus[parentMenu]->AddComponent(name+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton,-1);
}
virtual inline void RemoveAllComponents(){
while(components.size()>0){
@ -100,6 +95,11 @@ public:
delete button;
}
protected:
virtual inline void AfterCreate()override{
//Let's use the internal name of this component to add unique names for sub-components.
upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH -1 END;
downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH -1 END;
}
virtual inline void BeforeUpdate(Crawler*game)override{
for(MenuComponent*component:components){
component->BeforeUpdate(game);
@ -229,7 +229,8 @@ protected:
return bounds;
}
public:
void inline AddComponent(Menu*parentMenu,std::string key,MenuComponent*button){
template<class T>
T* AddComponent(std::string key,T*button){
components.push_back(button);
button->renderInMain=false; //Now we are in control!
button->parentComponent=this;
@ -253,7 +254,8 @@ public:
bounds.size.y+=sizeIncrease;
}
parentMenu->AddComponent(key,button);
Menu::menus[parentMenu]->AddComponent(key,button);
return button;
}
virtual inline bool PointWithinParent(MenuComponent*child,vi2d drawPos)override{
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawPos);
@ -270,7 +272,7 @@ public:
}
virtual inline void Enable(bool enabled)override final{
disabled=!enabled;
upButton->Enable(enabled);
downButton->Enable(enabled);
if(upButton){upButton->Enable(enabled);}
if(downButton){downButton->Enable(enabled);}
};
};

@ -50,8 +50,8 @@ class SpawnEncounterLabel:public MenuLabel{
Animate2D::Animation<std::string>anim;
Animate2D::AnimationState state;
public:
inline SpawnEncounterLabel(MenuType parent,geom2d::rect<float>rect,std::string label,int monsterID)
:MenuLabel(parent,rect,label),monsterID(monsterID){
inline SpawnEncounterLabel(geom2d::rect<float>rect,std::string label,int monsterID)
:MenuLabel(rect,label),monsterID(monsterID){
anim.AddState("IDLE",ANIMATION_DATA.at(MONSTER_DATA.at(monsterID).GetIdleAnimation()));
anim.ChangeState(state,"IDLE");
anim.UpdateState(state,util::random(1));

@ -49,8 +49,8 @@ private:
int value=0;
int statChangeAmt=0;
public:
inline StatLabel(MenuType parent,geom2d::rect<float>rect,ItemAttribute stat,int scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(parent,rect,"",scale,attributes),stat(stat){
inline StatLabel(geom2d::rect<float>rect,ItemAttribute stat,int scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(rect,"",scale,attributes),stat(stat){
border=attributes&ComponentAttr::OUTLINE;
this->background=attributes&ComponentAttr::BACKGROUND;
showDefaultLabel=false;

@ -1,104 +0,0 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2018 - 2023 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "Crawler.h"
#include "DEFINES.h"
#include "olcPixelGameEngine.h"
#include "safemap.h"
#include "MenuIconButton.h"
#include "MenuLabel.h"
INCLUDE_GFX
using A=Attribute;
void Menu::InitializeTestSubMenu(){
Menu*testSubMenu=CreateMenu(TEST_2,{30,30},{24*4,24*5});
MenuFunc goBack=[](MenuFuncData data){
data.menu.stack.pop_back();
return true;
};
testSubMenu->AddComponent("BACK",NEW MenuComponent(TEST_2,{{24*1,24*1},{24*2,24*1}},"Go Back",goBack));
int index=0;
for(auto&theme:Menu::themes){
if(theme.displayName==Menu::themeSelection){
testSubMenu->I(A::INDEXED_THEME)=index;
break;
}
index++;
}
MenuFunc themePrev=[](MenuFuncData data){
bool found=false;
data.menu.I(A::INDEXED_THEME)--;
if(data.menu.I(A::INDEXED_THEME)<0){
data.menu.I(A::INDEXED_THEME)=int(themes.size()-1);
}
int index=0;
for(auto&theme:Menu::themes){
if(index==data.menu.I(A::INDEXED_THEME)){
Menu::themeSelection=theme.displayName;
((MenuLabel*)(data.menu.components["THEME_DISPLAY"]))->SetLabel("Theme\n"+Menu::themes[themeSelection].GetThemeName());
break;
}
index++;
}
return true;
};
testSubMenu->AddComponent("PREV_THEME",NEW MenuComponent(TEST_2,{{24*-0.5,24*3},{24*1,24*1}},"<",themePrev));
testSubMenu->AddComponent("THEME_DISPLAY",NEW MenuLabel(TEST_2,{{24*0.5,24*3},{24*3,24*1}},"Theme\n"+Menu::themes[themeSelection].GetThemeName()));
MenuFunc themeNext=[](MenuFuncData data){
data.menu.I(A::INDEXED_THEME)=(size_t(data.menu.I(A::INDEXED_THEME))+1)%themes.size();
int index=0;
for(auto&theme:Menu::themes){
if(index==data.menu.I(A::INDEXED_THEME)){
Menu::themeSelection=theme.displayName;
((MenuLabel*)(data.menu.components["THEME_DISPLAY"]))->SetLabel("Theme\n"+Menu::themes[themeSelection].GetThemeName());
break;
}
index++;
}
return true;
};
testSubMenu->AddComponent("NEXT_THEME",NEW MenuComponent(TEST_2,{{24*3.5,24*3},{24*1,24*1}},">",themeNext));
}

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_PATCH 1
#define VERSION_BUILD 3692
#define VERSION_BUILD 3722
#define stringify(a) stringify_(a)
#define stringify_(a) #a

Loading…
Cancel
Save