bevy_ui_builders/text_input/native_input/
components.rs1use bevy::prelude::*;
4use std::collections::VecDeque;
5use super::helpers::{char_to_byte_index};
6use super::types::{CursorStyle, OperationType, TabBehavior};
7
8#[derive(Component, Default)]
10pub struct NativeTextInput;
11
12#[derive(Component, Default)]
14pub struct TextBuffer {
15 pub content: String,
17 pub cursor_pos: usize,
19 pub is_focused: bool,
21}
22
23#[derive(Component, Default)]
25pub struct SelectionState {
26 pub anchor: Option<usize>,
28 pub cursor: usize,
30}
31
32impl SelectionState {
33 pub fn range(&self) -> Option<(usize, usize)> {
35 self.anchor.map(|anchor| {
36 if anchor < self.cursor {
37 (anchor, self.cursor)
38 } else {
39 (self.cursor, anchor)
40 }
41 })
42 }
43
44 pub fn has_selection(&self) -> bool {
46 self.anchor.is_some() && self.anchor != Some(self.cursor)
47 }
48
49 pub fn clear(&mut self) {
51 self.anchor = None;
52 }
53
54 pub fn start_selection(&mut self, pos: usize) {
56 self.anchor = Some(pos);
57 self.cursor = pos;
58 }
59
60 pub fn update_selection(&mut self, pos: usize) {
62 if self.anchor.is_none() {
63 self.anchor = Some(pos);
64 }
65 self.cursor = pos;
66 }
67
68 pub fn get_selected_text<'a>(&self, content: &'a str) -> Option<&'a str> {
70 self.range().map(|(start, end)| {
71 let start_byte = char_to_byte_index(content, start);
72 let end_byte = char_to_byte_index(content, end);
73 &content[start_byte..end_byte]
74 })
75 }
76}
77
78#[derive(Component)]
80pub struct TextInputVisual {
81 pub font: TextFont,
83 pub text_color: Color,
85 pub selection_color: Color,
87 pub cursor_color: Color,
89 pub placeholder: String,
91 pub placeholder_color: Color,
93 pub mask_char: Option<char>,
95}
96
97impl Default for TextInputVisual {
98 fn default() -> Self {
99 Self {
100 font: TextFont::default(),
101 text_color: Color::WHITE,
102 selection_color: Color::srgba(0.3, 0.5, 0.8, 0.3),
103 cursor_color: Color::WHITE,
104 placeholder: String::new(),
105 placeholder_color: Color::srgba(0.5, 0.5, 0.5, 0.5),
106 mask_char: None,
107 }
108 }
109}
110
111#[derive(Component)]
113pub struct CursorVisual {
114 pub blink_timer: Timer,
116 pub visible: bool,
118 pub style: CursorStyle,
120 pub cursor_entity: Option<Entity>,
122 pub selection_entities: Vec<Entity>,
124}
125
126impl Default for CursorVisual {
127 fn default() -> Self {
128 Self {
129 blink_timer: Timer::from_seconds(0.5, TimerMode::Repeating),
130 visible: true,
131 style: CursorStyle::Line,
132 cursor_entity: None,
133 selection_entities: Vec::new(),
134 }
135 }
136}
137
138#[derive(Component, Default)]
140pub struct ScrollViewport {
141 pub offset_x: f32,
143 pub offset_y: f32,
145}
146
147#[derive(Component)]
149pub struct UndoHistory {
150 pub undo_stack: VecDeque<EditOperation>,
152 pub redo_stack: VecDeque<EditOperation>,
154 pub max_size: usize,
156}
157
158impl Default for UndoHistory {
159 fn default() -> Self {
160 Self {
161 undo_stack: VecDeque::new(),
162 redo_stack: VecDeque::new(),
163 max_size: 100,
164 }
165 }
166}
167
168#[derive(Clone, Debug)]
170pub struct EditOperation {
171 pub op_type: OperationType,
173 pub cursor_before: usize,
175 pub cursor_after: usize,
177}
178
179#[derive(Component)]
181pub struct TextInputInner;
182
183#[derive(Component)]
185pub struct TextInputSelection {
186 pub input_entity: Entity,
188}
189
190#[derive(Component)]
192pub struct TextInputSettings {
193 pub multiline: bool,
195 pub max_length: Option<usize>,
197 pub retain_on_submit: bool,
199 pub read_only: bool,
201 pub tab_behavior: TabBehavior,
203}
204
205impl Default for TextInputSettings {
206 fn default() -> Self {
207 Self {
208 multiline: false,
209 max_length: None,
210 retain_on_submit: false,
211 read_only: false,
212 tab_behavior: TabBehavior::NextField,
213 }
214 }
215}