# include "Crawler.h"
# include "MenuComponent.h"
# include "DEFINES.h"
# include "safemap.h"
# include "Item.h"
# include "MenuItemButton.h"
# include "ScrollableWindowComponent.h"
bool Menu : : MOUSE_NAVIGATION = true ;
std : : vector < Menu * > Menu : : stack ;
std : : map < MenuType , Menu * > Menu : : menus ;
std : : string Menu : : themeSelection = " BlueDefault " ;
safeunorderedmap < std : : string , Theme > Menu : : themes ;
safemap < ITCategory , std : : vector < MenuComponent * > > Menu : : inventoryListeners ;
const vf2d Menu : : CENTERED = { - 456 , - 456 } ;
std : : vector < MenuComponent * > Menu : : unhandledComponents ;
INCLUDE_GFX
extern vi2d WINDOW_SIZE ;
typedef Attribute A ;
Menu : : Menu ( vf2d pos , vf2d size )
: pos ( pos = = CENTERED ? WINDOW_SIZE / 2 - size / 2 : vi2d { pos } ) , size ( size ) {
r . Create ( size . x , size . y ) ;
overlay . Create ( WINDOW_SIZE . x , WINDOW_SIZE . y ) ;
}
Menu : : ~ Menu ( ) {
for ( auto key : components ) {
delete key . second ;
}
}
void Menu : : InitializeMenus ( ) {
stack . reserve ( 32 ) ;
InitializeTestMenu ( ) ;
InitializeTestSubMenu ( ) ;
InitializeInventoryWindow ( ) ;
InitializeClassSelectionWindow ( ) ;
InitializeClassInfoWindow ( ) ;
InitializeMainMenuWindow ( ) ;
for ( MenuType type = TEST ; type < MenuType : : ENUM_END ; type = MenuType ( int ( type + 1 ) ) ) {
if ( menus . count ( type ) = = 0 ) {
std : : cout < < " WARNING! Menu Type " < < type < < " does not exist! " < < std : : endl ;
throw ;
}
//Lock up everything once it's done.
menus [ type ] - > buttons . SetInitialized ( ) ;
menus [ type ] - > keyboardButtons . SetInitialized ( ) ;
for ( auto & key : menus [ type ] - > components ) {
MenuComponent * component = key . second ;
component - > AfterCreate ( ) ;
}
}
if ( Menu : : unhandledComponents . size ( ) > 0 ) {
std : : cout < < " WARNING! There are " < < Menu : : unhandledComponents . size ( ) < < " components that were not added to any Menu! These have been leaked and should not be happening! " < < std : : endl ;
std : : cout < < " See below for a report of unhandled components: " < < std : : endl ;
int count = 0 ;
for ( MenuComponent * component : Menu : : unhandledComponents ) {
std : : cout < < " \t Component " < < ( count + 1 ) < < " : " < < std : : endl ;
std : : cout < < " \t - " < < component - > name < < std : : endl ;
count + + ;
}
throw ;
}
}
Menu * Menu : : CreateMenu ( MenuType type , vf2d pos , vf2d size ) {
menus [ type ] = new Menu ( pos , size ) ;
return menus . at ( type ) ;
}
void Menu : : AddComponent ( std : : string key , MenuComponent * button ) {
if ( button - > selectable ) {
buttons . Unlock ( ) ;
if ( buttons . count ( button - > rect . pos . y ) ) {
buttons . at ( button - > rect . pos . y ) . push_back ( button ) ;
} else {
buttons [ button - > rect . pos . y ] . push_back ( button ) ;
}
if ( button - > selectableViaKeyboard ) {
keyboardButtons . Unlock ( ) ;
if ( keyboardButtons . count ( button - > rect . pos . y ) ) {
keyboardButtons . at ( button - > rect . pos . y ) . push_back ( button ) ;
} else {
keyboardButtons [ 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 [ button - > rect . pos . y ] . begin ( ) , buttons [ button - > rect . pos . y ] . end ( ) , [ ] ( MenuComponent * c1 , MenuComponent * c2 ) {
return c1 - > GetPos ( ) . x < c2 - > GetPos ( ) . x ;
} ) ;
if ( keyboardButtons . count ( button - > rect . pos . y ) ) { //Keyboard buttons may not necessarily contain this key...Let's be sure.
std : : sort ( keyboardButtons [ button - > rect . pos . y ] . begin ( ) , keyboardButtons [ button - > rect . pos . y ] . end ( ) , [ ] ( MenuComponent * c1 , MenuComponent * c2 ) {
return c1 - > GetPos ( ) . x < c2 - > GetPos ( ) . x ;
} ) ;
}
} else {
displayComponents . push_back ( button ) ;
}
if ( components . count ( key ) ) {
std : : cout < < " WARNING! Key " < < key < < " for this sub-menu already exists! Key names must be unique! " < < std : : endl ;
throw ;
}
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 ( ) ;
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 ) ;
}
}
void Menu : : HoverMenuSelect ( Crawler * game ) {
if ( selection = = vi2d { - 1 , - 1 } | | buttons [ selection . y ] [ selection . x ] - > disabled ) return ;
if ( buttons [ selection . y ] [ selection . x ] - > draggable ) {
if ( buttonHoldTime < " ThemeGlobal.MenuHoldTime " _F ) {
CheckClickAndPerformMenuSelect ( game ) ;
} else {
draggingComponent = buttons [ selection . y ] [ selection . x ] - > PickUpDraggableItem ( ) ;
buttonHoldTime = 0 ;
}
} else {
CheckClickAndPerformMenuSelect ( game ) ;
}
}
void Menu : : MenuSelect ( Crawler * game ) {
if ( selection = = vi2d { - 1 , - 1 } | | buttons [ selection . y ] [ selection . x ] - > disabled ) return ;
buttons [ selection . y ] [ selection . x ] - > onClick ( MenuFuncData { * this , game , buttons [ selection . y ] [ selection . x ] } ) ;
if ( buttons [ selection . y ] [ selection . x ] - > menuDest ! = MenuType : : ENUM_END ) {
if ( stack . size ( ) < 32 ) {
stack . push_back ( menus [ buttons [ selection . y ] [ selection . x ] - > menuDest ] ) ; //Navigate to the next menu.
} else {
std : : cout < < " WARNING! Exceeded menu stack size limit! " < < std : : endl ;
throw ;
}
}
}
void Menu : : Update ( Crawler * game ) {
if ( draggingComponent = = nullptr ) {
HoverMenuSelect ( game ) ;
}
if ( ! UsingMouseNavigation ( ) & & geom2d : : line < float > ( lastActiveMousePos , game - > GetMousePos ( ) ) . length ( ) > = " ThemeGlobal.MouseActivationDistance " _F | | UsingMouseNavigation ( ) ) {
SetMouseNavigation ( true ) ;
}
for ( auto & key : buttons ) {
for ( auto & button : key . second ) {
if ( ! button - > disabled ) {
button - > hovered = false ;
}
}
}
bool itemHovered = false ;
if ( ! UsingMouseNavigation ( ) ) {
if ( selection ! = vi2d { - 1 , - 1 } ) {
buttons [ selection . y ] [ selection . x ] - > hovered = true ;
itemHovered = true ;
}
} else {
selection = { - 1 , - 1 } ;
for ( auto & key : buttons ) {
int index = 0 ;
for ( auto & button : key . second ) {
if ( ! button - > disabled ) {
if ( button - > GetHoverState ( game ) ) {
button - > hovered = true ;
itemHovered = true ;
selection . y = key . first ;
selection . x = index ;
}
}
index + + ;
}
}
}
if ( itemHovered & & draggingComponent = = nullptr & & selection ! = vi2d { - 1 , - 1 } & & ( ( ( ! UsingMouseNavigation ( ) & & ( game - > GetKey ( ENTER ) . bHeld ) | | game - > GetKey ( SPACE ) . bHeld ) ) | | game - > GetMouse ( Mouse : : LEFT ) . bHeld ) ) {
buttonHoldTime + = game - > GetElapsedTime ( ) ;
} else {
buttonHoldTime = 0 ;
}
if ( draggingComponent ! = nullptr ) {
MenuComponent * selectedComponent = nullptr ;
if ( selection ! = vi2d { - 1 , - 1 } ) {
selectedComponent = buttons [ selection . y ] [ selection . x ] ;
}
auto ClearDraggingComponent = [ & ] ( ) {
delete draggingComponent ; //We know we allocated a new instance of this, so we will now free it.
draggingComponent = nullptr ;
} ;
if ( ! UsingMouseNavigation ( ) ) {
if ( game - > GetKey ( ENTER ) . bReleased | | game - > GetKey ( SPACE ) . bReleased ) {
if ( selectedComponent = = nullptr ) { //Dropping over an empty area.
ClearDraggingComponent ( ) ;
} else
if ( selectedComponent - > DropDraggableItem ( draggingComponent ) ) {
ClearDraggingComponent ( ) ;
}
}
} else {
if ( game - > GetMouse ( Mouse : : LEFT ) . bReleased ) {
if ( selectedComponent = = nullptr ) { //Dropping over an empty area.
ClearDraggingComponent ( ) ;
} else
if ( selectedComponent - > DropDraggableItem ( draggingComponent ) ) {
ClearDraggingComponent ( ) ;
}
}
}
}
KeyboardButtonNavigation ( game , pos ) ;
for ( auto & key : buttons ) {
for ( auto & button : key . second ) {
if ( button - > renderInMain ) {
button - > _Update ( game ) ;
}
}
}
for ( auto & component : displayComponents ) {
if ( component - > renderInMain ) {
component - > _Update ( game ) ;
}
}
} ;
void Menu : : Draw ( Crawler * game ) {
if ( GetCurrentTheme ( ) . IsScaled ( ) ) {
DrawScaledWindowBackground ( game , pos ) ;
} else {
DrawTiledWindowBackground ( game , pos ) ;
}
game - > SetDrawTarget ( r . Sprite ( ) ) ;
Pixel : : Mode prevMode = game - > GetPixelMode ( ) ;
game - > SetPixelMode ( Pixel : : MASK ) ;
game - > Clear ( BLANK ) ;
for ( auto & component : displayComponents ) {
if ( component - > renderInMain ) {
component - > _Draw ( game , { 0 , 0 } , this = = Menu : : stack . back ( ) ) ;
}
}
for ( auto & key : buttons ) {
for ( auto & button : key . second ) {
if ( button - > renderInMain ) {
button - > _Draw ( game , { 0 , 0 } , this = = Menu : : stack . back ( ) ) ;
}
}
}
game - > SetPixelMode ( prevMode ) ;
game - > SetDrawTarget ( nullptr ) ;
r . Decal ( ) - > Update ( ) ;
game - > DrawDecal ( pos , r . Decal ( ) ) ;
for ( auto & component : displayComponents ) {
if ( component - > renderInMain ) {
component - > _DrawDecal ( game , { 0 , 0 } , this = = Menu : : stack . back ( ) ) ;
}
}
for ( auto & key : buttons ) {
for ( auto & button : key . second ) {
if ( button - > renderInMain ) {
button - > _DrawDecal ( game , { 0 , 0 } , this = = Menu : : stack . back ( ) ) ;
}
}
}
if ( GetCurrentTheme ( ) . IsScaled ( ) ) {
DrawScaledWindowBorder ( game , pos ) ;
} else {
DrawTiledWindowBorder ( game , pos ) ;
}
if ( draggingComponent ! = nullptr ) {
game - > SetDrawTarget ( overlay . Sprite ( ) ) ;
Pixel : : Mode prevMode = game - > GetPixelMode ( ) ;
game - > SetPixelMode ( Pixel : : MASK ) ;
game - > Clear ( BLANK ) ;
vf2d offsetPos = draggingComponent - > rect . pos ;
if ( ! UsingMouseNavigation ( ) ) {
MenuComponent * selectedComponent = buttons [ selection . y ] [ selection . x ] ;
vf2d drawOffset { } ;
if ( selectedComponent - > parentComponent ! = nullptr ) {
drawOffset + = selectedComponent - > parentComponent - > V ( A : : SCROLL_OFFSET ) ;
}
draggingComponent - > Draw ( game , drawOffset + pos - offsetPos + selectedComponent - > rect . pos + vi2d { 1 , - 4 } , this = = Menu : : stack . back ( ) ) ;
} else {
draggingComponent - > Draw ( game , - offsetPos + game - > GetMousePos ( ) , this = = Menu : : stack . back ( ) ) ;
}
game - > SetPixelMode ( prevMode ) ;
game - > SetDrawTarget ( nullptr ) ;
overlay . Decal ( ) - > Update ( ) ;
game - > DrawDecal ( { 0 , 0 } , overlay . Decal ( ) ) ;
if ( ! UsingMouseNavigation ( ) ) {
MenuComponent * selectedComponent = buttons [ selection . y ] [ selection . x ] ;
vf2d drawOffset { } ;
if ( selectedComponent - > parentComponent ! = nullptr ) {
drawOffset + = selectedComponent - > parentComponent - > V ( A : : SCROLL_OFFSET ) ;
}
draggingComponent - > DrawDecal ( game , drawOffset + pos - offsetPos + selectedComponent - > rect . pos + vi2d { 1 , - 4 } , this = = Menu : : stack . back ( ) ) ;
} else {
draggingComponent - > DrawDecal ( game , - offsetPos + game - > GetMousePos ( ) , this = = Menu : : stack . back ( ) ) ;
}
}
} ;
void Menu : : OpenMenu ( MenuType menu ) {
stack . clear ( ) ;
stack . push_back ( menus [ menu ] ) ;
}
void Menu : : KeyboardButtonNavigation ( Crawler * game , vf2d menuPos ) {
vi2d prevSelection = selection ;
if ( game - > GetKey ( RIGHT ) . bPressed ) {
if ( selection = = vi2d { - 1 , - 1 } ) return ;
SetMouseNavigation ( false ) ;
selection . x = ( size_t ( selection . x ) + 1 ) % keyboardButtons [ selection . y ] . size ( ) ;
}
if ( game - > GetKey ( LEFT ) . bPressed ) {
if ( selection = = vi2d { - 1 , - 1 } ) return ;
selection . x - - ;
SetMouseNavigation ( false ) ;
if ( selection . x < 0 ) selection . x + = keyboardButtons [ selection . y ] . size ( ) ;
}
if ( game - > GetKey ( DOWN ) . bPressed | | game - > GetKey ( UP ) . bPressed ) {
if ( game - > GetKey ( DOWN ) . bPressed ) {
SetMouseNavigation ( false ) ;
bool found = false ;
bool selectedItem = false ;
if ( selection = = vi2d { - 1 , - 1 } ) {
//Highlight first item.
for ( auto & key : keyboardButtons ) {
selection . y = key . first ;
break ;
}
} else {
for ( auto & key : keyboardButtons ) {
if ( found ) { //Once we discover the previous element, the next element becomes our next selection.
int previousButtonX = keyboardButtons [ selection . y ] [ selection . x ] - > rect . pos . x ;
selection . y = key . first ;
int index = 0 ;
for ( auto & button : key . second ) { //Try to match a button in the same column as this button first.
if ( previousButtonX = = button - > rect . pos . x ) {
selection . x = index ;
break ;
}
index + + ;
}
selectedItem = true ;
break ;
}
if ( key . first = = selection . y
//It's entirely possible this button was selected from the button selection list and may be out-of-bounds here.
& & selection . x > = 0 & & selection . x < keyboardButtons [ selection . y ] . size ( ) ) {
found = true ;
}
}
if ( ! selectedItem ) { //This means we need to loop around instead and pick the first one.
for ( auto & key : keyboardButtons ) {
selection . y = key . first ;
break ;
}
}
}
}
if ( game - > GetKey ( UP ) . bPressed ) {
SetMouseNavigation ( false ) ;
if ( selection = = vi2d { - 1 , - 1 } ) {
//Highlight last item.
for ( auto & key : keyboardButtons ) {
selection . y = key . first ;
}
} else {
int prevInd = - 1 ;
for ( auto & key : keyboardButtons ) {
if ( key . first = = selection . y & &
//It's entirely possible this button was selected from the button selection list and may be out-of-bounds here.
selection . x > = 0 & & selection . x < keyboardButtons [ selection . y ] . size ( ) ) {
break ;
}
prevInd = key . first ;
}
if ( prevInd ! = - 1 ) {
int previousButtonX = keyboardButtons [ selection . y ] [ selection . x ] - > rect . pos . x ;
selection . y = prevInd ;
int index = 0 ;
for ( auto & button : keyboardButtons [ prevInd ] ) { //Try to match a button in the same column as this button first.
if ( previousButtonX = = button - > rect . pos . x ) {
selection . x = index ;
break ;
}
index + + ;
}
} else { //Since we didn't find it, it means we're at the top of the list or the list is empty. Go to the last element and use that one.
int lastInd = - 1 ;
for ( auto & key : keyboardButtons ) {
lastInd = key . first ;
}
selection . y = lastInd ;
}
}
}
//In both cases, we should clamp the X index to make sure it's still valid.
if ( selection . y ! = - 1 ) {
selection . x = std : : clamp ( selection . x , 0 , int ( keyboardButtons [ selection . y ] . size ( ) ) - 1 ) ;
} else {
selection . x = - 1 ;
}
}
if ( game - > GetMouse ( 0 ) . bPressed | | game - > GetKey ( ENTER ) . bPressed | | game - > GetKey ( SPACE ) . bPressed ) {
SetMouseNavigation ( game - > GetMouse ( 0 ) . bPressed ) ; //If a click occurs we use mouse controls.
if ( ! UsingMouseNavigation ( ) ) {
buttonHoldTime = 0 ;
//Key presses automatically highlight the first button if it's not highlighted.
if ( selection = = vi2d { - 1 , - 1 } & & buttons . size ( ) > 0 ) {
//Find the first possible button entry in the map...
int firstInd = - 1 ;
for ( auto & key : buttons ) {
if ( buttons [ key . first ] . size ( ) > 0 ) {
firstInd = key . first ;
break ;
}
}
if ( firstInd ! = - 1 ) { //This means we found a valid menu item. If we didn't find one don't highlight any menu item...
selection = { 0 , firstInd } ;
}
}
} else { //Mouse click.
selection = { - 1 , - 1 } ;
for ( auto & key : buttons ) {
int index = 0 ;
for ( auto & button : key . second ) {
if ( ! button - > disabled ) {
if ( geom2d : : overlaps ( geom2d : : rect < float > { button - > rect . pos + menuPos , button - > rect . size } , game - > GetMousePos ( ) ) ) {
selection = { index , key . first } ;
break ;
}
}
index + + ;
}
}
buttonHoldTime = 0 ;
}
}
if ( prevSelection ! = selection ) {
if ( selection ! = vi2d { - 1 , - 1 } & & buttons [ selection . y ] [ selection . x ] - > disabled ) {
bool handled = false ;
if ( ! UsingMouseNavigation ( ) ) {
//Let's transfer some information about our selection being off the screen. Our intention with keyboard controls is that the screen will scroll to the correct location instead.
//If we return false, then we handled it ourselves, no need to go back to the previous selection.
if ( HandleOutsideDisabledButtonSelection ( buttons [ selection . y ] [ selection . x ] ) ) {
handled = true ;
}
}
if ( ! handled ) {
// If the new selection of a button on this frame is disabled for some reason and we didn't handle it, we need to go back to what we had selected before.
selection = prevSelection ;
}
}
}
}
void Menu : : DrawScaledWindowBorder ( Crawler * game , vf2d menuPos ) {
vf2d patchSize = { " Interface.9PatchSize " _f [ 0 ] , " Interface.9PatchSize " _f [ 1 ] } ;
//Upper-Left
game - > DrawPartialDecal ( menuPos - patchSize , patchSize , GetPatchPart ( 0 , 0 ) . Decal ( ) , { patchSize . x * 0 , patchSize . y * 0 } , patchSize , GetRenderColor ( ) ) ;
//Upper-Right
game - > DrawPartialDecal ( menuPos + vf2d { size . x , - patchSize . y } , patchSize , GetPatchPart ( 2 , 0 ) . Decal ( ) , { patchSize . x * 2 , patchSize . y * 0 } , patchSize , GetRenderColor ( ) ) ;
//Bottom-Left
game - > DrawPartialDecal ( menuPos + vf2d { - patchSize . x , size . y } , patchSize , GetPatchPart ( 0 , 2 ) . Decal ( ) , { patchSize . x * 0 , patchSize . y * 2 } , patchSize , GetRenderColor ( ) ) ;
//Bottom-Right
game - > DrawPartialDecal ( menuPos + vf2d { size . x , size . y } , patchSize , GetPatchPart ( 2 , 2 ) . Decal ( ) , { patchSize . x * 2 , patchSize . y * 2 } , patchSize , GetRenderColor ( ) ) ;
//Top
game - > DrawPartialDecal ( menuPos + vf2d { 0 , - patchSize . y } , vf2d { size . x , patchSize . y } , GetPatchPart ( 1 , 0 ) . Decal ( ) , { patchSize . x * 1 , patchSize . y * 0 } , patchSize , GetRenderColor ( ) ) ;
//Left
game - > DrawPartialDecal ( menuPos + vf2d { - patchSize . x , 0 } , vf2d { patchSize . x , size . y } , GetPatchPart ( 0 , 1 ) . Decal ( ) , { patchSize . x * 0 , patchSize . y * 1 } , patchSize , GetRenderColor ( ) ) ;
//Right
game - > DrawPartialDecal ( menuPos + vf2d { size . x , 0 } , vf2d { patchSize . x , size . y } , GetPatchPart ( 2 , 1 ) . Decal ( ) , { patchSize . x * 2 , patchSize . y * 1 } , patchSize , GetRenderColor ( ) ) ;
//Bottom
game - > DrawPartialDecal ( menuPos + vf2d { 0 , size . y } , vf2d { size . x , patchSize . y } , GetPatchPart ( 1 , 2 ) . Decal ( ) , { patchSize . x * 1 , patchSize . y * 2 } , patchSize , GetRenderColor ( ) ) ;
}
void Menu : : DrawTiledWindowBorder ( Crawler * game , vf2d menuPos ) {
vf2d patchSize = { " Interface.9PatchSize " _f [ 0 ] , " Interface.9PatchSize " _f [ 1 ] } ;
//Upper-Left
game - > DrawPartialDecal ( menuPos - patchSize , patchSize , GetPatchPart ( 0 , 0 ) . Decal ( ) , { 0 , 0 } , patchSize , GetRenderColor ( ) ) ;
//Upper-Right
game - > DrawPartialDecal ( menuPos + vf2d { size . x , - patchSize . y } , patchSize , GetPatchPart ( 2 , 0 ) . Decal ( ) , { 0 , 0 } , patchSize , GetRenderColor ( ) ) ;
//Bottom-Left
game - > DrawPartialDecal ( menuPos + vf2d { - patchSize . x , size . y } , patchSize , GetPatchPart ( 0 , 2 ) . Decal ( ) , { 0 , 0 } , patchSize , GetRenderColor ( ) ) ;
//Bottom-Right
game - > DrawPartialDecal ( menuPos + vf2d { size . x , size . y } , patchSize , GetPatchPart ( 2 , 2 ) . Decal ( ) , { 0 , 0 } , patchSize , GetRenderColor ( ) ) ;
//Top
game - > DrawPartialDecal ( menuPos + vf2d { 0 , - patchSize . y } , vf2d { size . x , patchSize . y } , GetPatchPart ( 1 , 0 ) . Decal ( ) , { 0 , 0 } , vf2d { size . x , patchSize . y } , GetRenderColor ( ) ) ;
//Left
game - > DrawPartialDecal ( menuPos + vf2d { - patchSize . x , 0 } , vf2d { patchSize . x , size . y } , GetPatchPart ( 0 , 1 ) . Decal ( ) , { 0 , 0 } , vf2d { patchSize . x , size . y } , GetRenderColor ( ) ) ;
//Right
game - > DrawPartialDecal ( menuPos + vf2d { size . x , 0 } , vf2d { patchSize . x , size . y } , GetPatchPart ( 2 , 1 ) . Decal ( ) , { 0 , 0 } , vf2d { patchSize . x , size . y } , GetRenderColor ( ) ) ;
//Bottom
game - > DrawPartialDecal ( menuPos + vf2d { 0 , size . y } , vf2d { size . x , patchSize . y } , GetPatchPart ( 1 , 2 ) . Decal ( ) , { 0 , 0 } , vf2d { size . x , patchSize . y } , GetRenderColor ( ) ) ;
}
void Menu : : DrawScaledWindowBackground ( Crawler * game , vf2d menuPos ) {
vf2d patchSize = { " Interface.9PatchSize " _f [ 0 ] , " Interface.9PatchSize " _f [ 1 ] } ;
//Center
if ( GetCurrentTheme ( ) . HasBackground ( ) ) {
Decal * back = GetCurrentTheme ( ) . GetBackground ( ) ;
game - > DrawPartialDecal ( menuPos , size , back , { 0 , 0 } , back - > sprite - > Size ( ) , GetRenderColor ( ) ) ;
} else {
game - > DrawPartialDecal ( menuPos , size , GetPatchPart ( 1 , 1 ) . Decal ( ) , { patchSize . x * 1 , patchSize . y * 1 } , patchSize , GetRenderColor ( ) ) ;
}
}
void Menu : : DrawTiledWindowBackground ( Crawler * game , vf2d menuPos ) {
vf2d patchSize = { " Interface.9PatchSize " _f [ 0 ] , " Interface.9PatchSize " _f [ 1 ] } ;
//Center
if ( GetCurrentTheme ( ) . HasBackground ( ) ) {
Decal * back = GetCurrentTheme ( ) . GetBackground ( ) ;
game - > DrawPartialDecal ( menuPos , size , back , { 0 , 0 } , size , GetRenderColor ( ) ) ;
} else {
game - > DrawPartialDecal ( menuPos , size , GetPatchPart ( 1 , 1 ) . Decal ( ) , { 0 , 0 } , patchSize , GetRenderColor ( ) ) ;
}
}
Renderable & Menu : : GetPatchPart ( int x , int y ) {
return GFX [ themeSelection + " _ " + std : : to_string ( x ) + std : : to_string ( y ) + " .png " ] ;
}
Theme & Menu : : GetCurrentTheme ( ) {
return themes [ themeSelection ] ;
}
Pixel Menu : : GetRenderColor ( ) {
bool focused = Menu : : stack . back ( ) = = this ;
Pixel col = WHITE ;
if ( ! focused ) {
col = WHITE * " ThemeGlobal.MenuUnfocusedColorMult " _F ;
}
return col ;
}
bool Menu : : HandleOutsideDisabledButtonSelection ( MenuComponent * disabledButton ) {
if ( disabledButton - > parentComponent ! = nullptr ) {
return disabledButton - > parentComponent - > HandleOutsideDisabledButtonSelection ( disabledButton ) ;
} else {
return false ;
}
}
bool Menu : : UsingMouseNavigation ( ) {
return MOUSE_NAVIGATION ;
} ;
void Menu : : SetMouseNavigation ( bool mouseNavigation ) {
if ( MOUSE_NAVIGATION & & ! mouseNavigation ) {
//When mouse navigation was enabled and now needs to be disabled, we store the mouse position.
INCLUDE_game
lastActiveMousePos = game - > GetMousePos ( ) ;
}
MOUSE_NAVIGATION = mouseNavigation ;
} ;
void Menu : : InventorySlotsUpdated ( ITCategory cat ) {
//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 ) ;
for ( MenuComponent * component : inventoryListeners . at ( cat ) ) {
component - > OnInventorySlotsUpdate ( cat ) ;
}
}
void Menu : : AddInventoryListener ( MenuComponent * component , ITCategory category ) {
if ( inventoryListeners . count ( category ) ) {
std : : vector < MenuComponent * > & listenerList = inventoryListeners . at ( category ) ;
if ( std : : find ( listenerList . begin ( ) , listenerList . end ( ) , component ) ! = listenerList . end ( ) ) {
std : : cout < < " WARNING! Component " < < component - > name < < " has already been added to the " < < category < < " listener list! There should not be any duplicates!! " < < std : : endl ;
throw ;
}
listenerList . push_back ( component ) ;
} else {
std : : cout < < " WARNING! Inventory category " < < category < < " does not exist! " < < std : : endl ;
throw ;
}
}
vf2d Menu : : center ( ) {
return size / 2 ;
}
void Menu : : CloseMenu ( ) {
if ( stack . size ( ) > 0 ) {
stack . pop_back ( ) ;
} else {
std : : cout < < " WARNING! Trying to close out no menu?? Why are we doing this? " < < std : : endl ;
throw ;
}
}