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 {
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-03-31 17:33:09 +03:00
void layout ( const Clay_ElementId & id , T * data , T minData , T maxData , const std : : function < void ( ) > & onChange ) {
2026-03-27 09:51:53 +03:00
this - > data = data ;
this - > minData = minData ;
this - > maxData = maxData ;
this - > onChange = onChange ;
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-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-03-27 09:51:53 +03:00
float lerpTimeHover = smooth_two_way_time ( hoverAnimation , io . deltaTime , isHovering , io . theme - > hoverExpandTime ) ;
2025-07-06 20:43:53 +03:00
static BezierEasing easeHeight ( 0.68 , - 1.55 , 0.265 , 2.55 ) ;
2026-03-27 09:51:53 +03:00
float lerpTimeHeld = easeHeight ( smooth_two_way_time ( holdAnimation , io . deltaTime , isHeld , 0.3 ) ) ;
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-03-27 09:51:53 +03:00
float holderPos = lerp_time < float > ( * data , maxData , 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-03-27 09:51:53 +03:00
virtual bool input_mouse_button_callback ( const InputManager : : MouseButtonCallbackArgs & button , bool mouseHovering ) override {
isHovering = mouseHovering ;
isHeld = isHovering & & button . button = = InputManager : : MouseButton : : LEFT & & button . down ;
2026-03-31 17:33:09 +03:00
if ( isHeld & & boundingBox . has_value ( ) )
update_slider_pos ( button . pos ) ;
2026-03-27 09:51:53 +03:00
return Element : : input_mouse_button_callback ( button , mouseHovering ) ;
}
virtual bool input_mouse_motion_callback ( const InputManager : : MouseMotionCallbackArgs & motion , bool mouseHovering ) override {
return Element : : input_mouse_motion_callback ( motion , mouseHovering ) ;
}
2025-07-06 20:43:53 +03:00
private :
2026-03-27 09:51:53 +03:00
void update_slider_pos ( const Vector2f & p ) {
gui . set_post_callback_func ( [ & , p ] {
2026-03-31 17:33:09 +03:00
float fracPosOnSlider = ( p . x ( ) - boundingBox . value ( ) . min . x ( ) ) / boundingBox . value ( ) . width ( ) ;
* data = static_cast < T > ( std : : clamp < double > ( std : : lerp < double > ( minData , maxData , fracPosOnSlider ) , minData , maxData ) ) ; // Clamp as double then cast so that unsigned types dont wrap on clamp
if ( onChange ) 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
bool isHeld = false ;
bool isHovering = false ;
T * data = nullptr ;
T minData = 0.0 ;
T maxData = 1.0 ;
std : : function < void ( ) > onChange ;
2025-07-06 20:43:53 +03:00
float hoverAnimation = 0.0 ;
float holdAnimation = 0.0 ;
} ;
}