2025-07-06 20:43:53 +03:00
# pragma once
# include "Element.hpp"
2026-03-27 09:51:53 +03:00
# include "../GUIManager.hpp"
2025-07-06 20:43:53 +03:00
namespace GUIStuff {
2026-04-04 17:52:43 +03:00
struct NumberSliderData {
std : : function < void ( ) > onChange ;
std : : function < void ( ) > onHold ;
std : : function < void ( ) > onRelease ;
} ;
2025-07-06 20:43:53 +03:00
template < typename T > class NumberSlider : public Element {
public :
2026-03-27 09:51:53 +03:00
NumberSlider ( GUIManager & gui ) :
Element ( gui ) { }
2025-11-05 14:55:22 +03:00
2026-04-08 17:34:50 +03:00
static constexpr float HOLD_ANIMATION_TIME = 0.3f ;
2026-04-04 17:52:43 +03:00
void layout ( const Clay_ElementId & id , T * data , T minData , T maxData , const NumberSliderData & config ) {
2026-03-27 09:51:53 +03:00
this - > data = data ;
2026-04-08 17:34:50 +03:00
dd . val = * data ;
dd . minData = minData ;
dd . maxData = maxData ;
2026-04-04 17:52:43 +03:00
this - > config = config ;
2025-07-06 20:43:53 +03:00
2026-03-31 17:33:09 +03:00
CLAY ( id , {
2025-07-06 20:43:53 +03:00
. layout = {
2025-11-01 16:07:19 +03:00
. sizing = { . width = CLAY_SIZING_GROW ( 100 ) , . height = CLAY_SIZING_FIXED ( 10 ) }
2025-07-06 20:43:53 +03:00
} ,
. custom = { . customData = this }
} ) {
}
}
2026-04-08 17:34:50 +03:00
virtual void update ( ) {
smooth_two_way_time ( dd . holdAnimation , gui . io . deltaTime , dd . isHeld , HOLD_ANIMATION_TIME ) ;
smooth_two_way_time ( dd . hoverAnimation , gui . io . deltaTime , mouseHovering , gui . io . theme - > hoverExpandTime ) ;
if ( oldDD ! = dd ) {
gui . invalidate_draw_element ( this , {
. top = 10.0f ,
. bottom = 10.0f ,
. left = 10.0f ,
. right = 10.0f
} ) ;
oldDD = dd ;
}
}
2026-03-20 20:53:59 +03:00
virtual void clay_draw ( SkCanvas * canvas , UpdateInputData & io , Clay_RenderCommand * command , bool skiaAA ) override {
2026-03-27 09:51:53 +03:00
auto & bb = boundingBox . value ( ) ;
2025-07-06 20:43:53 +03:00
canvas - > save ( ) ;
canvas - > translate ( bb . min . x ( ) , bb . min . y ( ) ) ;
2026-04-08 20:42:10 +03:00
float lerpTimeHover = dd . hoverAnimation / io . theme - > hoverExpandTime ;
2025-07-06 20:43:53 +03:00
static BezierEasing easeHeight ( 0.68 , - 1.55 , 0.265 , 2.55 ) ;
2026-04-08 17:34:50 +03:00
float lerpTimeHeld = easeHeight ( dd . holdAnimation / HOLD_ANIMATION_TIME ) ;
2025-07-06 20:43:53 +03:00
float holderRadius = lerp_vec ( 4.0 , 5.0 , lerpTimeHover ) ;
float holderHeight = lerp_vec ( 4.0 , 10.0 , lerpTimeHeld ) ;
const float yChange = bb . height ( ) * 0.5f - holderRadius * 0.5f ;
2026-04-08 17:34:50 +03:00
float holderPos = lerp_time < float > ( dd . val , dd . maxData , dd . minData ) * bb . width ( ) ;
2025-07-06 20:43:53 +03:00
SkRect barFull = SkRect : : MakeXYWH ( 0.0f , yChange , holderPos , holderRadius ) ;
SkRect barEmpty = SkRect : : MakeXYWH ( holderPos , yChange , bb . width ( ) - holderPos , holderRadius ) ;
SkPaint barFullP ;
2026-03-20 20:53:59 +03:00
barFullP . setAntiAlias ( skiaAA ) ;
2025-07-06 20:43:53 +03:00
barFullP . setColor ( convert_vec4 < SkColor4f > ( io . theme - > fillColor1 ) ) ;
canvas - > drawRoundRect ( barFull , 5.0f , 5.0f , barFullP ) ;
SkPaint barEmptyP ;
2026-03-20 20:53:59 +03:00
barEmptyP . setAntiAlias ( skiaAA ) ;
2025-07-06 20:43:53 +03:00
barEmptyP . setColor ( convert_vec4 < SkColor4f > ( io . theme - > backColor2 ) ) ;
canvas - > drawRoundRect ( barEmpty , 5.0f , 5.0f , barEmptyP ) ;
canvas - > translate ( holderPos , bb . height ( ) * 0.5f ) ;
SkRect holderRect = SkRect : : MakeLTRB ( - holderRadius , - holderHeight , holderRadius , holderHeight ) ;
SkPaint holderBorderP ;
2026-03-20 20:53:59 +03:00
holderBorderP . setAntiAlias ( skiaAA ) ;
2025-07-06 20:43:53 +03:00
holderBorderP . setStyle ( SkPaint : : kStroke_Style ) ;
holderBorderP . setStrokeWidth ( 3.0f ) ;
holderBorderP . setColor ( convert_vec4 < SkColor4f > ( io . theme - > fillColor1 ) ) ;
canvas - > drawRoundRect ( holderRect , holderRadius , holderRadius , holderBorderP ) ;
SkPaint holderP ;
2026-03-20 20:53:59 +03:00
holderP . setAntiAlias ( skiaAA ) ;
2025-07-06 20:43:53 +03:00
holderP . setColor ( convert_vec4 < SkColor4f > ( io . theme - > backColor2 ) ) ;
canvas - > drawRoundRect ( holderRect , holderRadius , holderRadius , holderP ) ;
canvas - > restore ( ) ;
}
2026-04-02 21:57:26 +03:00
virtual void input_mouse_button_callback ( const InputManager : : MouseButtonCallbackArgs & button ) override {
2026-04-08 17:34:50 +03:00
bool oldIsHeld = dd . isHeld ;
dd . isHeld = mouseHovering & & button . button = = InputManager : : MouseButton : : LEFT & & button . down ;
if ( oldIsHeld & & ! dd . isHeld ) {
2026-04-04 17:52:43 +03:00
gui . set_post_callback_func ( [ & ] {
if ( config . onRelease ) config . onRelease ( ) ;
} ) ;
}
2026-04-08 17:34:50 +03:00
else if ( dd . isHeld & & boundingBox . has_value ( ) )
2026-04-04 17:52:43 +03:00
update_slider_pos ( button . pos , true ) ;
2026-03-27 09:51:53 +03:00
}
2026-04-02 21:57:26 +03:00
virtual void input_mouse_motion_callback ( const InputManager : : MouseMotionCallbackArgs & motion ) override {
2026-04-08 17:34:50 +03:00
if ( dd . isHeld & & boundingBox . has_value ( ) )
2026-04-04 17:52:43 +03:00
update_slider_pos ( motion . pos , false ) ;
2026-03-27 09:51:53 +03:00
}
2025-07-06 20:43:53 +03:00
private :
2026-04-04 17:52:43 +03:00
void update_slider_pos ( const Vector2f & p , bool justHeld ) {
gui . set_post_callback_func ( [ & , p , justHeld ] {
2026-03-31 17:33:09 +03:00
float fracPosOnSlider = ( p . x ( ) - boundingBox . value ( ) . min . x ( ) ) / boundingBox . value ( ) . width ( ) ;
2026-04-08 17:34:50 +03:00
dd . val = * data = static_cast < T > ( std : : clamp < double > ( std : : lerp < double > ( dd . minData , dd . maxData , fracPosOnSlider ) , dd . minData , dd . maxData ) ) ; // Clamp as double then cast so that unsigned types dont wrap on clamp
2026-04-04 17:52:43 +03:00
if ( justHeld & & config . onHold ) config . onHold ( ) ;
if ( config . onChange ) config . onChange ( ) ;
2026-03-27 09:51:53 +03:00
} ) ;
}
2025-07-06 20:43:53 +03:00
2026-03-27 09:51:53 +03:00
T * data = nullptr ;
2025-07-06 20:43:53 +03:00
2026-04-08 17:34:50 +03:00
struct DisplayData {
bool isHeld = false ;
T val = 0.0 ;
T minData = 0.0 ;
T maxData = 1.0 ;
float hoverAnimation = 0.0 ;
float holdAnimation = 0.0 ;
bool operator ! = ( const DisplayData & ) const = default ;
bool operator = = ( const DisplayData & ) const = default ;
} ;
DisplayData dd ;
DisplayData oldDD ;
NumberSliderData config ;
2025-07-06 20:43:53 +03:00
} ;
}