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}
108
109impl BlockLayouts {
110 pub fn hit(&self, point: Point<Pixels>) -> Option<Cursor> {
116 let frames = self.0.borrow();
117 if let Some(row) = frames.rows.iter().find(|row| row.bounds.contains(&point)) {
118 return cursor_in_row(&frames, row, point.x);
119 }
120 frames
121 .rows
122 .iter()
123 .min_by_key(|row| {
124 let bounds = row.bounds;
125 let above = (bounds.origin.y - point.y).abs();
126 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
127 f32::from(above.min(below)) as i64
128 })
129 .and_then(|row| cursor_in_row(&frames, row, point.x))
130 }
131
132 pub fn position(&self, at: Cursor) -> Option<(Point<Pixels>, Pixels)> {
138 let frames = self.0.borrow();
139 let painted = frames.texts.iter().find(|painted| {
140 painted.block == at.block
141 && painted.part == at.part
142 && painted.range.start <= at.offset
143 && at.offset <= painted.range.end
144 })?;
145 let point = painted
146 .layout
147 .position_for_index(painted.shown.at(at.offset - painted.range.start))?;
148 Some((point, painted.layout.line_height()))
149 }
150
151 pub fn rects(&self, selection: Selection) -> Vec<Bounds<Pixels>> {
159 let (start, end) = selection.ordered();
160 self.0
161 .borrow()
162 .texts
163 .iter()
164 .filter_map(|painted| {
165 let here = Cursor::new(painted.block, painted.part, 0);
166 let (from, to) = (
167 Cursor::new(start.block, start.part, 0),
168 Cursor::new(end.block, end.part, 0),
169 );
170 if here < from || here > to {
171 return None;
172 }
173 let len = painted.range.len();
176 let first = if here == from { start.offset } else { 0 };
177 let last = if here == to { end.offset } else { usize::MAX };
178 let range = first.saturating_sub(painted.range.start).min(len)
179 ..last.saturating_sub(painted.range.start).min(len);
180 let range = painted.shown.range(&range);
181 (range.start < range.end).then(|| range_rects(&painted.layout, &range, 0.0, 0.0))
182 })
183 .flatten()
184 .collect()
185 }
186
187 pub fn step_row(
198 &self,
199 at: Cursor,
200 from: Point<Pixels>,
201 down: bool,
202 ) -> Option<(Cursor, Pixels)> {
203 let frames = self.0.borrow();
204 let ix = frames
205 .rows
206 .iter()
207 .position(|row| {
208 row.block == at.block
209 && row.part == at.part
210 && row_contains(row, at.offset)
211 && row.bounds.origin.y <= from.y
212 && from.y < row.bounds.origin.y + row.bounds.size.height
213 })
214 .or_else(|| {
215 frames.rows.iter().position(|row| {
216 row.block == at.block && row.part == at.part && row_contains(row, at.offset)
217 })
218 })?;
219 let next = match down {
220 true => frames.rows.get(ix + 1)?,
221 false => frames.rows.get(ix.checked_sub(1)?)?,
222 };
223 Some((cursor_in_row(&frames, next, from.x)?, next.bounds.origin.y))
224 }
225
226 pub fn over_text(&self, point: Point<Pixels>) -> bool {
233 self.0
234 .borrow()
235 .texts
236 .iter()
237 .any(|painted| painted.layout.bounds().contains(&point))
238 }
239
240 pub fn block_at(&self, point: Point<Pixels>) -> Option<usize> {
242 let blocks = &self.0.borrow().blocks;
243 blocks
244 .iter()
245 .find(|(_, bounds)| bounds.contains(&point))
246 .or_else(|| {
247 blocks.iter().min_by_key(|(_, bounds)| {
248 let above = (bounds.origin.y - point.y).abs();
249 let below = (bounds.origin.y + bounds.size.height - point.y).abs();
250 f32::from(above.min(below)) as i64
251 })
252 })
253 .map(|(ix, _)| *ix)
254 }
255
256 pub fn first_row(&self, ix: usize) -> Option<(Pixels, Pixels)> {
265 let texts = &self.0.borrow().texts;
266 let painted = texts.iter().find(|painted| painted.block == ix)?;
267 Some((
268 painted.layout.bounds().origin.y,
269 painted.layout.line_height(),
270 ))
271 }
272
273 pub fn block_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
275 self.0
276 .borrow()
277 .blocks
278 .iter()
279 .find(|(block, _)| *block == ix)
280 .map(|(_, bounds)| *bounds)
281 }
282
283 pub fn language_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
288 self.0
289 .borrow()
290 .languages
291 .iter()
292 .find(|(block, _)| *block == ix)
293 .map(|(_, bounds)| *bounds)
294 }
295
296 pub fn painted_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
299 self.0
300 .borrow()
301 .painted
302 .iter()
303 .find(|(at, _)| *at == ix)
304 .map(|(_, bounds)| *bounds)
305 }
306
307 pub fn picture_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
312 self.0
313 .borrow()
314 .pictures
315 .iter()
316 .find(|(block, _)| *block == ix)
317 .map(|(_, bounds)| *bounds)
318 }
319
320 pub fn checkbox_bounds(&self, ix: usize) -> Option<Bounds<Pixels>> {
324 self.0
325 .borrow()
326 .checkboxes
327 .iter()
328 .find(|(block, _)| *block == ix)
329 .map(|(_, bounds)| *bounds)
330 }
331
332 pub fn cell_bounds(&self, ix: usize, part: Part) -> Option<Bounds<Pixels>> {
334 self.0
335 .borrow()
336 .cells
337 .iter()
338 .find(|(block, at, _)| *block == ix && *at == part)
339 .map(|(_, _, bounds)| *bounds)
340 }
341
342 pub fn cell_at(&self, point: Point<Pixels>) -> Option<(usize, Part)> {
344 self.0
345 .borrow()
346 .cells
347 .iter()
348 .find(|(_, _, bounds)| bounds.contains(&point))
349 .map(|(block, part, _)| (*block, *part))
350 }
351
352 pub fn reveal(&self, range: Selection) {
359 self.reveal_with(range, RevealMode::Center);
360 }
361
362 pub fn reveal_with(&self, range: Selection, mode: RevealMode) {
364 self.0.borrow_mut().reveal = Some(Reveal {
365 range,
366 mode,
367 tries: 0,
368 scrolled: false,
369 top: None,
370 });
371 }
372
373 pub(super) fn revealing(&self) -> Option<Reveal> {
374 self.0.borrow().reveal
375 }
376
377 pub(super) fn set_revealing(&self, reveal: Option<Reveal>) {
378 self.0.borrow_mut().reveal = reveal;
379 }
380
381 pub(super) fn record(
382 &self,
383 block: usize,
384 part: Part,
385 range: Range<usize>,
386 layout: TextLayout,
387 shown: Shown,
388 ) {
389 let mut frames = self.0.borrow_mut();
390 let painted = frames.texts.len();
391 record_rows(
392 &mut frames.rows,
393 painted,
394 block,
395 part,
396 &range,
397 &layout,
398 &shown,
399 );
400 frames.texts.push(Painted {
401 block,
402 part,
403 range,
404 layout,
405 shown,
406 });
407 }
408
409 pub(super) fn record_block(&self, ix: usize, bounds: Bounds<Pixels>) {
410 self.0.borrow_mut().blocks.push((ix, bounds));
411 }
412
413 pub(super) fn record_language(&self, ix: usize, bounds: Bounds<Pixels>) {
414 self.0.borrow_mut().languages.push((ix, bounds));
415 }
416
417 pub(super) fn record_picture(&self, ix: usize, bounds: Bounds<Pixels>) {
418 self.0.borrow_mut().pictures.push((ix, bounds));
419 }
420
421 pub(super) fn record_painted(&self, ix: usize, bounds: Bounds<Pixels>) {
422 self.0.borrow_mut().painted.push((ix, bounds));
423 }
424
425 pub(super) fn record_checkbox(&self, ix: usize, bounds: Bounds<Pixels>) {
426 self.0.borrow_mut().checkboxes.push((ix, bounds));
427 }
428
429 pub(super) fn record_cell(&self, ix: usize, part: Part, bounds: Bounds<Pixels>) {
430 self.0.borrow_mut().cells.push((ix, part, bounds));
431 }
432
433 pub(super) fn height(&self, ix: usize, key: u64) -> Option<Pixels> {
436 let heights = &self.0.borrow().heights;
437 heights
438 .by_key
439 .get(&key)
440 .copied()
441 .or_else(|| heights.by_index.get(ix).copied().flatten())
442 }
443
444 pub(super) fn record_height(&self, ix: usize, key: u64, height: Pixels) {
445 let heights = &mut self.0.borrow_mut().heights;
446 heights.by_key.insert(key, height);
447 if heights.by_index.len() <= ix {
448 heights.by_index.resize(ix + 1, None);
449 }
450 heights.by_index[ix] = Some(height);
451 }
452
453 pub(super) fn prune(&self, keys: &[u64]) {
456 let heights = &mut self.0.borrow_mut().heights;
457 heights.by_index.truncate(keys.len());
458 if heights.by_key.len() > 2 * keys.len() {
459 let keep: std::collections::HashSet<u64> = keys.iter().copied().collect();
460 heights.by_key.retain(|key, _| keep.contains(key));
461 }
462 }
463
464 pub(super) fn clear(&self) {
465 let mut frames = self.0.borrow_mut();
466 frames.texts.clear();
467 frames.rows.clear();
468 frames.blocks.clear();
469 frames.languages.clear();
470 frames.pictures.clear();
471 frames.painted.clear();
472 frames.checkboxes.clear();
473 frames.cells.clear();
474 }
475}
476
477pub(super) fn row_contains(row: &PaintedRow, offset: usize) -> bool {
478 row.range.start <= offset && offset <= row.range.end
479}
480
481pub(super) fn cursor_in_row(frames: &Frames, row: &PaintedRow, x: Pixels) -> Option<Cursor> {
482 let painted = &frames.texts[row.painted];
483 let line = painted.layout.line_layout_for_index(row.line_start)?;
484 let height = row.bounds.size.height;
485 let local = point(
486 x - row.bounds.origin.x,
487 height * (row.wrapped_row as f32 + 0.5),
488 );
489 let (Ok(offset) | Err(offset)) = line.closest_index_for_position(local, height);
490 let offset = painted.range.start + painted.shown.offset(row.line_start + offset);
491 Some(Cursor::new(row.block, row.part, offset.min(row.range.end)))
492}
493
494pub(super) fn record_rows(
495 rows: &mut Vec<PaintedRow>,
496 painted: usize,
497 block: usize,
498 part: Part,
499 range: &Range<usize>,
500 layout: &TextLayout,
501 shown: &Shown,
502) {
503 let line_height = layout.line_height();
504 let bounds = layout.bounds();
505 let mut origin = bounds.origin;
506 let mut line_start = 0;
507 for line in layout.line_layouts() {
508 let shaped = &line.unwrapped_layout;
509 let row_ends = line
510 .wrap_boundaries()
511 .iter()
512 .map(|wrap| shaped.runs[wrap.run_ix].glyphs[wrap.glyph_ix].index)
513 .chain([line.len()]);
514 let mut row_start = 0;
515 for (row, row_end) in row_ends.enumerate() {
516 rows.push(PaintedRow {
517 painted,
518 block,
519 part,
520 range: range.start + shown.offset(line_start + row_start)
521 ..range.start + shown.offset(line_start + row_end),
522 bounds: Bounds::new(
523 origin + point(px(0.0), line_height * row as f32),
524 size(bounds.size.width, line_height),
525 ),
526 line_start,
527 wrapped_row: row,
528 });
529 row_start = row_end;
530 }
531 origin.y += line.size(line_height).height;
532 line_start += line.len() + 1;
533 }
534}