@@ -13,6 +13,7 @@ namespace BaseLib.Config.UI;
1313// We don't inherit from NSettingsSlider because it's too rigid (forces % in the format, forces step of 5, fixed width)
1414public partial class NConfigSlider : Control
1515{
16+ public static readonly Type [ ] SupportedTypes = [ typeof ( int ) , typeof ( float ) , typeof ( double ) ] ;
1617 private ModConfig ? _config ;
1718 private PropertyInfo ? _property ;
1819 private string _displayFormat = "{0}" ;
@@ -56,6 +57,8 @@ public NConfigSlider()
5657 public double MaxValue { get ; private set ; }
5758 public double Step => _slider . Step ;
5859
60+ private static bool IsInteger ( double value ) => Math . Abs ( value - Math . Round ( value ) ) < 1e-6 ;
61+
5962 /// <summary>
6063 /// Updates the slider's limits (and optionally step) atomically, ensuring no issues where e.g. min > max occur,
6164 /// even briefly.<br/>
@@ -68,15 +71,34 @@ public void SetRange(double min, double max, double? step = null)
6871 if ( min >= max )
6972 throw new ArgumentException ( $ "Invalid slider range: min ({ min } ) must be less than max ({ max } ).") ;
7073
74+ if ( _property ? . PropertyType == typeof ( int ) )
75+ {
76+ if ( ! IsInteger ( min ) || ! IsInteger ( max ) )
77+ throw new ArgumentException ( "Invalid slider values: min and max must be integers for property type int" ) ;
78+
79+ min = Math . Round ( min ) ;
80+ max = Math . Round ( max ) ;
81+
82+ if ( step . HasValue )
83+ {
84+ if ( ! IsInteger ( step . Value ) )
85+ throw new ArgumentException ( "Invalid slider values: step must be integer for property type int" ) ;
86+
87+ step = Math . Round ( step . Value ) ;
88+ }
89+ }
90+
7191 // We use an offset to enable negative value support in NSlider
7292 var currentRealValue = _slider . Value + MinValue ;
7393
7494 MinValue = min ;
7595 MaxValue = max ;
76- if ( step != null ) _slider . Step = step . Value ;
7796
78- // _slider.MinValue is always 0, so we don't touch it here even if _realMin changes
97+ // The internal NSlider does not support negative numbers, so we force it to run from 0 and up, and handle the
98+ // "real" values manually
99+ _slider . MinValue = 0 ;
79100 _slider . MaxValue = MaxValue - MinValue ;
101+ if ( step != null ) _slider . Step = step . Value ;
80102 RecalculateMinRepeatDelay ( ) ;
81103
82104 // NSlider.SetValueWithoutAnimation crashes unless its _Ready has executed, but if SetRange is called prior
@@ -111,45 +133,34 @@ public override void _Ready()
111133 Connect ( Godot . Control . SignalName . FocusEntered , Callable . From ( OnFocus ) ) ;
112134 Connect ( Godot . Control . SignalName . FocusExited , Callable . From ( OnUnfocus ) ) ;
113135
136+ _config ! . OnConfigReloaded += SetFromProperty ;
137+
114138 _fullyInitialized = true ;
115139 }
116140
117141 public void Initialize ( ModConfig modConfig , PropertyInfo property )
118142 {
119- if ( property . PropertyType != typeof ( double ) )
120- throw new ArgumentException ( "Attempted to assign NConfigSlider a non-double property" ) ;
143+ if ( ! SupportedTypes . Contains ( property . PropertyType ) )
144+ throw new ArgumentException ( "Attempted to initialize NConfigSlider with an unsupported property type. " +
145+ $ "Supported types: { string . Join < Type > ( ", " , SupportedTypes ) } ") ;
121146
122147 _config = modConfig ;
123148 _property = property ;
124149
125- var rangeAttr = property . GetCustomAttribute < SliderRangeAttribute > ( ) ;
126150 var formatAttr = property . GetCustomAttribute < SliderLabelFormatAttribute > ( ) ;
151+ _displayFormat = formatAttr ? . Format ?? "{0}" ;
127152
153+ var rangeAttr = property . GetCustomAttribute < SliderRangeAttribute > ( ) ;
128154 var min = rangeAttr ? . Min ?? 0 ;
129155 var max = rangeAttr ? . Max ?? 100 ;
130156 var step = rangeAttr ? . Step ?? 1 ;
131- _displayFormat = formatAttr ? . Format ?? "{0}" ;
132-
133- if ( min >= max )
134- throw new ArgumentException ( $ "Invalid slider range: min ({ min } ) must be less than max ({ max } ).") ;
135-
136- MinValue = min ;
137- MaxValue = max ;
138-
139- // Force the internal Godot NSlider to run from 0 upwards, since it does not support negative numbers
140- _slider . MinValue = 0 ;
141- _slider . MaxValue = MaxValue - MinValue ;
142- _slider . Step = step ;
143-
144- RecalculateMinRepeatDelay ( ) ;
145-
146- _config . OnConfigReloaded += SetFromProperty ;
157+ SetRange ( min , max , step ) ;
147158 }
148159
149160 private void SetFromProperty ( )
150161 {
151- var propValue = ( double ) _property ! . GetValue ( null ) ! ;
152- SetValue ( propValue ) ;
162+ var rawValue = _property ! . GetValue ( null ) ! ;
163+ SetValue ( Convert . ToDouble ( rawValue ) ) ;
153164 }
154165
155166 private void SetValue ( double value )
@@ -160,7 +171,7 @@ private void SetValue(double value)
160171
161172 // Clamp always returns one of its parameters, so exactness isn't an issue here
162173 // ReSharper disable once CompareOfFloatsByEqualityOperator
163- if ( value != clampedValue ) _property ? . SetValue ( null , clampedValue ) ;
174+ if ( value != clampedValue ) _property ? . SetValue ( null , Convert . ChangeType ( clampedValue , _property . PropertyType ) ) ;
164175 }
165176
166177 private void OnValueChanged ( double proxyValue )
@@ -175,7 +186,7 @@ private void OnValueChanged(double proxyValue)
175186 realValue = Math . Round ( realValue , decimalPlaces ) ;
176187 }
177188
178- _property ? . SetValue ( null , realValue ) ;
189+ _property ? . SetValue ( null , Convert . ChangeType ( realValue , _property . PropertyType ) ) ;
179190 _config ? . Changed ( ) ;
180191 UpdateLabel ( realValue ) ;
181192 }
0 commit comments