@ -44,6 +44,7 @@ All rights reserved.
using A = Attribute ;
using A = Attribute ;
class ScrollableWindowComponent : public MenuComponent {
class ScrollableWindowComponent : public MenuComponent {
friend class Menu ;
protected :
protected :
ViewPort subWindow ;
ViewPort subWindow ;
std : : vector < std : : weak_ptr < MenuComponent > > components ;
std : : vector < std : : weak_ptr < MenuComponent > > components ;
@ -56,6 +57,8 @@ protected:
float scrollBarHoverTime = 0 ;
float scrollBarHoverTime = 0 ;
vf2d scrollOffset { } ;
vf2d scrollOffset { } ;
vf2d targetScrollOffset { } ;
vf2d targetScrollOffset { } ;
float lastScrollUpdate = 0.f ;
float selectionIndex = 0.f ;
protected :
protected :
inline bool OnScreen ( std : : weak_ptr < MenuComponent > component ) {
inline bool OnScreen ( std : : weak_ptr < MenuComponent > component ) {
return geom2d : : overlaps ( geom2d : : rect < float > { { } , rect . size } , geom2d : : rect < float > { component . lock ( ) - > rect . pos + vf2d { 2 , 2 } , component . lock ( ) - > rect . size - vf2d { 2 , 2 } } ) ;
return geom2d : : overlaps ( geom2d : : rect < float > { { } , rect . size } , geom2d : : rect < float > { component . lock ( ) - > rect . pos + vf2d { 2 , 2 } , component . lock ( ) - > rect . size - vf2d { 2 , 2 } } ) ;
@ -89,14 +92,24 @@ public:
virtual inline void SetScrollAmount ( vf2d scrollOffset ) {
virtual inline void SetScrollAmount ( vf2d scrollOffset ) {
this - > targetScrollOffset = scrollOffset ;
this - > targetScrollOffset = scrollOffset ;
}
}
virtual inline vf2d GetScrollAmount ( ) {
//Use this when you need to add more scrolling offset to a previous amount as GetScrollAmount() is used to get the internal scroll offset specifically.
virtual inline vf2d GetTargetScrollAmount ( ) const {
return targetScrollOffset ;
return targetScrollOffset ;
}
}
virtual bool GetHoverState ( AiL * game , MenuComponent * child ) override {
virtual bool GetHoverState ( AiL * game , MenuComponent * child ) override {
return geom2d : : overlaps ( geom2d : : rect < float > { Menu : : menus [ parentMenu ] - > pos + rect . pos , rect . size } , game - > GetMousePos ( ) ) & & //Make sure the mouse is inside the parent window component first....
return geom2d : : overlaps ( geom2d : : rect < float > { Menu : : menus [ parentMenu ] - > pos + rect . pos , rect . size } , game - > GetMousePos ( ) ) & & //Make sure the mouse is inside the parent window component first....
geom2d : : overlaps ( geom2d : : rect < float > { Menu : : menus [ parentMenu ] - > pos + rect . pos + child - > rect . pos , child - > rect . size } , game - > GetMousePos ( ) ) ;
geom2d : : overlaps ( geom2d : : rect < float > { Menu : : menus [ parentMenu ] - > pos + rect . pos + child - > rect . pos , child - > rect . size } , game - > GetMousePos ( ) ) ;
}
}
inline void IncreaseSelectionIndex ( const float val ) {
float prevIndex = selectionIndex ;
selectionIndex = std : : clamp ( selectionIndex + val , 0.f , float ( components . size ( ) - 1 ) ) ;
if ( size_t ( prevIndex ) ! = size_t ( selectionIndex ) ) { Menu : : menus [ parentMenu ] - > SetSelection ( components [ size_t ( selectionIndex ) ] , false ) ; }
}
protected :
protected :
virtual inline vf2d GetScrollAmount ( ) const {
return scrollOffset ;
}
virtual inline void AfterCreate ( ) override {
virtual inline void AfterCreate ( ) override {
//Let's use the internal name of this component to add unique names for sub-components.
//Let's use the internal name of this component to add unique names for sub-components.
upButton = Menu : : menus [ parentMenu ] - > ADD ( name + vf2d ( rect . pos + vf2d { rect . size . x - 12 , 0 } ) . str ( ) + " _ " + vf2d ( 12 , 12 ) . str ( ) , MenuComponent ) ( geom2d : : rect < float > { rect . pos + vf2d { rect . size . x - 12 , 0 } , { 12 , 12 } } , " ^ " , [ & ] ( MenuFuncData dat ) { SetScrollAmount ( GetScrollAmount ( ) + vf2d { 0 , " ThemeGlobal.MenuButtonScrollSpeed " _F } ) ; return true ; } , ButtonAttr : : UNSELECTABLE_VIA_KEYBOARD ) DEPTH depth - 1 END ;
upButton = Menu : : menus [ parentMenu ] - > ADD ( name + vf2d ( rect . pos + vf2d { rect . size . x - 12 , 0 } ) . str ( ) + " _ " + vf2d ( 12 , 12 ) . str ( ) , MenuComponent ) ( geom2d : : rect < float > { rect . pos + vf2d { rect . size . x - 12 , 0 } , { 12 , 12 } } , " ^ " , [ & ] ( MenuFuncData dat ) { SetScrollAmount ( GetScrollAmount ( ) + vf2d { 0 , " ThemeGlobal.MenuButtonScrollSpeed " _F } ) ; return true ; } , ButtonAttr : : UNSELECTABLE_VIA_KEYBOARD ) DEPTH depth - 1 END ;
@ -116,6 +129,8 @@ protected:
virtual inline void Update ( AiL * game ) override {
virtual inline void Update ( AiL * game ) override {
MenuComponent : : Update ( game ) ;
MenuComponent : : Update ( game ) ;
lastScrollUpdate = std : : max ( 0.f , lastScrollUpdate - game - > GetElapsedTime ( ) ) ;
vf2d windowAbsPos = Menu : : menus [ parentMenu ] - > pos + rect . pos ;
vf2d windowAbsPos = Menu : : menus [ parentMenu ] - > pos + rect . pos ;
bool mouseOverScrollbar = geom2d : : overlaps ( geom2d : : rect < float > ( windowAbsPos + vf2d { rect . size . x - 12 , scrollBarTop + 12 } , { 12 , scrollBarHeight } ) , game - > GetMousePos ( ) ) ;
bool mouseOverScrollbar = geom2d : : overlaps ( geom2d : : rect < float > ( windowAbsPos + vf2d { rect . size . x - 12 , scrollBarTop + 12 } , { 12 , scrollBarHeight } ) , game - > GetMousePos ( ) ) ;
@ -143,10 +158,6 @@ protected:
scrollBarHoverTime = std : : max ( scrollBarHoverTime - game - > GetElapsedTime ( ) , 0.f ) ;
scrollBarHoverTime = std : : max ( scrollBarHoverTime - game - > GetElapsedTime ( ) , 0.f ) ;
}
}
for ( std : : weak_ptr < MenuComponent > component : components ) {
component . lock ( ) - > rect . pos = component . lock ( ) - > originalPos + targetScrollOffset ;
}
if ( game - > GetMouseWheel ( ) ! = 0 ) {
if ( game - > GetMouseWheel ( ) ! = 0 ) {
if ( game - > GetMouseWheel ( ) > 0 ) {
if ( game - > GetMouseWheel ( ) > 0 ) {
SetScrollAmount ( GetScrollAmount ( ) + vf2d { 0 , " ThemeGlobal.MenuScrollWheelSpeed " _F } ) ;
SetScrollAmount ( GetScrollAmount ( ) + vf2d { 0 , " ThemeGlobal.MenuScrollWheelSpeed " _F } ) ;
@ -157,10 +168,12 @@ protected:
if ( bounds . size . y - rect . size . y > 0 ) {
if ( bounds . size . y - rect . size . y > 0 ) {
scrollOffset . y = std : : clamp ( GetScrollAmount ( ) . y , - ( bounds . size . y - rect . size . y ) , 0.f ) ;
scrollOffset . y = std : : clamp ( GetScrollAmount ( ) . y , - ( bounds . size . y - rect . size . y ) , 0.f ) ;
SetScrollAmount ( { GetScrollAmount ( ) . x , std : : clamp ( GetScrollAmount ( ) . y , - ( bounds . size . y - rect . size . y ) , 0.f ) } ) ;
SetScrollAmount ( { targetScrollOffset . x , std : : clamp ( targetScrollOffset . y , - ( bounds . size . y - rect . size . y ) , 0.f ) } ) ;
selectionIndex = std : : clamp ( selectionIndex , 0.f , float ( components . size ( ) - 1 ) ) ;
} else {
} else {
scrollOffset . y = 0 ;
scrollOffset . y = 0 ;
SetScrollAmount ( { GetScrollAmount ( ) . x , 0 } ) ;
SetScrollAmount ( { targetScrollOffset . x , 0 } ) ;
selectionIndex = std : : clamp ( selectionIndex , 0.f , float ( components . size ( ) - 1 ) ) ;
}
}
std : : sort ( components . begin ( ) , components . end ( ) , [ ] ( std : : weak_ptr < MenuComponent > c1 , std : : weak_ptr < MenuComponent > c2 ) { return c1 . lock ( ) - > depth > c2 . lock ( ) - > depth ; } ) ;
std : : sort ( components . begin ( ) , components . end ( ) , [ ] ( std : : weak_ptr < MenuComponent > c1 , std : : weak_ptr < MenuComponent > c2 ) { return c1 . lock ( ) - > depth > c2 . lock ( ) - > depth ; } ) ;
@ -175,6 +188,31 @@ protected:
upButton . lock ( ) - > disabled = true ;
upButton . lock ( ) - > disabled = true ;
downButton . lock ( ) - > disabled = true ;
downButton . lock ( ) - > disabled = true ;
}
}
# pragma region Move scroll offset towards target offset
if ( scrollOffset . y ! = targetScrollOffset . y ) {
if ( lastScrollUpdate = = 0.f ) {
float diff = fabs ( targetScrollOffset . y - scrollOffset . y ) ;
if ( targetScrollOffset . y > scrollOffset . y ) {
scrollOffset . y + = diff / 4.f ;
if ( targetScrollOffset . y < scrollOffset . y ) {
scrollOffset . y = targetScrollOffset . y ;
}
} else {
scrollOffset . y - = diff / 4.f ;
if ( targetScrollOffset . y > scrollOffset . y ) {
scrollOffset . y = targetScrollOffset . y ;
}
}
for ( std : : weak_ptr < MenuComponent > component : components ) {
component . lock ( ) - > rect . pos = component . lock ( ) - > originalPos + scrollOffset ;
}
lastScrollUpdate = 1 / 60.f ;
}
}
# pragma endregion
}
}
inline void DrawScrollbar ( ViewPort & window , vf2d parentPos , bool focused ) {
inline void DrawScrollbar ( ViewPort & window , vf2d parentPos , bool focused ) {
float spaceBetweenTopAndBottomArrows = rect . size . y - 24 ;
float spaceBetweenTopAndBottomArrows = rect . size . y - 24 ;
@ -191,6 +229,10 @@ protected:
window . DrawRectDecal ( rect . pos + parentPos + vf2d { rect . size . x - 11.75f , scrollBarTop + 12 } , { 12 , scrollBarHeight } , WHITE * focusedWindowColorMult ) ;
window . DrawRectDecal ( rect . pos + parentPos + vf2d { rect . size . x - 11.75f , scrollBarTop + 12 } , { 12 , scrollBarHeight } , WHITE * focusedWindowColorMult ) ;
}
}
inline float GetComponentIndex ( std : : weak_ptr < MenuComponent > comp ) {
return float ( std : : distance ( GetComponents ( ) . begin ( ) , std : : find_if ( GetComponents ( ) . begin ( ) , GetComponents ( ) . end ( ) , [ & ] ( auto & component ) { return & * comp . lock ( ) = = & * component . lock ( ) ; } ) ) ) ;
}
virtual inline void DrawDecal ( ViewPort & window , bool focused ) override {
virtual inline void DrawDecal ( ViewPort & window , bool focused ) override {
MenuComponent : : DrawDecal ( window , focused ) ;
MenuComponent : : DrawDecal ( window , focused ) ;
if ( border ) {
if ( border ) {