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 placed: Option<Placed>,
42}
43
44struct Placed {
46 origin: Point<Pixels>,
48 tops: Vec<Pixels>,
50 item_of: super::column::ItemOf,
51}
52
53#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
56pub enum RevealMode {
57 #[default]
59 Center,
60 Nearest,
63}
64
65pub(super) const REVEAL_MARGIN: f32 = 16.0;
68
69#[derive(Clone, Copy)]
71pub(super) struct Reveal {
72 pub(super) range: Selection,
73 pub(super) mode: RevealMode,
74 pub(super) tries: u8,
76 pub(super) scrolled: bool,
78 pub(super) top: Option<Pixels>,
81}
82
83#[derive(Default)]
86pub(super) struct Heights {
87 by_key: HashMap<u64, Pixels>,
90 by_index: Vec<Option<Pixels>>,
93}
94
95pub(super) struct Painted {
102 block: usize,
103 part: Part,
104 range: Range<usize>,
105 layout: TextLayout,
106 shown: Shown,
107}
108
109pub(super) struct PaintedRow {
110 painted: usize,
111 block: usize,
112 part: Part,
113 range: Range<usize>,
114 bounds: Bounds<Pixels>,
115 line_start: usize,
117 wrapped_row: usize,
118 wraps: bool,
120}
121
122impl BlockLayouts {
123 pub fn hit(&self, point: Point<Pixels>) -> Option<(Cursor, Affinity)> {
129 let frames = self.0.borrow();
130 if let Some(row) = frames.rows.iter().find(|row| row.bounds.contains(&point)) {
131 return cursor_in_row(&frames, row, point.x);
132 }
133 frames
134 .rows
135 .iter()
136 .min_by_key(|row| {
137 let bounds = row.bounds;
138 let above = (bounds.origin.y - point.y).abs();
139 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
140 f32::from(above.min(below)) as i64
141 })
142 .and_then(|row| cursor_in_row(&frames, row, point.x))
143 }
144
145 pub fn position(&self, at: Cursor, affinity: Affinity) -> Option<(Point<Pixels>, Pixels)> {
152 let frames = self.0.borrow();
153 let painted = frames.texts.iter().find(|painted| {
154 painted.block == at.block
155 && painted.part == at.part
156 && painted.range.start <= at.offset
157 && at.offset <= painted.range.end
158 })?;
159 let point = caret_position(
160 &painted.layout,
161 painted.shown.at(at.offset - painted.range.start),
162 affinity,
163 )?;
164 Some((point, painted.layout.line_height()))
165 }
166
167 pub fn row_start(&self, at: Cursor, affinity: Affinity) -> Option<Cursor> {
169 let frames = self.0.borrow();
170 let row = row_of(&frames, at, affinity)?;
171 Some(Cursor::new(row.block, row.part, row.range.start))
172 }
173
174 pub fn row_end(&self, at: Cursor, affinity: Affinity) -> Option<(Cursor, Affinity)> {
177 let frames = self.0.borrow();
178 let row = row_of(&frames, at, affinity)?;
179 Some((
180 Cursor::new(row.block, row.part, row.range.end),
181 end_affinity(row),
182 ))
183 }
184
185 pub fn wraps_at(&self, at: Cursor) -> bool {
188 self.0.borrow().rows.iter().any(|row| {
189 row.wraps && row.block == at.block && row.part == at.part && row.range.end == at.offset
190 })
191 }
192
193 pub fn rects(&self, selection: Selection) -> Vec<Bounds<Pixels>> {
201 let (start, end) = selection.ordered();
202 self.0
203 .borrow()
204 .texts
205 .iter()
206 .filter_map(|painted| {
207 let here = Cursor::new(painted.block, painted.part, 0);
208 let (from, to) = (
209 Cursor::new(start.block, start.part, 0),
210 Cursor::new(end.block, end.part, 0),
211 );
212 if here < from || here > to {
213 return None;
214 }
215 let len = painted.range.len();
218 let first = if here == from { start.offset } else { 0 };
219 let last = if here == to { end.offset } else { usize::MAX };
220 let range = first.saturating_sub(painted.range.start).min(len)
221 ..last.saturating_sub(painted.range.start).min(len);
222 let range = painted.shown.range(&range);
223 (range.start < range.end).then(|| range_rects(&painted.layout, &range, 0.0, 0.0))
224 })
225 .flatten()
226 .collect()
227 }
228
229 pub fn step_row(
237 &self,
238 at: Cursor,
239 affinity: Affinity,
240 x: Pixels,
241 down: bool,
242 ) -> Option<(Cursor, Affinity)> {
243 let frames = self.0.borrow();
244 let row = row_of(&frames, at, affinity)?;
245 let ix = frames.rows.iter().position(|r| std::ptr::eq(r, row))?;
246 let next = match down {
247 true => frames.rows.get(ix + 1)?,
248 false => frames.rows.get(ix.checked_sub(1)?)?,
249 };
250 cursor_in_row(&frames, next, x)
251 }
252
253 pub fn over_text(&self, point: Point<Pixels>) -> bool {
260 self.0
261 .borrow()
262 .texts
263 .iter()
264 .any(|painted| painted.layout.bounds().contains(&point))
265 }
266
267 pub fn block_at(&self, point: Point<Pixels>) -> Option<usize> {
269 let blocks = &self.0.borrow().blocks;
270 blocks
271 .iter()
272 .find(|(_, bounds)| bounds.contains(&point))
273 .or_else(|| {
274 blocks.iter().min_by_key(|(_, bounds)| {
275 let above = (bounds.origin.y - point.y).abs();
276 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
277 f32::from(above.min(below)) as i64
278 })
279 })
280 .map(|(ix, _)| *ix)
281 }
282
283 pub fn first_row(&self, ix: usize) -> Option<(Pixels, Pixels)> {
292 let texts = &self.0.borrow().texts;
293 let painted = texts.iter().find(|painted| painted.block == ix)?;
294 Some((
295 painted.layout.bounds().origin.y,
296 painted.layout.line_height(),
297 ))
298 }
299
300 pub fn block_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
302 self.0
303 .borrow()
304 .blocks
305 .iter()
306 .find(|(block, _)| *block == ix)
307 .map(|(_, bounds)| *bounds)
308 }
309
310 pub fn language_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
315 self.0
316 .borrow()
317 .languages
318 .iter()
319 .find(|(block, _)| *block == ix)
320 .map(|(_, bounds)| *bounds)
321 }
322
323 pub fn painted_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
326 self.0
327 .borrow()
328 .painted
329 .iter()
330 .find(|(at, _)| *at == ix)
331 .map(|(_, bounds)| *bounds)
332 }
333
334 pub fn picture_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
339 self.0
340 .borrow()
341 .pictures
342 .iter()
343 .find(|(block, _)| *block == ix)
344 .map(|(_, bounds)| *bounds)
345 }
346
347 pub fn checkbox_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
351 self.0
352 .borrow()
353 .checkboxes
354 .iter()
355 .find(|(block, _)| *block == ix)
356 .map(|(_, bounds)| *bounds)
357 }
358
359 pub fn cell_bounds(&self, ix: usize, part: Part) -> Option<Bounds<Pixels>> {
361 self.0
362 .borrow()
363 .cells
364 .iter()
365 .find(|(block, at, _)| *block == ix && *at == part)
366 .map(|(_, _, bounds)| *bounds)
367 }
368
369 pub fn cell_at(&self, point: Point<Pixels>) -> Option<(usize, Part)> {
371 self.0
372 .borrow()
373 .cells
374 .iter()
375 .find(|(_, _, bounds)| bounds.contains(&point))
376 .map(|(block, part, _)| (*block, *part))
377 }
378
379 pub fn reveal(&self, range: Selection) {
386 self.reveal_with(range, RevealMode::Center);
387 }
388
389 pub fn reveal_with(&self, range: Selection, mode: RevealMode) {
391 self.0.borrow_mut().reveal = Some(Reveal {
392 range,
393 mode,
394 tries: 0,
395 scrolled: false,
396 top: None,
397 });
398 }
399
400 pub(super) fn revealing(&self) -> Option<Reveal> {
401 self.0.borrow().reveal
402 }
403
404 pub(super) fn set_revealing(&self, reveal: Option<Reveal>) {
405 self.0.borrow_mut().reveal = reveal;
406 }
407
408 pub(super) fn record(
409 &self,
410 block: usize,
411 part: Part,
412 range: Range<usize>,
413 layout: TextLayout,
414 shown: Shown,
415 ) {
416 let mut frames = self.0.borrow_mut();
417 let painted = frames.texts.len();
418 record_rows(
419 &mut frames.rows,
420 painted,
421 block,
422 part,
423 &range,
424 &layout,
425 &shown,
426 );
427 frames.texts.push(Painted {
428 block,
429 part,
430 range,
431 layout,
432 shown,
433 });
434 }
435
436 pub(super) fn record_block(&self, ix: usize, bounds: Bounds<Pixels>) {
437 self.0.borrow_mut().blocks.push((ix, bounds));
438 }
439
440 pub(super) fn record_language(&self, ix: usize, bounds: Bounds<Pixels>) {
441 self.0.borrow_mut().languages.push((ix, bounds));
442 }
443
444 pub(super) fn record_picture(&self, ix: usize, bounds: Bounds<Pixels>) {
445 self.0.borrow_mut().pictures.push((ix, bounds));
446 }
447
448 pub(super) fn record_painted(&self, ix: usize, bounds: Bounds<Pixels>) {
449 self.0.borrow_mut().painted.push((ix, bounds));
450 }
451
452 pub(super) fn record_checkbox(&self, ix: usize, bounds: Bounds<Pixels>) {
453 self.0.borrow_mut().checkboxes.push((ix, bounds));
454 }
455
456 pub(super) fn record_cell(&self, ix: usize, part: Part, bounds: Bounds<Pixels>) {
457 self.0.borrow_mut().cells.push((ix, part, bounds));
458 }
459
460 pub(super) fn height(&self, ix: usize, key: u64) -> Option<Pixels> {
463 let heights = &self.0.borrow().heights;
464 heights
465 .by_key
466 .get(&key)
467 .copied()
468 .or_else(|| heights.by_index.get(ix).copied().flatten())
469 }
470
471 pub(super) fn record_height(&self, ix: usize, key: u64, height: Pixels) {
472 let heights = &mut self.0.borrow_mut().heights;
473 heights.by_key.insert(key, height);
474 if heights.by_index.len() <= ix {
475 heights.by_index.resize(ix + 1, None);
476 }
477 heights.by_index[ix] = Some(height);
478 }
479
480 pub(super) fn prune(&self, keys: &[u64]) {
483 let heights = &mut self.0.borrow_mut().heights;
484 heights.by_index.truncate(keys.len());
485 if heights.by_key.len() > 2 * keys.len() {
486 let keep: std::collections::HashSet<u64> = keys.iter().copied().collect();
487 heights.by_key.retain(|key, _| keep.contains(key));
488 }
489 }
490
491 pub fn top(&self, at: Cursor) -> Option<Pixels> {
499 let frames = self.0.borrow();
500 let placed = frames.placed.as_ref()?;
501 if let Some(row) = row_of(&frames, at, Affinity::Downstream) {
502 return Some(row.bounds.top());
503 }
504 let item = (placed.item_of)(at);
505 let top = placed.tops.get(item).or(placed.tops.last())?;
506 Some(placed.origin.y + *top)
507 }
508
509 pub(super) fn place(
512 &self,
513 origin: Point<Pixels>,
514 tops: Vec<Pixels>,
515 item_of: super::column::ItemOf,
516 ) -> bool {
517 let mut frames = self.0.borrow_mut();
518 let moved = frames.placed.as_ref().is_none_or(|placed| {
519 placed.tops.len() != tops.len()
520 || placed
521 .tops
522 .iter()
523 .zip(&tops)
524 .any(|(was, now)| (*was - *now).abs() > px(0.5))
525 });
526 frames.placed = Some(Placed {
527 origin,
528 tops,
529 item_of,
530 });
531 moved
532 }
533
534 pub(super) fn clear(&self) {
535 let mut frames = self.0.borrow_mut();
536 frames.texts.clear();
537 frames.rows.clear();
538 frames.blocks.clear();
539 frames.languages.clear();
540 frames.pictures.clear();
541 frames.painted.clear();
542 frames.checkboxes.clear();
543 frames.cells.clear();
544 }
545}
546
547pub(super) fn row_contains(row: &PaintedRow, offset: usize) -> bool {
548 row.range.start <= offset && offset <= row.range.end
549}
550
551fn row_of(frames: &Frames, at: Cursor, affinity: Affinity) -> Option<&PaintedRow> {
554 let mut rows = frames
555 .rows
556 .iter()
557 .filter(|row| row.block == at.block && row.part == at.part && row_contains(row, at.offset));
558 let first = rows.next()?;
559 let wrapped = first.wraps && first.range.end == at.offset;
560 match (wrapped, affinity) {
561 (true, Affinity::Downstream) => rows.next().or(Some(first)),
562 _ => Some(first),
563 }
564}
565
566fn end_affinity(row: &PaintedRow) -> Affinity {
568 match row.wraps {
569 true => Affinity::Upstream,
570 false => Affinity::Downstream,
571 }
572}
573
574pub(super) fn cursor_in_row(
575 frames: &Frames,
576 row: &PaintedRow,
577 x: Pixels,
578) -> Option<(Cursor, Affinity)> {
579 let painted = &frames.texts[row.painted];
580 let line = painted.layout.line_layout_for_index(row.line_start)?;
581 let height = row.bounds.size.height;
582 let local = point(
583 x - row.bounds.origin.x,
584 height * (row.wrapped_row as f32 + 0.5),
585 );
586 let (Ok(offset) | Err(offset)) = line.closest_index_for_position(local, height);
587 let offset =
588 (painted.range.start + painted.shown.offset(row.line_start + offset)).min(row.range.end);
589 let affinity = match offset == row.range.end {
590 true => end_affinity(row),
591 false => Affinity::Downstream,
592 };
593 Some((Cursor::new(row.block, row.part, offset), affinity))
594}
595
596pub(super) fn record_rows(
597 rows: &mut Vec<PaintedRow>,
598 painted: usize,
599 block: usize,
600 part: Part,
601 range: &Range<usize>,
602 layout: &TextLayout,
603 shown: &Shown,
604) {
605 let line_height = layout.line_height();
606 let bounds = layout.bounds();
607 let mut origin = bounds.origin;
608 let mut line_start = 0;
609 for line in layout.line_layouts() {
610 let shaped = &line.unwrapped_layout;
611 let row_ends = line
612 .wrap_boundaries()
613 .iter()
614 .map(|wrap| shaped.runs[wrap.run_ix].glyphs[wrap.glyph_ix].index)
615 .chain([line.len()]);
616 let rows_in_line = line.wrap_boundaries().len() + 1;
617 let mut row_start = 0;
618 for (row, row_end) in row_ends.enumerate() {
619 rows.push(PaintedRow {
620 painted,
621 block,
622 part,
623 range: range.start + shown.offset(line_start + row_start)
624 ..range.start + shown.offset(line_start + row_end),
625 bounds: Bounds::new(
626 origin + point(px(0.0), line_height * row as f32),
627 size(bounds.size.width, line_height),
628 ),
629 line_start,
630 wrapped_row: row,
631 wraps: row + 1 < rows_in_line,
632 });
633 row_start = row_end;
634 }
635 origin.y += line.size(line_height).height;
636 line_start += line.len() + 1;
637 }
638}