# 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 .
*/
# pragma endregion
# pragma once
# include "Menu.h"
# include "MenuComponent.h"
# include "MenuItemButton.h"
# include "Crawler.h"
# include "ScrollableWindowComponent.h"
typedef Attribute A ;
class InventoryScrollableWindowComponent : public ScrollableWindowComponent {
protected :
ITCategory inventoryType ;
public :
inline InventoryScrollableWindowComponent ( MenuType parent , geom2d : : rect < float > rect , ITCategory invType , ComponentAttr attributes = ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE )
: ScrollableWindowComponent ( parent , rect , attributes ) , inventoryType ( invType ) {
Menu : : AddInventoryListener ( this , invType ) ;
}
protected :
virtual inline void RemoveButton ( MenuComponent * button ) {
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 ) ;
size_t removedCount = 0 ;
removedCount + = std : : erase ( buttonList , button ) ;
removedCount + = std : : erase ( keyboardButtonList , button ) ;
if ( removedCount ! = 2 ) {
std : : cout < < " WARNING! Attempted to remove buttons from button listing, but not found! " ;
}
if ( buttonList . size ( ) = = 0 ) {
if ( ! Menu : : menus [ button - > parentMenu ] - > buttons . erase ( button - > GetPos ( ) . y ) ) {
ERR ( " WARNING! Attempted to erase key " < < button - > GetPos ( ) . y < < " from button map, but the list still exists! " )
}
}
if ( keyboardButtonList . size ( ) = = 0 ) {
if ( ! Menu : : menus [ button - > parentMenu ] - > keyboardButtons . erase ( button - > GetPos ( ) . y ) ) {
ERR ( " WARNING! Attempted to erase key " < < button - > GetPos ( ) . y < < " from button map, but the list still exists! " )
}
}
}
inline void 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.
for ( int i = 0 ; i < components . size ( ) ; i + + ) {
MenuComponent * button = components [ i ] ;
button - > Update ( game ) ; //We have to call update to update the validation state.
//HACK ALERT!! This only gets called on inventories...And only on inventory items, which would have the valid flag set. We only care about components that are inventory slots.
if ( ! button - > valid ) {
for ( int j = i ; j < components . size ( ) - 1 ; j + + ) {
//Take the item in the next slot and move it to this slot.
Menu : : menus [ components [ j ] - > parentMenu ] - > components . at ( components [ j ] - > name ) = components [ j + 1 ] ;
components [ j ] = components [ j + 1 ] ;
}
MenuComponent * lastButton = Menu : : menus [ components [ components . size ( ) - 1 ] - > parentMenu ] - > components . at ( components [ components . size ( ) - 1 ] - > name ) ;
//Now we have to fix up the keyboard button list.
RemoveButton ( lastButton ) ;
Menu : : menus [ components [ components . size ( ) - 1 ] - > parentMenu ] - > components . erase ( components [ components . size ( ) - 1 ] - > name ) ;
//Now delete the last slot.
components . erase ( components . end ( ) - 1 ) ;
i - - ; //Subtract one from the index so we don't accidently skip slots.
delete lastButton ;
}
}
bounds = CalculateBounds ( ) ; //Recalculate the bounds as it's possible the width/height of the component has changed.
}
virtual inline 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 ( components . size ( ) < 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 ;
data . game - > ClearLoadoutItem ( data . menu . I ( A : : LOADOUT_SLOT ) ) ;
for ( MenuComponent * component : components ) {
if ( component - > GetName ( ) . starts_with ( " item " ) ) {
MenuItemButton * button2 = ( MenuItemButton * ) component ; //HACK ALERT! This is probably an item since we populated item lists using this name for the components. So we assume these are MenuItemButton classes.
if ( button2 = = button ) {
if ( button2 - > selected ! = - 1 ) {
data . game - > ClearLoadoutItem ( button2 - > selected ) ;
}
button2 - > selected = - 1 ;
}
if ( button2 - > selected = = data . menu . I ( A : : LOADOUT_SLOT ) ) {
button2 - > selected = - 1 ;
}
}
}
button - > selected = data . menu . I ( A : : LOADOUT_SLOT ) ;
data . game - > SetLoadoutItem ( button - > selected , button - > GetItem ( ) . Name ( ) ) ;
return true ;
} ;
MenuItemButton * button = NEW MenuItemButton { parentMenu , { { float ( totalSpacing * x ) , float ( totalSpacing * y ) } , { float ( buttonSize ) , float ( buttonSize ) } } , Inventory : : get ( " Consumables " ) , itemIndex , useItemFunc , parentMenu , " itemName " , " itemDescription " } ;
AddComponent ( Menu : : menus [ parentMenu ] , " item_ " + cat + " _ " + std : : to_string ( itemIndex ) , button ) ;
} else
if ( components . size ( ) > inv . size ( ) ) { //There are empty spots, so let's clean up.
RemoveEmptySlots ( ) ;
}
}
virtual inline void Cleanup ( ) override {
}
} ;