33//! A [`Slider`] has some local [`State`].
44use crate :: core:: event:: { self , Event } ;
55use crate :: core:: layout;
6- use crate :: core:: mouse;
6+ use crate :: core:: mouse:: { self , click } ;
77use crate :: core:: renderer;
88use crate :: core:: touch;
99use crate :: core:: widget:: tree:: { self , Tree } ;
@@ -14,6 +14,8 @@ use crate::core::{
1414
1515use std:: ops:: RangeInclusive ;
1616
17+ use iced_renderer:: core:: keyboard;
18+ use iced_runtime:: keyboard:: KeyCode ;
1719pub use iced_style:: slider:: {
1820 Appearance , Handle , HandleShape , Rail , StyleSheet ,
1921} ;
5052{
5153 range : RangeInclusive < T > ,
5254 step : T ,
55+ step_fine : Option < T > ,
5356 value : T ,
57+ default : Option < T > ,
5458 on_change : Box < dyn Fn ( T ) -> Message + ' a > ,
5559 on_release : Option < Message > ,
5660 width : Length ,
9498
9599 Slider {
96100 value,
101+ default : None ,
97102 range,
98103 step : T :: from ( 1 ) ,
104+ step_fine : None ,
99105 on_change : Box :: new ( on_change) ,
100106 on_release : None ,
101107 width : Length :: Fill ,
@@ -104,6 +110,13 @@ where
104110 }
105111 }
106112
113+ /// Sets the optional default value for the [`Slider`].
114+ /// If set, [`Slider`] will reset to this value when doubled-clicked, ctrl-clicked, or command-clicked.
115+ pub fn default ( mut self , default : impl Into < T > ) -> Self {
116+ self . default = Some ( default. into ( ) ) ;
117+ self
118+ }
119+
107120 /// Sets the release message of the [`Slider`].
108121 /// This is called when the mouse is released from the slider.
109122 ///
@@ -141,6 +154,13 @@ where
141154 self . step = step. into ( ) ;
142155 self
143156 }
157+
158+ /// Sets the optional fine-grained step size for the [`Slider`].
159+ /// If set, this value is used as the step size while shift is pressed.
160+ pub fn step_fine ( mut self , step_fine : impl Into < T > ) -> Self {
161+ self . step_fine = Some ( step_fine. into ( ) ) ;
162+ self
163+ }
144164}
145165
146166impl < ' a , T , Message , Renderer > Widget < Message , Renderer >
@@ -197,8 +217,10 @@ where
197217 shell,
198218 tree. state . downcast_mut :: < State > ( ) ,
199219 & mut self . value ,
220+ self . default ,
200221 & self . range ,
201222 self . step ,
223+ self . step_fine ,
202224 self . on_change . as_ref ( ) ,
203225 & self . on_release ,
204226 )
@@ -262,8 +284,10 @@ pub fn update<Message, T>(
262284 shell : & mut Shell < ' _ , Message > ,
263285 state : & mut State ,
264286 value : & mut T ,
287+ default : Option < T > ,
265288 range : & RangeInclusive < T > ,
266289 step : T ,
290+ step_fine : Option < T > ,
267291 on_change : & dyn Fn ( T ) -> Message ,
268292 on_release : & Option < Message > ,
269293) -> event:: Status
@@ -273,14 +297,19 @@ where
273297{
274298 let is_dragging = state. is_dragging ;
275299
276- let mut change = |cursor_position : Point | {
300+ let change_cursor_position = |cursor_position : Point | -> Option < T > {
277301 let bounds = layout. bounds ( ) ;
278302 let new_value = if cursor_position. x <= bounds. x {
279- * range. start ( )
303+ Some ( * range. start ( ) )
280304 } else if cursor_position. x >= bounds. x + bounds. width {
281- * range. end ( )
305+ Some ( * range. end ( ) )
282306 } else {
283- let step = step. into ( ) ;
307+ let step = match step_fine {
308+ Some ( step_fine) if state. keyboard_modifiers . shift ( ) => {
309+ step_fine. into ( )
310+ }
311+ _ => step. into ( ) ,
312+ } ;
284313 let start = ( * range. start ( ) ) . into ( ) ;
285314 let end = ( * range. end ( ) ) . into ( ) ;
286315
@@ -290,17 +319,67 @@ where
290319 let steps = ( percent * ( end - start) / step) . round ( ) ;
291320 let value = steps * step + start;
292321
293- if let Some ( value) = T :: from_f64 ( value) {
294- value
295- } else {
296- return ;
322+ T :: from_f64 ( value)
323+ } ;
324+
325+ new_value
326+ } ;
327+
328+ let increment = |value : T | -> Option < T > {
329+ let step = match step_fine {
330+ Some ( step_fine) if state. keyboard_modifiers . shift ( ) => {
331+ step_fine. into ( )
332+ }
333+ _ => step. into ( ) ,
334+ } ;
335+
336+ let steps = ( value. into ( ) / step) . round ( ) ;
337+ let new_value = step * ( steps + f64:: from ( 1 ) ) ;
338+
339+ if new_value > ( * range. end ( ) ) . into ( ) {
340+ return Some ( * range. end ( ) ) ;
341+ }
342+
343+ T :: from_f64 ( new_value)
344+ } ;
345+
346+ let decrement = |value : T | -> Option < T > {
347+ let step = match step_fine {
348+ Some ( step_fine) if state. keyboard_modifiers . shift ( ) => {
349+ step_fine. into ( )
297350 }
351+ _ => step. into ( ) ,
298352 } ;
299353
300- if ( ( * value) . into ( ) - new_value. into ( ) ) . abs ( ) > f64:: EPSILON {
301- shell. publish ( ( on_change) ( new_value) ) ;
354+ let steps = ( value. into ( ) / step) . round ( ) ;
355+ let new_value = step * ( steps - f64:: from ( 1 ) ) ;
356+
357+ if new_value < ( * range. start ( ) ) . into ( ) {
358+ return Some ( * range. start ( ) ) ;
359+ }
360+
361+ T :: from_f64 ( new_value)
362+ } ;
363+
364+ enum Change {
365+ Default ,
366+ CursorPosition ( Point ) ,
367+ Increment ,
368+ Decrement ,
369+ }
302370
303- * value = new_value;
371+ let mut change = |change : Change | {
372+ if let Some ( new_value) = match change {
373+ Change :: Default => default,
374+ Change :: CursorPosition ( point) => change_cursor_position ( point) ,
375+ Change :: Increment => increment ( * value) ,
376+ Change :: Decrement => decrement ( * value) ,
377+ } {
378+ if ( ( * value) . into ( ) - new_value. into ( ) ) . abs ( ) > f64:: EPSILON {
379+ shell. publish ( ( on_change) ( new_value) ) ;
380+
381+ * value = new_value;
382+ }
304383 }
305384 } ;
306385
@@ -309,8 +388,31 @@ where
309388 | Event :: Touch ( touch:: Event :: FingerPressed { .. } ) => {
310389 if let Some ( cursor_position) = cursor. position_over ( layout. bounds ( ) )
311390 {
312- change ( cursor_position) ;
313- state. is_dragging = true ;
391+ let click =
392+ mouse:: Click :: new ( cursor_position, state. last_click ) ;
393+
394+ match click. kind ( ) {
395+ click:: Kind :: Single => {
396+ if state. keyboard_modifiers . control ( )
397+ || state. keyboard_modifiers . command ( )
398+ {
399+ change ( Change :: Default ) ;
400+ state. is_dragging = false ;
401+ } else {
402+ change ( Change :: CursorPosition ( cursor_position) ) ;
403+ state. is_dragging = true ;
404+ }
405+ }
406+ click:: Kind :: Double => {
407+ change ( Change :: Default ) ;
408+ state. is_dragging = false ;
409+ }
410+ mouse:: click:: Kind :: Triple => {
411+ state. is_dragging = false ;
412+ }
413+ }
414+
415+ state. last_click = Some ( click) ;
314416
315417 return event:: Status :: Captured ;
316418 }
@@ -330,11 +432,27 @@ where
330432 Event :: Mouse ( mouse:: Event :: CursorMoved { .. } )
331433 | Event :: Touch ( touch:: Event :: FingerMoved { .. } ) => {
332434 if is_dragging {
333- let _ = cursor. position ( ) . map ( change) ;
435+ let _ = cursor
436+ . position ( )
437+ . map ( |point| change ( Change :: CursorPosition ( point) ) ) ;
334438
335439 return event:: Status :: Captured ;
336440 }
337441 }
442+ Event :: Keyboard ( keyboard:: Event :: KeyPressed { key_code, .. } ) => {
443+ if cursor. position_over ( layout. bounds ( ) ) . is_some ( ) {
444+ match key_code {
445+ KeyCode :: Up => change ( Change :: Increment ) ,
446+ KeyCode :: Down => change ( Change :: Decrement ) ,
447+ _ => ( ) ,
448+ }
449+
450+ return event:: Status :: Captured ;
451+ }
452+ }
453+ Event :: Keyboard ( keyboard:: Event :: ModifiersChanged ( modifiers) ) => {
454+ state. keyboard_modifiers = modifiers;
455+ }
338456 _ => { }
339457 }
340458
@@ -459,9 +577,11 @@ pub fn mouse_interaction(
459577}
460578
461579/// The local state of a [`Slider`].
462- #[ derive( Debug , Clone , Copy , PartialEq , Eq , Default ) ]
580+ #[ derive( Debug , Clone , Copy , Default ) ]
463581pub struct State {
464582 is_dragging : bool ,
583+ last_click : Option < mouse:: Click > ,
584+ keyboard_modifiers : keyboard:: Modifiers ,
465585}
466586
467587impl State {
@@ -470,3 +590,11 @@ impl State {
470590 State :: default ( )
471591 }
472592}
593+
594+ impl PartialEq for State {
595+ fn eq ( & self , other : & Self ) -> bool {
596+ self . is_dragging == other. is_dragging
597+ }
598+ }
599+
600+ impl Eq for State { }
0 commit comments