1
- use egui:: {
2
- vec2, Align2 , Context , Id , InnerResponse , Key , Rect , Response , Rounding , Sense , TextStyle , Ui ,
3
- Widget ,
4
- } ;
1
+ use egui:: { vec2, Align2 , Id , Key , Rect , Response , Rounding , Sense , TextStyle , Ui , Widget } ;
5
2
6
3
const ANIMATION_TIME_SECONDS : f32 = 0.1 ;
7
4
8
5
pub struct SegmentedControl < ' ui , T > {
9
- selectables : & ' ui [ T ] ,
10
6
id : Id ,
7
+ selected : & ' ui mut usize ,
8
+ selectables : & ' ui [ T ] ,
11
9
rounding : Option < Rounding > ,
12
10
text_style : TextStyle ,
13
11
}
14
12
15
- #[ derive( Debug , Default , Clone ) ]
16
- struct SegmentedControlState {
17
- selected : usize ,
18
- }
19
-
20
13
impl < ' ui , T : ToString > SegmentedControl < ' ui , T > {
21
- pub fn new ( id : impl Into < Id > , selectables : & ' ui [ T ] ) -> Self {
14
+ pub fn new ( id : impl Into < Id > , selected : & ' ui mut usize , selectables : & ' ui [ T ] ) -> Self {
22
15
SegmentedControl {
23
16
id : id. into ( ) ,
17
+ selected,
24
18
selectables,
25
19
rounding : None ,
26
20
text_style : TextStyle :: Body ,
@@ -31,25 +25,20 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
31
25
self . rounding = Some ( rounding. into ( ) ) ;
32
26
self
33
27
}
28
+ }
34
29
35
- pub fn ui ( self , ui : & mut Ui ) -> InnerResponse < & ' ui T > {
36
- let mut state = load_state ( ui. ctx ( ) , self . id ) ;
37
- let response = self . show ( ui, & mut state) ;
38
- let selected = & self . selectables [ state. selected ] ;
39
- save_state ( ui. ctx ( ) , self . id , state) ;
40
- InnerResponse :: new ( selected, response)
41
- }
42
-
43
- fn show ( & self , ui : & mut Ui , state : & mut SegmentedControlState ) -> Response {
30
+ impl < T : ToString > Widget for SegmentedControl < ' _ , T > {
31
+ fn ui ( mut self , ui : & mut Ui ) -> Response {
32
+ let this = & mut self ;
44
33
let width = ui. available_width ( ) ;
45
34
let text_style = ui
46
35
. style ( )
47
36
. text_styles
48
- . get ( & self . text_style )
37
+ . get ( & this . text_style )
49
38
. expect ( "failed to get text style" )
50
39
. clone ( ) ;
51
40
let text_size = text_style. size * ui. ctx ( ) . pixels_per_point ( ) ;
52
- let rounding = self
41
+ let rounding = this
53
42
. rounding
54
43
. unwrap_or ( ui. style ( ) . noninteractive ( ) . rounding ) ;
55
44
@@ -58,41 +47,41 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
58
47
if response. contains_pointer ( ) {
59
48
ui. input ( |reader| {
60
49
if reader. key_pressed ( Key :: ArrowLeft ) || reader. key_pressed ( Key :: ArrowDown ) {
61
- state . selected = state . selected . saturating_sub ( 1 ) ;
50
+ * this . selected = this . selected . saturating_sub ( 1 ) ;
62
51
response. mark_changed ( ) ;
63
52
} else if reader. key_pressed ( Key :: ArrowRight ) || reader. key_pressed ( Key :: ArrowUp ) {
64
- state . selected = ( state . selected + 1 ) . min ( self . selectables . len ( ) - 1 ) ;
53
+ * this . selected = ( * this . selected + 1 ) . min ( this . selectables . len ( ) - 1 ) ;
65
54
response. mark_changed ( ) ;
66
55
}
67
56
} )
68
57
}
69
58
painter. rect_filled ( response. rect , rounding, ui. style ( ) . visuals . extreme_bg_color ) ;
70
59
71
- let text_rects = text_rects ( response. rect , self . selectables . len ( ) ) ;
60
+ let text_rects = text_rects ( response. rect , this . selectables . len ( ) ) ;
72
61
let offset = text_rects[ 0 ] . width ( ) ;
73
62
74
63
let translation = ui. ctx ( ) . animate_value_with_time (
75
- self . id ,
76
- offset * state . selected as f32 ,
64
+ this . id ,
65
+ offset * * this . selected as f32 ,
77
66
ANIMATION_TIME_SECONDS ,
78
67
) ;
79
68
let selector_rect = text_rects[ 0 ] . translate ( vec2 ( translation, 0.0 ) ) . shrink ( 2.0 ) ;
80
69
let selector_response =
81
- ui. interact ( selector_rect, self . id . with ( "selector" ) , Sense :: click ( ) ) ;
70
+ ui. interact ( selector_rect, this . id . with ( "selector" ) , Sense :: click ( ) ) ;
82
71
let selector_style = ui. style ( ) . interact ( & selector_response) ;
83
72
painter. rect_filled ( selector_rect, rounding, selector_style. bg_fill ) ;
84
73
85
74
let noninteractive_style = ui. style ( ) . noninteractive ( ) ;
86
75
87
- for ( idx, ( & rect, text) ) in text_rects. iter ( ) . zip ( self . selectables . iter ( ) ) . enumerate ( ) {
88
- let label_response = ui. interact ( rect, self . id . with ( idx) , Sense :: click ( ) ) ;
76
+ for ( idx, ( & rect, text) ) in text_rects. iter ( ) . zip ( this . selectables . iter ( ) ) . enumerate ( ) {
77
+ let label_response = ui. interact ( rect, this . id . with ( idx) , Sense :: click ( ) ) ;
89
78
let style = ui. style ( ) . interact ( & response) ;
90
79
91
- let show_line = idx > 0 && state . selected != idx && state . selected + 1 != idx;
80
+ let show_line = idx > 0 && * this . selected != idx && * this . selected + 1 != idx;
92
81
{
93
82
let animated_height = ui
94
83
. ctx ( )
95
- . animate_bool ( self . id . with ( "vline" ) . with ( idx) , show_line) ;
84
+ . animate_bool ( this . id . with ( "vline" ) . with ( idx) , show_line) ;
96
85
97
86
let height = vec2 ( 0.0 , rect. height ( ) - 4.0 ) ;
98
87
let center = rect. left_center ( ) ;
@@ -107,7 +96,7 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
107
96
}
108
97
109
98
if label_response. clicked ( ) {
110
- state . selected = idx;
99
+ * this . selected = idx;
111
100
response. mark_changed ( ) ;
112
101
}
113
102
painter. text (
@@ -122,24 +111,6 @@ impl<'ui, T: ToString> SegmentedControl<'ui, T> {
122
111
}
123
112
}
124
113
125
- impl < T : ToString > Widget for SegmentedControl < ' _ , T > {
126
- fn ui ( self , ui : & mut Ui ) -> Response {
127
- let mut state = load_state ( ui. ctx ( ) , self . id ) ;
128
- let response = self . show ( ui, & mut state) ;
129
- save_state ( ui. ctx ( ) , self . id , state) ;
130
- response
131
- }
132
- }
133
-
134
- fn load_state ( ctx : & Context , id : Id ) -> SegmentedControlState {
135
- let persisted = ctx. data_mut ( |reader| reader. get_temp ( id) ) ;
136
- persisted. unwrap_or_default ( )
137
- }
138
-
139
- fn save_state ( ctx : & Context , id : Id , state : SegmentedControlState ) {
140
- ctx. data_mut ( |writer| writer. insert_temp ( id, state) ) ;
141
- }
142
-
143
114
fn text_rects ( mut rect : Rect , number_of_texts : usize ) -> Vec < Rect > {
144
115
let base_width = rect. width ( ) / number_of_texts as f32 ;
145
116
let base_rect = {
0 commit comments