Refactor inventory window so the scrollable consumable window now subscribes to a listener.

Listener list system removes the arbitrary requirement of components needing to be called "inventory" (very error-prone)
pull/28/head
parent 04d6f42526
commit 46462a24e7
  1. 64
      Crawler/.vscode/settings.json
  2. 4
      Crawler/InventoryWindow.cpp
  3. 56
      Crawler/Menu.cpp
  4. 4
      Crawler/Menu.h
  5. 2
      Crawler/MenuComponent.cpp
  6. 2
      Crawler/MenuComponent.h
  7. 28
      Crawler/ScrollableWindowComponent.h

@ -0,0 +1,64 @@
{
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp"
}
}

@ -23,6 +23,10 @@ void Menu::InitializeInventoryWindow(){
ScrollableWindowComponent*inventory=new ScrollableWindowComponent(INVENTORY,{{1,0},{windowSize.x,float(totalSpacing*3-itemSpacing)}},nullptr,[](MenuFuncData data){}); ScrollableWindowComponent*inventory=new ScrollableWindowComponent(INVENTORY,{{1,0},{windowSize.x,float(totalSpacing*3-itemSpacing)}},nullptr,[](MenuFuncData data){});
inventoryWindow->AddComponent("inventory",inventory); inventoryWindow->AddComponent("inventory",inventory);
Menu::AddInventoryListener(inventory,"Consumables");
Menu::AddInventoryListener(inventory,"Equipment");
Menu::AddInventoryListener(inventory,"Accessories");
Menu::AddInventoryListener(inventory,"Materials");
//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. //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.

@ -564,49 +564,21 @@ void Menu::SetMouseNavigation(bool mouseNavigation){
void Menu::InventorySlotsUpdated(ITCategory cat){ void Menu::InventorySlotsUpdated(ITCategory cat){
//Update the inventory with a new inventory slot, since there's one additional item to interact with now. //Update the inventory with a new inventory slot, since there's one additional item to interact with now.
std::vector<std::string>&inv=Inventory::get(cat); std::vector<std::string>&inv=Inventory::get(cat);
MenuType inventoryWindow; for(MenuComponent*component:inventoryListeners.at(cat)){
if(cat=="Consumables"){ component->OnInventorySlotsUpdate(cat);
inventoryWindow=INVENTORY; }
}else }
if(cat=="Equipment"){
//TODO: Update different inventories depending on what the item's category is. void Menu::AddInventoryListener(MenuComponent*component,ITCategory category){
std::cout<<"WARNING! Unimplemented inventory slot addition for category "<<cat<<"!"<<std::endl; if(inventoryListeners.count(category)){
return; //Currenly a no-op std::vector<MenuComponent*>&listenerList=inventoryListeners.at(category);
}else if(std::find(listenerList.begin(),listenerList.end(),component)!=listenerList.end()){
if(cat=="Accesories"){ std::cout<<"WARNING! Component "<<component->name<<" has already been added to the "<<category<<" listener list! There should not be any duplicates!!"<<std::endl;
//TODO: Update different inventories depending on what the item's category is. throw;
std::cout<<"WARNING! Unimplemented inventory slot addition for category "<<cat<<"!"<<std::endl; }
return; //Currenly a no-op listenerList.push_back(component);
}else
if(cat=="Materials"){
//TODO: Update different inventories depending on what the item's category is.
std::cout<<"WARNING! Unimplemented inventory slot addition for category "<<cat<<"!"<<std::endl;
return; //Currenly a no-op
}else{ }else{
std::cout<<"WARNING! Inventory category "<<category<<" does not exist!"<<std::endl;
throw; throw;
std::cout<<"WARNING! Attempting to add an inventory to a category that does not exist. THIS SHOULD NOT BE HAPPENING!"<<std::endl;
}
//HACK ALERT!! We make a very bold assumption here that every inventory window will contain a ScrollableWindowComponent called "inventory"! Because it's a safemap, if it doesn't exist it will let us know as such, we won't include any extra checks here.
ScrollableWindowComponent*inventory=((ScrollableWindowComponent*)menus[inventoryWindow]->components["inventory"]);
//We only want to refresh the inventory slots if the component count no longer matches what's actually in our inventory.
if(inventory->ComponentCount()<inv.size()){//We need more space to display our items.
int invWidth="ThemeGlobal.InventoryWidth"_I;
int x=(inv.size()-1)%invWidth;
int y=(inv.size()-1)/invWidth;
int itemIndex=y*invWidth+x;
int buttonSize="ThemeGlobal.InventoryButtonSize"_I;
int totalSpacing="ThemeGlobal.InventoryItemSpacing"_I+buttonSize;
MenuFunc useItemFunc=[](MenuFuncData data){
MenuItemButton*button=(MenuItemButton*)data.component;
button->UseItem();
};
MenuItemButton*button=new MenuItemButton{inventoryWindow,{{float(totalSpacing*x),float(totalSpacing*y)},{float(buttonSize),float(buttonSize)}},Inventory::get("Consumables"),itemIndex,useItemFunc};
inventory->AddComponent(menus[inventoryWindow],"item"+std::to_string(itemIndex),button);
}else
if(inventory->ComponentCount()>inv.size()){ //There are empty spots, so let's clean up.
inventory->RemoveEmptySlots();
} }
} }

@ -24,12 +24,13 @@ class Menu:IAttributable{
friend class Player; friend class Player;
float buttonHoldTime=0; float buttonHoldTime=0;
std::vector<MenuComponent*>displayComponents; //Components that are only for displaying purposes. std::vector<MenuComponent*>displayComponents; //Comp.onents that are only for displaying purposes.
vi2d selection={-1,-1}; vi2d selection={-1,-1};
vi2d lastActiveMousePos={}; vi2d lastActiveMousePos={};
MenuComponent*draggingComponent=nullptr; MenuComponent*draggingComponent=nullptr;
Renderable r,overlay; Renderable r,overlay;
static safemap<ITCategory,std::vector<MenuComponent*>>inventoryListeners; //All menu components that care about inventory updates subscribe to this list indirectly (See Menu::AddInventoryListener()).
public: public:
//The constructor is private. Use CreateMenu() instead! //The constructor is private. Use CreateMenu() instead!
Menu()=default; Menu()=default;
@ -54,6 +55,7 @@ public:
bool UsingMouseNavigation(); bool UsingMouseNavigation();
void SetMouseNavigation(bool mouseNavigation); void SetMouseNavigation(bool mouseNavigation);
static void InventorySlotsUpdated(ITCategory cat); //Called whenever an inventory item gets added to the player's inventory, thus increasing the total number of slots in our bag. static void InventorySlotsUpdated(ITCategory cat); //Called whenever an inventory item gets added to the player's inventory, thus increasing the total number of slots in our bag.
static void AddInventoryListener(MenuComponent*component,ITCategory category); //Adds a component to be in a given listener category.
private: private:
Menu(vf2d pos,vf2d size); Menu(vf2d pos,vf2d size);
void HoverMenuSelect(Crawler*game); void HoverMenuSelect(Crawler*game);

@ -85,3 +85,5 @@ bool MenuComponent::HandleOutsideDisabledButtonSelection(MenuComponent*disabledB
vf2d MenuComponent::GetPos(){ vf2d MenuComponent::GetPos(){
return rect.pos; return rect.pos;
} }
void MenuComponent::OnInventorySlotsUpdate(ITCategory cat){}

@ -45,4 +45,6 @@ public:
virtual bool DropDraggableItem(MenuComponent*draggable); virtual bool DropDraggableItem(MenuComponent*draggable);
//A notification that a button outside the region has been selected. Return false if it's not allowed. //A notification that a button outside the region has been selected. Return false if it's not allowed.
virtual bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton); virtual bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton);
//Called whenever an inventory slot gets updated, whether it's adding or removing an item.
virtual void OnInventorySlotsUpdate(ITCategory cat);
}; };

@ -191,7 +191,7 @@ public:
virtual inline size_t ComponentCount(){ virtual inline size_t ComponentCount(){
return components.size(); return components.size();
} }
virtual void RemoveButton(MenuComponent*button){ virtual inline void RemoveButton(MenuComponent*button){
std::vector<MenuComponent*>&buttonList=Menu::menus[button->parentMenu]->buttons.at(button->GetPos().y); std::vector<MenuComponent*>&buttonList=Menu::menus[button->parentMenu]->buttons.at(button->GetPos().y);
std::vector<MenuComponent*>&keyboardButtonList=Menu::menus[button->parentMenu]->keyboardButtons.at(button->GetPos().y); std::vector<MenuComponent*>&keyboardButtonList=Menu::menus[button->parentMenu]->keyboardButtons.at(button->GetPos().y);
size_t removedCount=0; size_t removedCount=0;
@ -214,7 +214,7 @@ public:
} }
} }
} }
virtual void RemoveEmptySlots(){ void inline RemoveEmptySlots(){
//Algorithm will iterate through all slots, finding blank slots. Each time a blank slot is found, all items will shift over by one, and then the last item will be removed. Repeat until all slots iterated through. //Algorithm will iterate through all slots, finding blank slots. Each time a blank slot is found, all items will shift over by one, and then the last item will be removed. Repeat until all slots iterated through.
for(int i=0;i<components.size();i++){ for(int i=0;i<components.size();i++){
MenuComponent*button=components[i]; MenuComponent*button=components[i];
@ -237,4 +237,28 @@ public:
} }
bounds=CalculateBounds(); //Recalculate the bounds as it's possible the width/height of the component has changed. bounds=CalculateBounds(); //Recalculate the bounds as it's possible the width/height of the component has changed.
} }
virtual void OnInventorySlotsUpdate(ITCategory cat)override{
std::vector<std::string>&inv=Inventory::get(cat);
//We only want to refresh the inventory slots if the component count no longer matches what's actually in our inventory.
if(ComponentCount()<inv.size()){//We need more space to display our items.
int invWidth="ThemeGlobal.InventoryWidth"_I;
int x=(inv.size()-1)%invWidth;
int y=(inv.size()-1)/invWidth;
int itemIndex=y*invWidth+x;
int buttonSize="ThemeGlobal.InventoryButtonSize"_I;
int totalSpacing="ThemeGlobal.InventoryItemSpacing"_I+buttonSize;
MenuFunc useItemFunc=[](MenuFuncData data){
MenuItemButton*button=(MenuItemButton*)data.component;
button->UseItem();
};
MenuItemButton*button=new MenuItemButton{parentMenu,{{float(totalSpacing*x),float(totalSpacing*y)},{float(buttonSize),float(buttonSize)}},Inventory::get("Consumables"),itemIndex,useItemFunc};
AddComponent(Menu::menus[parentMenu],"item"+std::to_string(itemIndex),button);
}else
if(ComponentCount()>inv.size()){ //There are empty spots, so let's clean up.
RemoveEmptySlots();
}
}
}; };
Loading…
Cancel
Save