1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
pub struct BoxData {
pub max_char_per_line: usize,
pub max_line: usize,
pub nb_line: usize,
pub scroll_offset: usize,
}
pub struct InputField {
pub input: String,
pub input_mode: InputMode,
character_index: usize, // Cursor index in 1D input
pub input_data: BoxData, // InputField data
}
pub enum InputMode {
Normal,
Editing,
}
impl BoxData {
pub fn new() -> Self {
Self {
max_char_per_line: 1,
max_line: 1,
nb_line: 0,
scroll_offset: 0,
}
}
}
impl InputField {
pub fn new() -> Self {
Self {
input: String::new(),
input_mode: InputMode::Normal,
character_index: 0,
input_data: BoxData::new(),
}
}
// Move cursor left in 1D
pub fn move_cursor_left(&mut self) {
let cursor_moved_left = self.character_index.saturating_sub(1);
self.character_index = self.clamp_cursor(cursor_moved_left);
}
// Move cursor right in 1D
pub fn move_cursor_right(&mut self) {
let cursor_moved_right = self.character_index.saturating_add(1);
self.character_index = self.clamp_cursor(cursor_moved_right);
}
// Move cursor in 2D, y-1
pub fn move_cursor_up(&mut self) {
if self.input_data.nb_line > 1 {
let cursor_moved_up = self
.character_index
.saturating_sub(self.input_data.max_char_per_line);
self.character_index = self.clamp_cursor(cursor_moved_up);
}
}
// Move cursor in 2D, y+1
pub fn move_cursor_down(&mut self) {
if self.input_data.nb_line > 1
&& self
.character_index
.saturating_add(self.input_data.max_char_per_line)
< self.input_len()
{
let cursor_moved_down = self
.character_index
.saturating_add(self.input_data.max_char_per_line);
self.character_index = self.clamp_cursor(cursor_moved_down);
}
}
pub fn enter_char(&mut self, new_char: char) {
let index = self.byte_index();
self.input.insert(index, new_char);
self.move_cursor_right();
}
// Limit the character_index between 0 and inputfield characters number
fn clamp_cursor(&self, new_cursor_pos: usize) -> usize {
new_cursor_pos.clamp(0, self.input.chars().count())
}
pub fn reset_char_index(&mut self) {
self.character_index = 0;
self.input_data.scroll_offset = 0;
}
fn byte_index(&self) -> usize {
self.input
.char_indices()
.map(|(i, _)| i)
.nth(self.character_index)
.unwrap_or(self.input.len())
}
pub fn delete_char(&mut self) {
if self.character_index != 0 {
// Method "remove" is not used on the saved text for deleting the selected char.
// Reason: Using remove on String works on bytes instead of the chars.
// Using remove would require special care because of char boundaries.
let current_index = self.character_index;
let from_left_to_current_index = current_index - 1;
// Getting all characters before the selected character.
let before_char_to_delete = self.input.chars().take(from_left_to_current_index);
// Getting all characters after selected character.
let after_char_to_delete = self.input.chars().skip(current_index);
// Put all characters together except the selected one.
// By leaving the selected one out, it is forgotten and therefore deleted.
self.input = before_char_to_delete.chain(after_char_to_delete).collect();
self.move_cursor_left();
}
}
// Get the max chars allowed per line (not trustable while a line is not completed) and the max
// line allowed
pub fn update_max(&mut self, area_width: u16, area_height: u16) {
let available_width = area_width.saturating_sub(2); // Retirer les bordures
self.input_data.max_char_per_line =
self.input.chars().take(available_width as usize).count();
self.input_data.max_line = area_height.saturating_sub(2) as usize; // retirer les bordures
}
// Get the number of line needed for the inputfield text
pub fn update_nb_line(&mut self, area_width: u16) {
let available_width = area_width.saturating_sub(2); // Retirer les bordures
self.input_data.nb_line =
(self.input.chars().count() as f64 / available_width as f64).ceil() as usize;
}
pub fn input_len(&mut self) -> usize {
self.input.chars().count()
}
// Calculate cursor_y position
pub fn cursor_y(&mut self) -> usize {
if self.input_data.nb_line > 1 {
let mut y = (self.character_index / self.input_data.max_char_per_line) + 1;
// Offsetting the inputfield for y be inside
if y > self.input_data.max_line {
self.input_data.scroll_offset = y - self.input_data.max_line;
y -= self.input_data.scroll_offset;
}
if y < self.input_data.scroll_offset {
self.input_data.scroll_offset = y;
}
return y.max(1);
} else {
return 1;
}
}
// Calculate cursor_x position
pub fn cursor_x(&mut self) -> usize {
if self.input_data.nb_line > 1 {
return self.character_index % self.input_data.max_char_per_line;
} else {
return self.character_index;
}
}
}
|