# 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 "MenuComponent.h"
# include "drawutil.h"
# include "util.h"
INCLUDE_game
using A = Attribute ;
MenuComponent : : MenuComponent ( geom2d : : rect < float > rect , std : : string label , MenuFunc onClick , ButtonAttr attributes )
: rect ( rect ) , originalPos ( rect . pos ) , label ( label ) , menuDest ( MenuType : : ENUM_END ) , onClick ( onClick ) , hoverEffect ( 0 ) , selectable ( ! ( attributes & ButtonAttr : : UNSELECTABLE ) ) , selectableViaKeyboard ( ! ( attributes & ButtonAttr : : UNSELECTABLE_VIA_KEYBOARD ) ) , memoryLeakInfo ( Menu : : GetMemoryLeakReportInfo ( ) ) , fitToLabel ( attributes & ButtonAttr : : FIT_TO_LABEL ) {
Menu : : unhandledComponents . push_back ( this ) ;
}
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 ;
}
MenuComponent : : MenuComponent ( geom2d : : rect < float > rect , std : : string label , MenuType menuDest , MenuFunc onClick , vf2d labelScaling , ButtonAttr attributes )
: MenuComponent ( rect , label , menuDest , onClick , attributes ) {
//NOTE: This constructor also calls the other constructor above!
this - > labelScaling = labelScaling ;
}
MenuComponent : : ~ MenuComponent ( ) {
Menu * pMenu = Menu : : menus [ parentMenu ] ;
for ( auto key : pMenu - > buttons ) {
std : : vector < MenuComponent * > & components = key . second ;
std : : erase_if ( components , [ & ] ( MenuComponent * component ) { return component = = this ; } ) ;
}
for ( auto key : pMenu - > keyboardButtons ) {
std : : vector < MenuComponent * > & components = key . second ;
std : : erase_if ( components , [ & ] ( MenuComponent * component ) { return component = = this ; } ) ;
}
std : : erase_if ( pMenu - > displayComponents , [ & ] ( MenuComponent * component ) { return component = = this ; } ) ;
//pMenu->components.erase(this->name); //We're not going to do this here because we are in the middle of a loop for another menu component when cleaning up.
}
void MenuComponent : : AfterCreate ( ) { }
void MenuComponent : : _BeforeUpdate ( Crawler * game ) {
_OnMouseOut ( ) ;
BeforeUpdate ( game ) ;
}
void MenuComponent : : BeforeUpdate ( Crawler * game ) { }
void MenuComponent : : Update ( Crawler * game ) {
if ( hovered ) {
hoverEffect = std : : min ( " ThemeGlobal.HighlightTime " _F , hoverEffect + game - > GetElapsedTime ( ) ) ;
} else {
hoverEffect = std : : max ( 0.f , hoverEffect - game - > GetElapsedTime ( ) ) ;
}
}
void MenuComponent : : _Update ( Crawler * game ) {
if ( ! disabled ) {
_OnHover ( ) ;
Update ( game ) ;
}
}
void MenuComponent : : OnEquipStatsUpdate ( ) { }
void MenuComponent : : DrawDecal ( ViewPort & window , bool focused ) {
if ( background ) {
Pixel backCol = PixelLerp ( Menu : : themes [ Menu : : themeSelection ] . GetButtonCol ( ) , Menu : : themes [ Menu : : themeSelection ] . GetHighlightCol ( ) , hoverEffect / " ThemeGlobal.HighlightTime " _F ) ;
if ( grayedOut ) {
backCol = DARK_GREY ;
}
window . FillRectDecal ( rect . pos + V ( A : : DRAW_OFFSET ) , rect . size , backCol ) ;
}
if ( selected & & selectionType = = HIGHLIGHT ) {
window . FillRectDecal ( rect . pos + V ( A : : DRAW_OFFSET ) , rect . size , PixelLerp ( Menu : : themes [ Menu : : themeSelection ] . GetButtonCol ( ) , Menu : : themes [ Menu : : themeSelection ] . GetHighlightCol ( ) , util : : lerp ( 0.75f , 1.0f , hoverEffect / " ThemeGlobal.HighlightTime " _F ) ) ) ;
}
if ( border ) {
window . FillRectDecal ( rect . pos + V ( A : : DRAW_OFFSET ) , { rect . size . x + 1 , 1 } ) ;
window . FillRectDecal ( rect . pos + V ( A : : DRAW_OFFSET ) , { 1 , rect . size . y + 1 } ) ;
window . FillRectDecal ( rect . pos + V ( A : : DRAW_OFFSET ) + vf2d { rect . size . x - 1 + 1 , 0 } , { 1 , rect . size . y + 1 } ) ;
window . FillRectDecal ( rect . pos + V ( A : : DRAW_OFFSET ) + vf2d { 0 , rect . size . y - 1 + 1 } , { rect . size . x + 1 , 1 } ) ;
}
if ( showDefaultLabel ) {
vf2d adjustedScale = labelScaling ;
vi2d labelTextSize = vf2d ( game - > GetTextSizeProp ( label ) ) * adjustedScale ;
if ( fitToLabel ) {
float sizeRatio = ( ( vf2d ( labelTextSize ) * adjustedScale ) . x ) / ( rect . size . x - 2 ) ;
if ( sizeRatio > 1 ) {
adjustedScale . x / = sizeRatio ;
}
}
window . DrawStringPropDecal ( rect . pos + V ( A : : DRAW_OFFSET ) + rect . size / 2 - vf2d ( labelTextSize ) / 2.f , label , WHITE , adjustedScale ) ;
}
if ( selected ) {
switch ( selectionType ) {
case CROSSHAIR : drawutil : : DrawCrosshairDecalViewPort ( window , { rect . pos + V ( A : : DRAW_OFFSET ) , rect . size } , 0 ) ; break ;
case INNER_BOX : window . DrawRectDecal ( rect . pos + V ( A : : DRAW_OFFSET ) + vi2d { 1 , 1 } , rect . size - vi2d { 2 , 2 } ) ; break ;
case HIGHLIGHT : break ; //Not used.
case SelectionType : : NONE : break ; //Displays nothing.
default : ERR ( " Undefined selection type selected: " < < int ( selectionType ) ) ;
}
}
}
void MenuComponent : : _DrawDecal ( ViewPort & window , bool focused ) {
if ( ! disabled ) {
DrawDecal ( window , focused ) ;
}
}
MenuComponent * MenuComponent : : PickUpDraggableItem ( ) {
return nullptr ;
}
bool MenuComponent : : DropDraggableItem ( MenuComponent * draggable ) {
return false ;
}
bool MenuComponent : : GetHoverState ( Crawler * game ) {
if ( parentComponent ! = nullptr ) {
return parentComponent - > GetHoverState ( game , this ) ;
} else {
vf2d parentWindowPos = Menu : : menus [ parentMenu ] - > pos ;
return geom2d : : overlaps ( geom2d : : rect < float > { rect . pos + parentWindowPos , rect . size } , game - > GetMousePos ( ) ) ;
}
}
bool MenuComponent : : GetHoverState ( Crawler * game , MenuComponent * child ) {
return false ;
}
bool MenuComponent : : PointWithinParent ( MenuComponent * child , vi2d drawPos ) {
if ( parentComponent ! = nullptr ) {
return parentComponent - > PointWithinParent ( child , drawPos ) ;
} else {
return true ;
}
}
bool MenuComponent : : PointWithinParent ( MenuComponent * child , geom2d : : rect < float > drawRect ) {
if ( parentComponent ! = nullptr ) {
return parentComponent - > PointWithinParent ( child , drawRect ) ;
} else {
return true ;
}
}
bool MenuComponent : : HandleOutsideDisabledButtonSelection ( MenuComponent * disabledButton ) {
return false ;
} ;
vf2d MenuComponent : : GetPos ( ) {
return rect . pos ;
}
std : : string MenuComponent : : GetLabel ( ) {
return label ;
}
void MenuComponent : : Enable ( bool enabled ) {
disabled = ! enabled ;
} ;
void MenuComponent : : Cleanup ( ) { }
std : : string MenuComponent : : GetName ( ) {
return name ;
}
void MenuComponent : : SetSelected ( bool selected ) {
this - > selected = selected ;
}
void MenuComponent : : SetSelectionType ( SelectionType selectionType ) {
this - > selectionType = selectionType ;
}
void MenuComponent : : OnMouseOut ( ) { } ;
void MenuComponent : : OnHover ( ) { } ;
void MenuComponent : : _OnMouseOut ( ) {
if ( ! hovered ) {
if ( runHoverFunctions ) {
if ( hoverState ) {
hoverState = false ;
onMouseOut ( MenuFuncData { * Menu : : menus [ parentMenu ] , game , this , ( ScrollableWindowComponent * ) ( parentComponent ) } ) ;
OnMouseOut ( ) ;
}
}
}
}
void MenuComponent : : _OnHover ( ) {
if ( hovered ) {
if ( runHoverFunctions & & ! hoverState ) {
hoverState = true ;
onHover ( MenuFuncData { * Menu : : menus [ parentMenu ] , game , this , ( ScrollableWindowComponent * ) ( parentComponent ) } ) ;
OnHover ( ) ;
}
}
}
void MenuComponent : : SetHoverFunc ( std : : function < bool ( MenuFuncData ) > func ) {
runHoverFunctions = true ;
onHover = func ;
} ;
void MenuComponent : : SetMouseOutFunc ( std : : function < bool ( MenuFuncData ) > func ) {
runHoverFunctions = true ;
onMouseOut = func ;
} ;
void MenuComponent : : SetGrayedOut ( bool grayedOut ) {
this - > grayedOut = grayedOut ;
}
void MenuComponent : : OnPlayerMoneyUpdate ( uint32_t newMoney ) { }