1use super::*;
4
5#[derive(Clone, Default)]
12pub struct BlockLayouts(Rc<RefCell<Frames>>);
13
14#[derive(Default)]
15pub(super) struct Frames {
16 texts: Vec<Painted>,
17 rows: Vec<PaintedRow>,
18 blocks: Vec<(usize, Bounds<Pixels>)>,
21 languages: Vec<(usize, Bounds<Pixels>)>,
24 pictures: Vec<(usize, Bounds<Pixels>)>,
28 checkboxes: Vec<(usize, Bounds<Pixels>)>,
31 cells: Vec<(usize, Part, Bounds<Pixels>)>,
33 heights: Heights,
35 reveal: Option<Reveal>,
37}
38
39#[derive(Clone, Copy)]
41pub(super) struct Reveal {
42 pub(super) range: Selection,
43 pub(super) tries: u8,
45 pub(super) top: Option<Pixels>,
48}
49
50#[derive(Default)]
53pub(super) struct Heights {
54 by_key: HashMap<u64, Pixels>,
57 by_index: Vec<Option<Pixels>>,
60}
61
62pub(super) struct Painted {
69 block: usize,
70 part: Part,
71 range: Range<usize>,
72 layout: TextLayout,
73 shown: Shown,
74}
75
76pub(super) struct PaintedRow {
77 painted: usize,
78 block: usize,
79 part: Part,
80 range: Range<usize>,
81 bounds: Bounds<Pixels>,
82 line_start: usize,
84 wrapped_row: usize,
85}
86
87impl BlockLayouts {
88 pub fn hit(&self, point: Point<Pixels>) -> Option<Cursor> {
94 let frames = self.0.borrow();
95 if let Some(row) = frames.rows.iter().find(|row| row.bounds.contains(&point)) {
96 return cursor_in_row(&frames, row, point.x);
97 }
98 frames
99 .rows
100 .iter()
101 .min_by_key(|row| {
102 let bounds = row.bounds;
103 let above = (bounds.origin.y - point.y).abs();
104 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
105 f32::from(above.min(below)) as i64
106 })
107 .and_then(|row| cursor_in_row(&frames, row, point.x))
108 }
109
110 pub fn position(&self, at: Cursor) -> Option<(Point<Pixels>, Pixels)> {
116 let frames = self.0.borrow();
117 let painted = frames.texts.iter().find(|painted| {
118 painted.block == at.block
119 && painted.part == at.part
120 && painted.range.start <= at.offset
121 && at.offset <= painted.range.end
122 })?;
123 let point = painted
124 .layout
125 .position_for_index(painted.shown.at(at.offset - painted.range.start))?;
126 Some((point, painted.layout.line_height()))
127 }
128
129 pub fn rects(&self, selection: Selection) -> Vec<Bounds<Pixels>> {
137 let (start, end) = selection.ordered();
138 self.0
139 .borrow()
140 .texts
141 .iter()
142 .filter_map(|painted| {
143 let here = Cursor::new(painted.block, painted.part, 0);
144 let (from, to) = (
145 Cursor::new(start.block, start.part, 0),
146 Cursor::new(end.block, end.part, 0),
147 );
148 if here < from || here > to {
149 return None;
150 }
151 let len = painted.range.len();
154 let first = if here == from { start.offset } else { 0 };
155 let last = if here == to { end.offset } else { usize::MAX };
156 let range = first.saturating_sub(painted.range.start).min(len)
157 ..last.saturating_sub(painted.range.start).min(len);
158 let range = painted.shown.range(&range);
159 (range.start < range.end).then(|| range_rects(&painted.layout, &range, 0.0, 0.0))
160 })
161 .flatten()
162 .collect()
163 }
164
165 pub fn step_row(
176 &self,
177 at: Cursor,
178 from: Point<Pixels>,
179 down: bool,
180 ) -> Option<(Cursor, Pixels)> {
181 let frames = self.0.borrow();
182 let ix = frames
183 .rows
184 .iter()
185 .position(|row| {
186 row.block == at.block
187 && row.part == at.part
188 && row_contains(row, at.offset)
189 && row.bounds.origin.y <= from.y
190 && from.y < row.bounds.origin.y + row.bounds.size.height
191 })
192 .or_else(|| {
193 frames.rows.iter().position(|row| {
194 row.block == at.block && row.part == at.part && row_contains(row, at.offset)
195 })
196 })?;
197 let next = match down {
198 true => frames.rows.get(ix + 1)?,
199 false => frames.rows.get(ix.checked_sub(1)?)?,
200 };
201 Some((cursor_in_row(&frames, next, from.x)?, next.bounds.origin.y))
202 }
203
204 pub fn over_text(&self, point: Point<Pixels>) -> bool {
211 self.0
212 .borrow()
213 .texts
214 .iter()
215 .any(|painted| painted.layout.bounds().contains(&point))
216 }
217
218 pub fn block_at(&self, point: Point<Pixels>) -> Option<usize> {
220 let blocks = &self.0.borrow().blocks;
221 blocks
222 .iter()
223 .find(|(_, bounds)| bounds.contains(&point))
224 .or_else(|| {
225 blocks.iter().min_by_key(|(_, bounds)| {
226 let above = (bounds.origin.y - point.y).abs();
227 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
228 f32::from(above.min(below)) as i64
229 })
230 })
231 .map(|(ix, _)| *ix)
232 }
233
234 pub fn first_row(&self, ix: usize) -> Option<(Pixels, Pixels)> {
243 let texts = &self.0.borrow().texts;
244 let painted = texts.iter().find(|painted| painted.block == ix)?;
245 Some((
246 painted.layout.bounds().origin.y,
247 painted.layout.line_height(),
248 ))
249 }
250
251 pub fn block_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
253 self.0
254 .borrow()
255 .blocks
256 .iter()
257 .find(|(block, _)| *block == ix)
258 .map(|(_, bounds)| *bounds)
259 }
260
261 pub fn language_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
266 self.0
267 .borrow()
268 .languages
269 .iter()
270 .find(|(block, _)| *block == ix)
271 .map(|(_, bounds)| *bounds)
272 }
273
274 pub fn picture_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
279 self.0
280 .borrow()
281 .pictures
282 .iter()
283 .find(|(block, _)| *block == ix)
284 .map(|(_, bounds)| *bounds)
285 }
286
287 pub fn checkbox_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
291 self.0
292 .borrow()
293 .checkboxes
294 .iter()
295 .find(|(block, _)| *block == ix)
296 .map(|(_, bounds)| *bounds)
297 }
298
299 pub fn cell_bounds(&self, ix: usize, part: Part) -> Option<Bounds<Pixels>> {
301 self.0
302 .borrow()
303 .cells
304 .iter()
305 .find(|(block, at, _)| *block == ix && *at == part)
306 .map(|(_, _, bounds)| *bounds)
307 }
308
309 pub fn cell_at(&self, point: Point<Pixels>) -> Option<(usize, Part)> {
311 self.0
312 .borrow()
313 .cells
314 .iter()
315 .find(|(_, _, bounds)| bounds.contains(&point))
316 .map(|(block, part, _)| (*block, *part))
317 }
318
319 pub fn reveal(&self, range: Selection) {
326 self.0.borrow_mut().reveal = Some(Reveal {
327 range,
328 tries: 0,
329 top: None,
330 });
331 }
332
333 pub(super) fn revealing(&self) -> Option<Reveal> {
334 self.0.borrow().reveal
335 }
336
337 pub(super) fn set_revealing(&self, reveal: Option<Reveal>) {
338 self.0.borrow_mut().reveal = reveal;
339 }
340
341 pub(super) fn record(
342 &self,
343 block: usize,
344 part: Part,
345 range: Range<usize>,
346 layout: TextLayout,
347 shown: Shown,
348 ) {
349 let mut frames = self.0.borrow_mut();
350 let painted = frames.texts.len();
351 record_rows(
352 &mut frames.rows,
353 painted,
354 block,
355 part,
356 &range,
357 &layout,
358 &shown,
359 );
360 frames.texts.push(Painted {
361 block,
362 part,
363 range,
364 layout,
365 shown,
366 });
367 }
368
369 pub(super) fn record_block(&self, ix: usize, bounds: Bounds<Pixels>) {
370 self.0.borrow_mut().blocks.push((ix, bounds));
371 }
372
373 pub(super) fn record_language(&self, ix: usize, bounds: Bounds<Pixels>) {
374 self.0.borrow_mut().languages.push((ix, bounds));
375 }
376
377 pub(super) fn record_picture(&self, ix: usize, bounds: Bounds<Pixels>) {
378 self.0.borrow_mut().pictures.push((ix, bounds));
379 }
380
381 pub(super) fn record_checkbox(&self, ix: usize, bounds: Bounds<Pixels>) {
382 self.0.borrow_mut().checkboxes.push((ix, bounds));
383 }
384
385 pub(super) fn record_cell(&self, ix: usize, part: Part, bounds: Bounds<Pixels>) {
386 self.0.borrow_mut().cells.push((ix, part, bounds));
387 }
388
389 pub(super) fn height(&self, ix: usize, key: u64) -> Option<Pixels> {
392 let heights = &self.0.borrow().heights;
393 heights
394 .by_key
395 .get(&key)
396 .copied()
397 .or_else(|| heights.by_index.get(ix).copied().flatten())
398 }
399
400 pub(super) fn record_height(&self, ix: usize, key: u64, height: Pixels) {
401 let heights = &mut self.0.borrow_mut().heights;
402 heights.by_key.insert(key, height);
403 if heights.by_index.len() <= ix {
404 heights.by_index.resize(ix + 1, None);
405 }
406 heights.by_index[ix] = Some(height);
407 }
408
409 pub(super) fn prune(&self, keys: &[u64]) {
412 let heights = &mut self.0.borrow_mut().heights;
413 heights.by_index.truncate(keys.len());
414 if heights.by_key.len() > 2 * keys.len() {
415 let keep: std::collections::HashSet<u64> = keys.iter().copied().collect();
416 heights.by_key.retain(|key, _| keep.contains(key));
417 }
418 }
419
420 pub(super) fn clear(&self) {
421 let mut frames = self.0.borrow_mut();
422 frames.texts.clear();
423 frames.rows.clear();
424 frames.blocks.clear();
425 frames.languages.clear();
426 frames.pictures.clear();
427 frames.checkboxes.clear();
428 frames.cells.clear();
429 }
430}
431
432pub(super) fn row_contains(row: &PaintedRow, offset: usize) -> bool {
433 row.range.start <= offset && offset <= row.range.end
434}
435
436pub(super) fn cursor_in_row(frames: &Frames, row: &PaintedRow, x: Pixels) -> Option<Cursor> {
437 let painted = &frames.texts[row.painted];
438 let line = painted.layout.line_layout_for_index(row.line_start)?;
439 let height = row.bounds.size.height;
440 let local = point(
441 x - row.bounds.origin.x,
442 height * (row.wrapped_row as f32 + 0.5),
443 );
444 let (Ok(offset) | Err(offset)) = line.closest_index_for_position(local, height);
445 let offset = painted.range.start + painted.shown.offset(row.line_start + offset);
446 Some(Cursor::new(row.block, row.part, offset.min(row.range.end)))
447}
448
449pub(super) fn record_rows(
450 rows: &mut Vec<PaintedRow>,
451 painted: usize,
452 block: usize,
453 part: Part,
454 range: &Range<usize>,
455 layout: &TextLayout,
456 shown: &Shown,
457) {
458 let line_height = layout.line_height();
459 let bounds = layout.bounds();
460 let mut origin = bounds.origin;
461 let mut line_start = 0;
462 for line in layout.line_layouts() {
463 let shaped = &line.unwrapped_layout;
464 let row_ends = line
465 .wrap_boundaries()
466 .iter()
467 .map(|wrap| shaped.runs[wrap.run_ix].glyphs[wrap.glyph_ix].index)
468 .chain([line.len()]);
469 let mut row_start = 0;
470 for (row, row_end) in row_ends.enumerate() {
471 rows.push(PaintedRow {
472 painted,
473 block,
474 part,
475 range: range.start + shown.offset(line_start + row_start)
476 ..range.start + shown.offset(line_start + row_end),
477 bounds: Bounds::new(
478 origin + point(px(0.0), line_height * row as f32),
479 size(bounds.size.width, line_height),
480 ),
481 line_start,
482 wrapped_row: row,
483 });
484 row_start = row_end;
485 }
486 origin.y += line.size(line_height).height;
487 line_start += line.len() + 1;
488 }
489}