1use crate::{
2 makepad_derive_widget::*,
3 makepad_draw::*,
4 widget::*,
5};
6
7live_design!{
8 link widgets;
9 use link::theme::*;
10 use link::shaders::*;
11
12 pub FoldButtonBase = {{FoldButton}} {}
13
14 pub FoldButton = <FoldButtonBase> {
15 height: 20, width: 15,
16 margin: { left: 0. }
17
18 draw_bg: {
19 instance active: 0.0
20 instance hover: 0.0
21
22 uniform color: (THEME_COLOR_LABEL_INNER)
23 uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
24 uniform color_active: (THEME_COLOR_LABEL_INNER_ACTIVE)
25
26 uniform fade: 1.0
27
28 fn pixel(self) -> vec4 {
29 let sz = 2.5;
30 let c = vec2(5.0, self.rect_size.y * 0.4);
31 let sdf = Sdf2d::viewport(self.pos * self.rect_size);
32 sdf.clear(vec4(0.));
33
34 sdf.rotate(self.active * 0.5 * PI + 0.5 * PI, c.x, c.y);
36 sdf.move_to(c.x - sz, c.y + sz);
37 sdf.line_to(c.x, c.y - sz);
38 sdf.line_to(c.x + sz, c.y + sz);
39 sdf.close_path();
40 sdf.fill(
41 mix(
42 mix(self.color, self.color_hover, self.hover),
43 mix(self.color_active, self.color_hover, self.hover),
44 self.active
45 )
46 );
47 return sdf.result * self.fade;
48 }
49 }
50
51 animator: {
52 hover = {
53 default: off
54 off = {
55 from: {all: Forward {duration: 0.1}}
56 apply: {draw_bg: {hover: 0.0}}
57 }
58
59 on = {
60 from: {all: Snap}
61 apply: {draw_bg: {hover: 1.0}}
62 }
63 }
64
65 active = {
66 default: on
67 off = {
68 from: {all: Forward {duration: 0.2}}
69 ease: ExpDecay {d1: 0.96, d2: 0.97}
70 redraw: true
71 apply: {
72 active: 0.0
73 draw_bg: {active: [{time: 0.0, value: 1.0}, {time: 1.0, value: 0.0}]}
74 }
75 }
76 on = {
77 from: {all: Forward {duration: 0.2}}
78 ease: ExpDecay {d1: 0.98, d2: 0.95}
79 redraw: true
80 apply: {
81 active: 1.0
82 draw_bg: {active: [{time: 0.0, value: 0.0}, {time: 1.0, value: 1.0}]}
83 }
84 }
85 }
86 }
87 }
88}
89
90#[derive(Live, LiveHook, Widget)]
91pub struct FoldButton {
92 #[animator] animator: Animator,
93
94 #[redraw] #[live] draw_bg: DrawQuad,
95 #[live] abs_size: DVec2,
96 #[live] abs_offset: DVec2,
97 #[walk] walk: Walk,
98 #[live] active: f64,
99 #[action_data] #[rust] action_data: WidgetActionData,
100}
101
102#[derive(Clone, Debug, DefaultNone)]
103pub enum FoldButtonAction {
104 None,
105 Opening,
106 Closing,
107 Animating(f64)
108}
109
110impl FoldButton {
111
112 pub fn set_is_open(&mut self, cx: &mut Cx, is_open: bool, animate: Animate) {
113 self.animator_toggle(cx, is_open, animate, id!(active.on), id!(active.off))
114 }
115
116 pub fn draw_walk_fold_button(&mut self, cx: &mut Cx2d, walk: Walk) {
117 self.draw_bg.draw_walk(cx, walk);
118 }
119
120 pub fn area(&mut self)->Area{
121 self.draw_bg.area()
122 }
123
124 pub fn draw_abs(&mut self, cx: &mut Cx2d, pos: DVec2, fade: f64) {
125 self.draw_bg.apply_over(cx, live!{fade: (fade)});
126 self.draw_bg.draw_abs(cx, Rect {
127 pos: pos + self.abs_offset,
128 size: self.abs_size
129 });
130 }
131
132 pub fn opening(&self, actions:&Actions) -> bool {
133 if let Some(item) = actions.find_widget_action(self.widget_uid()) {
134 if let FoldButtonAction::Opening = item.cast() {
135 return true
136 }
137 }
138 false
139 }
140
141 pub fn closing(&self, actions:&Actions) -> bool {
142 if let Some(item) = actions.find_widget_action(self.widget_uid()) {
143 if let FoldButtonAction::Closing = item.cast() {
144 return true
145 }
146 }
147 false
148 }
149
150 pub fn animating(&self, actions:&Actions) -> Option<f64> {
151 if let Some(item) = actions.find_widget_action(self.widget_uid()) {
152 if let FoldButtonAction::Animating(v) = item.cast() {
153 return Some(v)
154 }
155 }
156 None
157 }
158}
159
160impl Widget for FoldButton {
161
162 fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope:&mut Scope) {
163 let uid = self.widget_uid();
164 let res = self.animator_handle_event(cx, event);
165 if res.is_animating() {
166 if self.animator.is_track_animating(cx, id!(active)) {
167 let mut value = [0.0];
168 self.draw_bg.get_instance(cx, id!(active),&mut value);
169 cx.widget_action(uid, &scope.path, FoldButtonAction::Animating(value[0] as f64))
170 }
171 if res.must_redraw(){
172 self.draw_bg.redraw(cx);
173 }
174 };
175
176 match event.hits(cx, self.draw_bg.area()) {
177 Hit::FingerDown(_fe) => {
178 if self.animator_in_state(cx, id!(active.on)) {
179 self.animator_play(cx, id!(active.off));
180 cx.widget_action(uid, &scope.path, FoldButtonAction::Closing)
181 }
182 else {
183 self.animator_play(cx, id!(active.on));
184 cx.widget_action(uid, &scope.path, FoldButtonAction::Opening)
185 }
186 self.animator_play(cx, id!(hover.on));
187 },
188 Hit::FingerHoverIn(_) => {
189 cx.set_cursor(MouseCursor::Hand);
190 self.animator_play(cx, id!(hover.on));
191 }
192 Hit::FingerHoverOut(_) => {
193 self.animator_play(cx, id!(hover.off));
194 }
195 Hit::FingerUp(fe) => if fe.is_over {
196 if fe.device.has_hovers() {
197 self.animator_play(cx, id!(hover.on));
198 }
199 else{
200 self.animator_play(cx, id!(hover.off));
201 }
202 }
203 else {
204 self.animator_play(cx, id!(hover.off));
205 }
206 _ => ()
207 };
208 }
209
210 fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope, walk: Walk) -> DrawStep {
211 self.draw_walk_fold_button(cx, walk);
212 DrawStep::done()
213 }
214}
215
216
217impl FoldButtonRef {
218
219 pub fn opening(&self, actions:&Actions) -> bool {
220 if let Some(item) = actions.find_widget_action(self.widget_uid()) {
221 if let FoldButtonAction::Opening = item.cast() {
222 return true
223 }
224 }
225 false
226 }
227
228 pub fn closing(&self, actions:&Actions) -> bool {
229 if let Some(item) = actions.find_widget_action(self.widget_uid()) {
230 if let FoldButtonAction::Closing = item.cast() {
231 return true
232 }
233 }
234 false
235 }
236
237 pub fn animating(&self, actions:&Actions) -> Option<f64> {
238 if let Some(item) = actions.find_widget_action(self.widget_uid()) {
239 if let FoldButtonAction::Animating(v) = item.cast() {
240 return Some(v)
241 }
242 }
243 None
244 }
245
246 pub fn open_float(&self) -> f64 {
247 if let Some(inner) = self.borrow(){
248 inner.active
249 }
250 else{
251 1.0
252 }
253 }
254}
255