1use super::*;
4
5#[derive(Clone, Debug)]
7pub struct TextSurfaceLine {
8 pub start: usize,
10 pub end: usize,
11 pub rect: [i32; 4],
13 pub carets: Vec<(usize, i32)>,
15}
16impl TextSurfaceLine {
17 fn x(&self, at: usize) -> i32 {
18 self.carets
19 .iter()
20 .rev()
21 .find(|(offset, _)| *offset <= at)
22 .map_or(self.rect[0], |(_, x)| *x)
23 }
24 fn hit(&self, x: i32) -> usize {
25 self.carets
26 .iter()
27 .min_by_key(|(_, px)| (i64::from(*px) - i64::from(x)).abs())
28 .map_or(self.start, |(offset, _)| *offset)
29 }
30}
31impl Ui {
32 #[cfg_attr(jfgui_dev, track_caller)]
38 pub fn textbox_surface(
39 &mut self,
40 id: u32,
41 text: &mut String,
42 cap_flags: u32,
43 lines: &[TextSurfaceLine],
44 ) -> u32 {
45 let _src = self.src_scope();
46 self.m.edit.surface_change = None;
47 self.m.edit.surface_start = None;
48 if lines.is_empty()
49 || lines.len() > 100000
50 || lines.iter().any(|line| {
51 line.start > line.end
52 || !text.is_char_boundary(line.start)
53 || !text.is_char_boundary(line.end)
54 || line.rect[2] < 1
55 || line.rect[3] < 1
56 || line.carets.is_empty()
57 || line.carets.iter().any(|(at, _)| {
58 *at < line.start || *at > line.end || !text.is_char_boundary(*at)
59 })
60 || line.carets.first().map(|(at, _)| *at) != Some(line.start)
61 || line.carets.last().map(|(at, _)| *at) != Some(line.end)
62 || line.carets.windows(2).any(|p| p[0].0 >= p[1].0)
63 || line.carets.len() != text[line.start..line.end].chars().count() + 1
64 })
65 || lines.windows(2).any(|p| p[0].end > p[1].start)
66 {
67 return 0;
68 }
69 let original = text.clone();
70 let mut bytes = core::mem::take(text).into_bytes();
71 core::mem::swap(&mut bytes, &mut self.m.edit.buf);
72 let prior = self.m.edit.surface.replace(lines.to_vec());
73 let flags = self.tb_start(id, cap_flags | TB_MULTI, TB_FLAG_MASK & !TB_PASSWORD);
74 let mut ev = 0;
75 let hb = HB_FOCUS
76 | HB_TEXT
77 | CUR_IBEAM << HB_CURSOR_SHIFT
78 | if flags & ST_DISABLED != 0 {
79 HB_DISABLED
80 } else {
81 0
82 };
83 let mut registered = false;
84 for line in lines {
85 let r = line.rect;
86 let before = self.wp.ctx.hits[self.wp.ctx.hit_cur].len();
87 ev |= self.hit_rect(id, r[0], r[1], r[2], r[3], hb);
88 if let Some(hit) = self.wp.ctx.hits[self.wp.ctx.hit_cur].get_mut(before) {
89 hit.continuation = registered;
90 registered = true;
91 }
92 }
93 let mut editing = self.tb_focus();
94 if editing {
95 self.m.edit.ed_multi = true;
96 self.m.edit.ml_page = 20;
97 let c = &self.wp.ctx;
98 if c.pressed & (1 << BTN_LEFT) != 0 && ev & EV_HOVER != 0 && c.active == id {
99 let at = self.surface_hit(self.ltr_x(c.mx), c.my);
100 self.m.edit.ed_prefx = -1;
101 self.tb_press(ev, at);
102 } else if ev & EV_HELD != 0 && self.m.edit.ed_drag {
103 let at = self.surface_hit(self.ltr_x(c.mx), c.my);
104 self.tb_drag_to(at);
105 } else {
106 self.m.edit.ed_drag = false;
107 }
108 self.tb_keys();
109 self.tb_typed();
110 if self.m.edit.tb_chg {
111 self.m.edit.tb_ev |= EV_ACT;
112 self.repass();
113 }
114 editing = self.m.edit.ed_id == id;
115 }
116 if editing && !self.m.edit.tb_chg {
117 let (a, b) = self.tb_sel();
118 for line in lines {
119 let lo = a.max(line.start);
120 let hi = b.min(line.end);
121 if lo < hi || (lo == hi && a <= line.end && b > line.end) {
122 let x = line.x(lo);
123 let end = line
124 .x(hi)
125 .saturating_add(if b > line.end { self.dp(4) } else { 0 });
126 self.draw_color((self.color(T_ACCENT) & 0x00ffffff) | 0x50000000);
127 self.draw_rect(x, line.rect[1], (end - x).max(1), line.rect[3]);
128 }
129 }
130 let line = &lines[self.surface_line(self.m.edit.ed_caret)];
131 let x = line.x(self.m.edit.ed_caret);
132 if self.tb_caret_on() {
133 self.draw_color(0xff20272b);
134 self.draw_rect(x, line.rect[1], self.hair(), line.rect[3]);
135 }
136 self.ime_pos(x, line.rect[1], line.rect[3]);
137 }
138 self.wp.ctx.last_rect = lines[if editing {
139 self.surface_line(self.m.edit.ed_caret)
140 } else {
141 0
142 }]
143 .rect;
144 let result = self.tb_finish(ev, editing);
145 self.m.edit.surface = prior;
146 core::mem::swap(&mut bytes, &mut self.m.edit.buf);
147 *text = to_string(bytes);
148 if original != *text {
149 let start = self
152 .m
153 .edit
154 .surface_start
155 .unwrap_or(0)
156 .min(original.len())
157 .min(text.len());
158 let start = Self::tb_fix_index(original.as_bytes(), start);
159 let mut suffix = original.as_bytes()[start..]
160 .iter()
161 .rev()
162 .zip(text.as_bytes()[start..].iter().rev())
163 .take_while(|(a, b)| a == b)
164 .count();
165 while !original.is_char_boundary(original.len() - suffix)
166 || !text.is_char_boundary(text.len() - suffix)
167 {
168 suffix -= 1;
169 }
170 self.m.edit.surface_change = Some((
171 start,
172 original.len() - suffix,
173 String::from(&text[start..text.len() - suffix]),
174 ));
175 }
176 result
177 }
178 pub fn textbox_surface_change(&self) -> Option<(usize, usize, String)> {
181 self.m.edit.surface_change.clone()
182 }
183 fn surface_line(&self, offset: usize) -> usize {
184 self.m
185 .edit
186 .surface
187 .as_ref()
188 .unwrap()
189 .iter()
190 .rposition(|l| l.start <= offset)
191 .unwrap_or(0)
192 }
193 fn surface_hit(&self, x: i32, y: i32) -> usize {
194 let lines = self.m.edit.surface.as_ref().unwrap();
195 let line = lines
196 .iter()
197 .min_by_key(|line| {
198 let top = i64::from(line.rect[1]);
199 let end = top + i64::from(line.rect[3]);
200 if i64::from(y) < top {
201 top - i64::from(y)
202 } else {
203 (i64::from(y) - end).max(0)
204 }
205 })
206 .unwrap();
207 Self::tb_fix_index(&self.m.edit.buf, line.hit(x))
208 }
209 pub(super) fn surface_vmove(&mut self, delta: i32, shift: bool) {
210 let lines = self.m.edit.surface.as_ref().unwrap();
211 let current = self.surface_line(self.m.edit.ed_caret);
212 let x = if self.m.edit.ed_prefx < 0 {
213 lines[current].x(self.m.edit.ed_caret)
214 } else {
215 self.m.edit.ed_prefx
216 };
217 let next = current as i64 + i64::from(delta);
218 let at = if next < 0 {
219 0
220 } else if next >= lines.len() as i64 {
221 self.m.edit.buf.len()
222 } else {
223 Self::tb_fix_index(&self.m.edit.buf, lines[next as usize].hit(x))
224 };
225 self.tb_move(at, shift);
226 self.m.edit.ed_prefx = x;
227 }
228}