2023-11-20 23:25:36 -06:00
# pragma region License
2023-11-14 18:11:32 -06:00
/*
License ( OLC - 3 )
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
2023-11-14 18:12:54 -06:00
Copyright 2018 - 2023 OneLoneCoder . com
2023-11-14 18:11:32 -06:00
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 .
2023-11-29 00:50:00 -06:00
Portions of this software are copyright © 2023 The FreeType
Project ( www . freetype . org ) . Please see LICENSE_FT . txt for more information .
All rights reserved .
2023-11-14 18:11:32 -06:00
*/
2023-11-20 23:25:36 -06:00
# pragma endregion
2023-10-01 01:48:27 -05:00
# include "Crawler.h"
2023-10-07 15:47:26 -05:00
# include "MenuComponent.h"
2023-12-10 23:02:16 -06:00
# include "drawutil.h"
# include "util.h"
2023-10-01 01:48:27 -05:00
2023-12-14 04:18:05 -06:00
INCLUDE_game
2023-12-05 23:07:49 -06:00
using A = Attribute ;
2023-10-17 05:35:19 -05:00
2023-12-10 19:14:37 -06:00
MenuComponent : : MenuComponent ( geom2d : : rect < float > rect , std : : string label , MenuFunc onClick , ButtonAttr attributes )
2023-12-19 17:10:04 -06:00
: 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 ) {
2023-10-22 23:19:47 -05:00
Menu : : unhandledComponents . push_back ( this ) ;
}
2023-10-01 01:48:27 -05:00
2023-12-10 19:14:37 -06:00
MenuComponent : : MenuComponent ( geom2d : : rect < float > rect , std : : string label , MenuType menuDest , MenuFunc onClick , ButtonAttr attributes )
: MenuComponent ( rect , label , onClick , attributes ) {
2023-10-23 00:05:30 -05:00
//NOTE: This constructor also calls the other constructor above!
2023-10-15 14:59:35 -05:00
this - > menuDest = menuDest ;
2023-10-22 23:19:47 -05:00
}
2023-12-10 20:14:32 -06:00
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 ;
}
2023-10-22 23:19:47 -05:00
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 ; } ) ;
2023-11-11 04:03:48 -06:00
//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.
2023-10-15 14:59:35 -05:00
}
2023-10-01 01:48:27 -05:00
2023-10-15 12:58:39 -05:00
void MenuComponent : : AfterCreate ( ) { }
2023-12-16 21:28:41 -06:00
void MenuComponent : : _BeforeUpdate ( Crawler * game ) {
_OnMouseOut ( ) ;
BeforeUpdate ( game ) ;
}
2023-12-08 16:36:51 -06:00
void MenuComponent : : BeforeUpdate ( Crawler * game ) { }
2023-10-01 01:48:27 -05:00
void MenuComponent : : Update ( Crawler * game ) {
if ( hovered ) {
2023-10-03 04:09:42 -05:00
hoverEffect = std : : min ( " ThemeGlobal.HighlightTime " _F , hoverEffect + game - > GetElapsedTime ( ) ) ;
2023-10-01 01:48:27 -05:00
} else {
hoverEffect = std : : max ( 0.f , hoverEffect - game - > GetElapsedTime ( ) ) ;
}
}
2023-10-12 19:35:16 -05:00
void MenuComponent : : _Update ( Crawler * game ) {
if ( ! disabled ) {
2023-12-16 21:28:41 -06:00
_OnHover ( ) ;
2023-10-12 19:35:16 -05:00
Update ( game ) ;
}
}
2023-12-06 22:47:09 -06:00
void MenuComponent : : OnEquipStatsUpdate ( ) { }
2023-12-15 23:57:09 -06:00
void MenuComponent : : DrawDecal ( ViewPort & window , bool focused ) {
2023-12-14 04:18:05 -06:00
if ( background ) {
2023-12-19 18:46:59 -06:00
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 ) ;
2023-10-12 19:35:16 -05:00
}
2023-12-14 04:18:05 -06:00
if ( selected & & selectionType = = HIGHLIGHT ) {
2023-12-15 23:57:09 -06:00
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 ) ) ) ;
2023-12-14 04:18:05 -06:00
}
if ( border ) {
2023-12-15 23:57:09 -06:00
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 } ) ;
2023-12-08 17:06:34 -06:00
}
2023-12-14 04:18:05 -06:00
if ( showDefaultLabel ) {
2023-12-19 17:10:04 -06:00
vf2d adjustedScale = labelScaling ;
2023-12-21 10:26:18 -06:00
vi2d labelTextSize = vf2d ( game - > GetTextSizeProp ( label ) ) * adjustedScale ;
2023-12-20 19:45:49 -06:00
2023-12-19 17:10:04 -06:00
if ( fitToLabel ) {
2023-12-21 10:26:18 -06:00
float sizeRatio = ( ( vf2d ( labelTextSize ) * adjustedScale ) . x ) / ( rect . size . x - 2 ) ;
2023-12-19 17:10:04 -06:00
if ( sizeRatio > 1 ) {
adjustedScale . x / = sizeRatio ;
}
}
2023-12-21 10:26:18 -06:00
window . DrawStringPropDecal ( rect . pos + V ( A : : DRAW_OFFSET ) + rect . size / 2 - vf2d ( labelTextSize ) / 2.f , label , WHITE , adjustedScale ) ;
2023-12-14 04:18:05 -06:00
}
if ( selected ) {
switch ( selectionType ) {
2023-12-15 23:57:09 -06:00
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 ;
2023-12-14 04:18:05 -06:00
case HIGHLIGHT : break ; //Not used.
2023-12-16 22:17:49 -06:00
case SelectionType : : NONE : break ; //Displays nothing.
2023-12-14 04:18:05 -06:00
default : ERR ( " Undefined selection type selected: " < < int ( selectionType ) ) ;
}
}
2023-12-08 17:06:34 -06:00
}
2023-10-11 19:50:12 -05:00
2023-12-14 04:18:05 -06:00
void MenuComponent : : _DrawDecal ( ViewPort & window , bool focused ) {
2023-10-12 19:35:16 -05:00
if ( ! disabled ) {
2023-12-15 23:57:09 -06:00
DrawDecal ( window , focused ) ;
2023-10-12 19:35:16 -05:00
}
}
2023-10-07 18:28:19 -05:00
MenuComponent * MenuComponent : : PickUpDraggableItem ( ) {
return nullptr ;
}
bool MenuComponent : : DropDraggableItem ( MenuComponent * draggable ) {
return false ;
2023-10-12 19:35:16 -05:00
}
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 ;
2023-10-12 20:16:22 -05:00
}
bool MenuComponent : : PointWithinParent ( MenuComponent * child , vi2d drawPos ) {
if ( parentComponent ! = nullptr ) {
return parentComponent - > PointWithinParent ( child , drawPos ) ;
} else {
return true ;
}
2023-10-17 00:50:58 -05:00
}
2023-12-14 01:43:42 -06:00
bool MenuComponent : : PointWithinParent ( MenuComponent * child , geom2d : : rect < float > drawRect ) {
if ( parentComponent ! = nullptr ) {
return parentComponent - > PointWithinParent ( child , drawRect ) ;
} else {
return true ;
}
}
2023-10-17 00:50:58 -05:00
bool MenuComponent : : HandleOutsideDisabledButtonSelection ( MenuComponent * disabledButton ) {
return false ;
2023-10-17 05:35:19 -05:00
} ;
vf2d MenuComponent : : GetPos ( ) {
return rect . pos ;
2023-10-18 16:06:08 +00:00
}
2023-10-24 03:03:34 -05:00
void MenuComponent : : OnInventorySlotsUpdate ( ITCategory cat ) { }
std : : string MenuComponent : : GetLabel ( ) {
return label ;
2023-10-24 04:52:24 -05:00
}
void MenuComponent : : Enable ( bool enabled ) {
disabled = ! enabled ;
2023-11-11 04:03:48 -06:00
} ;
2023-11-12 23:51:49 -06:00
void MenuComponent : : Cleanup ( ) { }
std : : string MenuComponent : : GetName ( ) {
return name ;
2023-12-10 23:02:16 -06:00
}
void MenuComponent : : SetSelected ( bool selected ) {
this - > selected = selected ;
}
void MenuComponent : : SetSelectionType ( SelectionType selectionType ) {
this - > selectionType = selectionType ;
2023-12-16 21:28:41 -06:00
}
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 ;
2023-12-19 18:46:59 -06:00
} ;
void MenuComponent : : SetGrayedOut ( bool grayedOut ) {
this - > grayedOut = grayedOut ;
}
void MenuComponent : : OnPlayerMoneyUpdate ( uint32_t newMoney ) { }