embedded_ui/kit/
focus_input.rs

1// use core::ops::Range;
2
3// use embedded_text::TextBox;
4
5// use crate::{
6//     el::ElId,
7//     event::{Capture, CommonEvent, Event, Propagate},
8//     layout::Layout,
9//     render::Renderer,
10//     size::{Length, Size},
11//     state::{State, StateTag},
12//     style::component_style,
13//     ui::UiCtx,
14//     value::Value,
15//     widget::Widget,
16// };
17
18// #[derive(Clone, Copy)]
19// struct FocusInputState {
20//     is_active: bool,
21//     is_pressed: bool,
22// }
23
24// impl Default for FocusInputState {
25//     fn default() -> Self {
26//         Self { is_active: false, is_pressed: false }
27//     }
28// }
29
30// // const ALPHABET: &[char] = &[
31
32// // ];
33
34// #[derive(Clone, Copy)]
35// pub enum FocusInputStatus {
36//     Normal,
37//     Focused,
38//     Pressed,
39//     Active,
40// }
41
42// component_style! {
43//     pub FocusInputStyle: FocusInputStyler(FocusInputStatus) {
44//         background: background,
45//         border: border,
46//     }
47// }
48
49// pub struct FocusInput<'a, Message, R, S>
50// where
51//     R: Renderer,
52//     S: FocusInputStyler<R::Color>,
53// {
54//     id: ElId,
55//     size: Size<Length>,
56//     // length: usize,
57//     value: Value<String>,
58//     position: usize,
59//     on_change: Option<Box<dyn Fn(&str) -> Message + 'a>>,
60//     class: S::Class<'a>,
61// }
62
63// impl<'a, Message, R, S> FocusInput<'a, Message, R, S>
64// where
65//     R: Renderer,
66//     S: FocusInputStyler<R::Color>,
67// {
68//     pub fn new(value: Value<String>) -> Self {
69//         Self {
70//             id: ElId::unique(),
71//             size: Size::fill(),
72//             // length: 128,
73//             value,
74//             position: 0,
75//             on_change: None,
76//             class: S::default(),
77//         }
78//     }
79
80//     // pub fn length(mut self, length: usize) -> Self {
81//     //     self.length = length;
82//     //     self
83//     // }
84
85//     pub fn width(mut self, width: impl Into<Length>) -> Self {
86//         self.size.width = width.into();
87//         self
88//     }
89
90//     pub fn height(mut self, height: impl Into<Length>) -> Self {
91//         self.size.height = height.into();
92//         self
93//     }
94
95//     // Helpers //
96//     fn status<E: Event>(&self, ctx: &UiCtx<Message>, state: &FocusInputState) -> FocusInputStatus {
97//         match (UiCtx::is_focused::<R, E, S>(&ctx, self), state) {
98//             (_, FocusInputState { is_active: true, .. }) => FocusInputStatus::Active,
99//             (_, FocusInputState { is_pressed: true, .. }) => FocusInputStatus::Pressed,
100//             (true, FocusInputState { is_active: false, is_pressed: false }) => {
101//                 FocusInputStatus::Focused
102//             },
103//             (false, FocusInputState { is_active: false, is_pressed: false }) => {
104//                 FocusInputStatus::Normal
105//             },
106//         }
107//     }
108// }
109
110// impl<'a, Message, R, E, S> Widget<Message, R, E, S> for FocusInput<'a, Message, R, S>
111// where
112//     R: Renderer,
113//     E: Event,
114//     S: FocusInputStyler<R::Color>,
115// {
116//     fn id(&self) -> Option<ElId> {
117//         Some(self.id)
118//     }
119
120//     fn tree_ids(&self) -> Vec<ElId> {
121//         vec![self.id]
122//     }
123
124//     fn size(&self) -> Size<Length> {
125//         self.size
126//     }
127
128//     fn state_tag(&self) -> crate::state::StateTag {
129//         StateTag::of::<FocusInputState>()
130//     }
131
132//     fn state(&self) -> crate::state::State {
133//         State::new(FocusInputState::default())
134//     }
135
136//     fn state_children(&self) -> Vec<crate::state::StateNode> {
137//         vec![]
138//     }
139
140//     fn on_event(
141//         &mut self,
142//         ctx: &mut UiCtx<Message>,
143//         event: E,
144//         state: &mut crate::state::StateNode,
145//     ) -> crate::event::EventResponse<E> {
146//         let focused = ctx.is_focused::<R, E, S>(self);
147//         let current_state = *state.get::<FocusInputState>();
148
149//         if current_state.is_active {
150//             if let Some(offset) = event.as_input_letter_scroll() {
151//                 if self.position >= self.value.get().len() {
152//                     // self.value.get_mut().
153//                 }
154
155//                 let prev_char = self.value.get().chars().nth(self.position).unwrap_or(' ');
156
157//                 const CHAR_ASCII_RANGE: Range<u8> = 32..127;
158//                 const ALPHABET_SIZE: i32 =
159//                     CHAR_ASCII_RANGE.end as i32 - CHAR_ASCII_RANGE.start as i32;
160
161//                 let new_char = ((prev_char as i32 + offset % ALPHABET_SIZE + ALPHABET_SIZE)
162//                     % ALPHABET_SIZE) as u8 as char;
163
164//                 self.value.get_mut()[self.position] = new_char;
165
166//                 if prev_char != new_char {
167//                     if let Some(on_change) = self.on_change.as_ref() {
168//                         ctx.publish((on_change)(&String::from_iter(self.value.get().iter())))
169//                     }
170//                 }
171
172//                 return Capture::Captured.into();
173//             }
174//         }
175
176//         if let Some(common) = event.as_common() {
177//             match common {
178//                 CommonEvent::FocusMove(_) if focused => {
179//                     return Propagate::BubbleUp(self.id, event).into()
180//                 },
181//                 CommonEvent::FocusClickDown if focused => {
182//                     state.get_mut::<FocusInputState>().is_pressed = true;
183//                     return Capture::Captured.into();
184//                 },
185//                 CommonEvent::FocusClickUp if focused => {
186//                     state.get_mut::<FocusInputState>().is_pressed = false;
187
188//                     if current_state.is_pressed {
189//                         state.get_mut::<FocusInputState>().is_active =
190//                             !state.get::<FocusInputState>().is_active;
191
192//                         return Capture::Captured.into();
193//                     }
194//                 },
195//                 CommonEvent::FocusClickDown
196//                 | CommonEvent::FocusClickUp
197//                 | CommonEvent::FocusMove(_) => {
198//                     // Should we reset state on any event? Or only on common
199//                     state.reset::<FocusInputState>();
200//                 },
201//             }
202//         }
203
204//         Propagate::Ignored.into()
205//     }
206
207//     fn layout(
208//         &self,
209//         ctx: &mut UiCtx<Message>,
210//         state: &mut crate::state::StateNode,
211//         styler: &S,
212//         limits: &crate::layout::Limits,
213//     ) -> crate::layout::LayoutNode {
214//         Layout::sized(limits, self.size, |limits| {
215//             limits.resolve_size(self.size.width, self.size.height, Size::zero())
216//         })
217//     }
218
219//     fn draw(
220//         &self,
221//         ctx: &mut UiCtx<Message>,
222//         state: &mut crate::state::StateNode,
223//         renderer: &mut R,
224//         styler: &S,
225//         layout: crate::layout::Layout,
226//     ) {
227//         let state = state.get::<FocusInputState>();
228//         let style = styler.style(&self.class, self.status::<E>(ctx, state));
229
230//         let bounds = layout.bounds();
231
232//         renderer.block(&crate::block::Block {
233//             border: style.border,
234//             rect: bounds.into(),
235//             background: style.background,
236//         });
237
238//         renderer.text(TextBox::new(sel, bounds, character_style))
239//     }
240// }