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 painted: Vec<(usize, Bounds<Pixels>)>,
31 checkboxes: Vec<(usize, Bounds<Pixels>)>,
34 cells: Vec<(usize, Part, Bounds<Pixels>)>,
36 heights: Heights,
38 reveal: Option<Reveal>,
40}
41
42#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
45pub enum RevealMode {
46 #[default]
48 Center,
49 Nearest,
52}
53
54pub(super) const REVEAL_MARGIN: f32 = 16.0;
57
58#[derive(Clone, Copy)]
60pub(super) struct Reveal {
61 pub(super) range: Selection,
62 pub(super) mode: RevealMode,
63 pub(super) tries: u8,
65 pub(super) scrolled: bool,
67 pub(super) top: Option<Pixels>,
70}
71
72#[derive(Default)]
75pub(super) struct Heights {
76 by_key: HashMap<u64, Pixels>,
79 by_index: Vec<Option<Pixels>>,
82}
83
84pub(super) struct Painted {
91 block: usize,
92 part: Part,
93 range: Range<usize>,
94 layout: TextLayout,
95 shown: Shown,
96}
97
98pub(super) struct PaintedRow {
99 painted: usize,
100 block: usize,
101 part: Part,
102 range: Range<usize>,
103 bounds: Bounds<Pixels>,
104 line_start: usize,
106 wrapped_row: usize,
107 wraps: bool,
109}
110
111impl BlockLayouts {
112 pub fn hit(&self, point: Point<Pixels>) -> Option<(Cursor, Affinity)> {
118 let frames = self.0.borrow();
119 if let Some(row) = frames.rows.iter().find(|row| row.bounds.contains(&point)) {
120 return cursor_in_row(&frames, row, point.x);
121 }
122 frames
123 .rows
124 .iter()
125 .min_by_key(|row| {
126 let bounds = row.bounds;
127 let above = (bounds.origin.y - point.y).abs();
128 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
129 f32::from(above.min(below)) as i64
130 })
131 .and_then(|row| cursor_in_row(&frames, row, point.x))
132 }
133
134 pub fn position(&self, at: Cursor, affinity: Affinity) -> Option<(Point<Pixels>, Pixels)> {
141 let frames = self.0.borrow();
142 let painted = frames.texts.iter().find(|painted| {
143 painted.block == at.block
144 && painted.part == at.part
145 && painted.range.start <= at.offset
146 && at.offset <= painted.range.end
147 })?;
148 let point = caret_position(
149 &painted.layout,
150 painted.shown.at(at.offset - painted.range.start),
151 affinity,
152 )?;
153 Some((point, painted.layout.line_height()))
154 }
155
156 pub fn row_start(&self, at: Cursor, affinity: Affinity) -> Option<Cursor> {
158 let frames = self.0.borrow();
159 let row = row_of(&frames, at, affinity)?;
160 Some(Cursor::new(row.block, row.part, row.range.start))
161 }
162
163 pub fn row_end(&self, at: Cursor, affinity: Affinity) -> Option<(Cursor, Affinity)> {
166 let frames = self.0.borrow();
167 let row = row_of(&frames, at, affinity)?;
168 Some((
169 Cursor::new(row.block, row.part, row.range.end),
170 end_affinity(row),
171 ))
172 }
173
174 pub fn wraps_at(&self, at: Cursor) -> bool {
177 self.0.borrow().rows.iter().any(|row| {
178 row.wraps && row.block == at.block && row.part == at.part && row.range.end == at.offset
179 })
180 }
181
182 pub fn rects(&self, selection: Selection) -> Vec<Bounds<Pixels>> {
190 let (start, end) = selection.ordered();
191 self.0
192 .borrow()
193 .texts
194 .iter()
195 .filter_map(|painted| {
196 let here = Cursor::new(painted.block, painted.part, 0);
197 let (from, to) = (
198 Cursor::new(start.block, start.part, 0),
199 Cursor::new(end.block, end.part, 0),
200 );
201 if here < from || here > to {
202 return None;
203 }
204 let len = painted.range.len();
207 let first = if here == from { start.offset } else { 0 };
208 let last = if here == to { end.offset } else { usize::MAX };
209 let range = first.saturating_sub(painted.range.start).min(len)
210 ..last.saturating_sub(painted.range.start).min(len);
211 let range = painted.shown.range(&range);
212 (range.start < range.end).then(|| range_rects(&painted.layout, &range, 0.0, 0.0))
213 })
214 .flatten()
215 .collect()
216 }
217
218 pub fn step_row(
226 &self,
227 at: Cursor,
228 affinity: Affinity,
229 x: Pixels,
230 down: bool,
231 ) -> Option<(Cursor, Affinity)> {
232 let frames = self.0.borrow();
233 let row = row_of(&frames, at, affinity)?;
234 let ix = frames.rows.iter().position(|r| std::ptr::eq(r, row))?;
235 let next = match down {
236 true => frames.rows.get(ix + 1)?,
237 false => frames.rows.get(ix.checked_sub(1)?)?,
238 };
239 cursor_in_row(&frames, next, x)
240 }
241
242 pub fn over_text(&self, point: Point<Pixels>) -> bool {
249 self.0
250 .borrow()
251 .texts
252 .iter()
253 .any(|painted| painted.layout.bounds().contains(&point))
254 }
255
256 pub fn block_at(&self, point: Point<Pixels>) -> Option<usize> {
258 let blocks = &self.0.borrow().blocks;
259 blocks
260 .iter()
261 .find(|(_, bounds)| bounds.contains(&point))
262 .or_else(|| {
263 blocks.iter().min_by_key(|(_, bounds)| {
264 let above = (bounds.origin.y - point.y).abs();
265 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
266 f32::from(above.min(below)) as i64
267 })
268 })
269 .map(|(ix, _)| *ix)
270 }
271
272 pub fn first_row(&self, ix: usize) -> Option<(Pixels, Pixels)> {
281 let texts = &self.0.borrow().texts;
282 let painted = texts.iter().find(|painted| painted.block == ix)?;
283 Some((
284 painted.layout.bounds().origin.y,
285 painted.layout.line_height(),
286 ))
287 }
288
289 pub fn block_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
291 self.0
292 .borrow()
293 .blocks
294 .iter()
295 .find(|(block, _)| *block == ix)
296 .map(|(_, bounds)| *bounds)
297 }
298
299 pub fn language_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
304 self.0
305 .borrow()
306 .languages
307 .iter()
308 .find(|(block, _)| *block == ix)
309 .map(|(_, bounds)| *bounds)
310 }
311
312 pub fn painted_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
315 self.0
316 .borrow()
317 .painted
318 .iter()
319 .find(|(at, _)| *at == ix)
320 .map(|(_, bounds)| *bounds)
321 }
322
323 pub fn picture_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
328 self.0
329 .borrow()
330 .pictures
331 .iter()
332 .find(|(block, _)| *block == ix)
333 .map(|(_, bounds)| *bounds)
334 }
335
336 pub fn checkbox_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
340 self.0
341 .borrow()
342 .checkboxes
343 .iter()
344 .find(|(block, _)| *block == ix)
345 .map(|(_, bounds)| *bounds)
346 }
347
348 pub fn cell_bounds(&self, ix: usize, part: Part) -> Option<Bounds<Pixels>> {
350 self.0
351 .borrow()
352 .cells
353 .iter()
354 .find(|(block, at, _)| *block == ix && *at == part)
355 .map(|(_, _, bounds)| *bounds)
356 }
357
358 pub fn cell_at(&self, point: Point<Pixels>) -> Option<(usize, Part)> {
360 self.0
361 .borrow()
362 .cells
363 .iter()
364 .find(|(_, _, bounds)| bounds.contains(&point))
365 .map(|(block, part, _)| (*block, *part))
366 }
367
368 pub fn reveal(&self, range: Selection) {
375 self.reveal_with(range, RevealMode::Center);
376 }
377
378 pub fn reveal_with(&self, range: Selection, mode: RevealMode) {
380 self.0.borrow_mut().reveal = Some(Reveal {
381 range,
382 mode,
383 tries: 0,
384 scrolled: false,
385 top: None,
386 });
387 }
388
389 pub(super) fn revealing(&self) -> Option<Reveal> {
390 self.0.borrow().reveal
391 }
392
393 pub(super) fn set_revealing(&self, reveal: Option<Reveal>) {
394 self.0.borrow_mut().reveal = reveal;
395 }
396
397 pub(super) fn record(
398 &self,
399 block: usize,
400 part: Part,
401 range: Range<usize>,
402 layout: TextLayout,
403 shown: Shown,
404 ) {
405 let mut frames = self.0.borrow_mut();
406 let painted = frames.texts.len();
407 record_rows(
408 &mut frames.rows,
409 painted,
410 block,
411 part,
412 &range,
413 &layout,
414 &shown,
415 );
416 frames.texts.push(Painted {
417 block,
418 part,
419 range,
420 layout,
421 shown,
422 });
423 }
424
425 pub(super) fn record_block(&self, ix: usize, bounds: Bounds<Pixels>) {
426 self.0.borrow_mut().blocks.push((ix, bounds));
427 }
428
429 pub(super) fn record_language(&self, ix: usize, bounds: Bounds<Pixels>) {
430 self.0.borrow_mut().languages.push((ix, bounds));
431 }
432
433 pub(super) fn record_picture(&self, ix: usize, bounds: Bounds<Pixels>) {
434 self.0.borrow_mut().pictures.push((ix, bounds));
435 }
436
437 pub(super) fn record_painted(&self, ix: usize, bounds: Bounds<Pixels>) {
438 self.0.borrow_mut().painted.push((ix, bounds));
439 }
440
441 pub(super) fn record_checkbox(&self, ix: usize, bounds: Bounds<Pixels>) {
442 self.0.borrow_mut().checkboxes.push((ix, bounds));
443 }
444
445 pub(super) fn record_cell(&self, ix: usize, part: Part, bounds: Bounds<Pixels>) {
446 self.0.borrow_mut().cells.push((ix, part, bounds));
447 }
448
449 pub(super) fn height(&self, ix: usize, key: u64) -> Option<Pixels> {
452 let heights = &self.0.borrow().heights;
453 heights
454 .by_key
455 .get(&key)
456 .copied()
457 .or_else(|| heights.by_index.get(ix).copied().flatten())
458 }
459
460 pub(super) fn record_height(&self, ix: usize, key: u64, height: Pixels) {
461 let heights = &mut self.0.borrow_mut().heights;
462 heights.by_key.insert(key, height);
463 if heights.by_index.len() <= ix {
464 heights.by_index.resize(ix + 1, None);
465 }
466 heights.by_index[ix] = Some(height);
467 }
468
469 pub(super) fn prune(&self, keys: &[u64]) {
472 let heights = &mut self.0.borrow_mut().heights;
473 heights.by_index.truncate(keys.len());
474 if heights.by_key.len() > 2 * keys.len() {
475 let keep: std::collections::HashSet<u64> = keys.iter().copied().collect();
476 heights.by_key.retain(|key, _| keep.contains(key));
477 }
478 }
479
480 pub(super) fn clear(&self) {
481 let mut frames = self.0.borrow_mut();
482 frames.texts.clear();
483 frames.rows.clear();
484 frames.blocks.clear();
485 frames.languages.clear();
486 frames.pictures.clear();
487 frames.painted.clear();
488 frames.checkboxes.clear();
489 frames.cells.clear();
490 }
491}
492
493pub(super) fn row_contains(row: &PaintedRow, offset: usize) -> bool {
494 row.range.start <= offset && offset <= row.range.end
495}
496
497fn row_of(frames: &Frames, at: Cursor, affinity: Affinity) -> Option<&PaintedRow> {
500 let mut rows = frames
501 .rows
502 .iter()
503 .filter(|row| row.block == at.block && row.part == at.part && row_contains(row, at.offset));
504 let first = rows.next()?;
505 let wrapped = first.wraps && first.range.end == at.offset;
506 match (wrapped, affinity) {
507 (true, Affinity::Downstream) => rows.next().or(Some(first)),
508 _ => Some(first),
509 }
510}
511
512fn end_affinity(row: &PaintedRow) -> Affinity {
514 match row.wraps {
515 true => Affinity::Upstream,
516 false => Affinity::Downstream,
517 }
518}
519
520pub(super) fn cursor_in_row(
521 frames: &Frames,
522 row: &PaintedRow,
523 x: Pixels,
524) -> Option<(Cursor, Affinity)> {
525 let painted = &frames.texts[row.painted];
526 let line = painted.layout.line_layout_for_index(row.line_start)?;
527 let height = row.bounds.size.height;
528 let local = point(
529 x - row.bounds.origin.x,
530 height * (row.wrapped_row as f32 + 0.5),
531 );
532 let (Ok(offset) | Err(offset)) = line.closest_index_for_position(local, height);
533 let offset =
534 (painted.range.start + painted.shown.offset(row.line_start + offset)).min(row.range.end);
535 let affinity = match offset == row.range.end {
536 true => end_affinity(row),
537 false => Affinity::Downstream,
538 };
539 Some((Cursor::new(row.block, row.part, offset), affinity))
540}
541
542pub(super) fn record_rows(
543 rows: &mut Vec<PaintedRow>,
544 painted: usize,
545 block: usize,
546 part: Part,
547 range: &Range<usize>,
548 layout: &TextLayout,
549 shown: &Shown,
550) {
551 let line_height = layout.line_height();
552 let bounds = layout.bounds();
553 let mut origin = bounds.origin;
554 let mut line_start = 0;
555 for line in layout.line_layouts() {
556 let shaped = &line.unwrapped_layout;
557 let row_ends = line
558 .wrap_boundaries()
559 .iter()
560 .map(|wrap| shaped.runs[wrap.run_ix].glyphs[wrap.glyph_ix].index)
561 .chain([line.len()]);
562 let rows_in_line = line.wrap_boundaries().len() + 1;
563 let mut row_start = 0;
564 for (row, row_end) in row_ends.enumerate() {
565 rows.push(PaintedRow {
566 painted,
567 block,
568 part,
569 range: range.start + shown.offset(line_start + row_start)
570 ..range.start + shown.offset(line_start + row_end),
571 bounds: Bounds::new(
572 origin + point(px(0.0), line_height * row as f32),
573 size(bounds.size.width, line_height),
574 ),
575 line_start,
576 wrapped_row: row,
577 wraps: row + 1 < rows_in_line,
578 });
579 row_start = row_end;
580 }
581 origin.y += line.size(line_height).height;
582 line_start += line.len() + 1;
583 }
584}