nvim_gtk/render/
model_clip_iterator.rs1use std::cmp::min;
2use std::slice::Iter;
3
4use cairo;
5
6use super::context::CellMetrics;
7use crate::ui_model;
8
9pub struct RowView<'a> {
10 pub line: &'a ui_model::Line,
11 pub cell_metrics: &'a CellMetrics,
12 pub line_y: f64,
13 pub ctx: &'a cairo::Context,
14}
15
16impl<'a> RowView<'a> {
17 pub fn new(
18 row: usize,
19 ctx: &'a cairo::Context,
20 cell_metrics: &'a CellMetrics,
21 line: &'a ui_model::Line,
22 ) -> Self {
23 RowView {
24 line,
25 line_y: row as f64 * cell_metrics.line_height,
26 cell_metrics,
27 ctx,
28 }
29 }
30}
31
32pub struct ModelClipIterator<'a> {
33 model_idx: usize,
34 model_iter: Iter<'a, ui_model::Line>,
35 cell_metrics: &'a CellMetrics,
36 ctx: &'a cairo::Context,
37}
38
39pub trait ModelClipIteratorFactory {
40 fn get_clip_iterator<'a>(
41 &'a self,
42 ctx: &'a cairo::Context,
43 cell_metrics: &'a CellMetrics,
44 ) -> ModelClipIterator;
45
46 fn get_row_view<'a>(
47 &'a self,
48 ctx: &'a cairo::Context,
49 cell_metrics: &'a CellMetrics,
50 col: usize,
51 ) -> RowView<'a>;
52}
53
54impl<'a> Iterator for ModelClipIterator<'a> {
55 type Item = RowView<'a>;
56
57 fn next(&mut self) -> Option<RowView<'a>> {
58 let next = if let Some(line) = self.model_iter.next() {
59 Some(RowView::new(
60 self.model_idx,
61 self.ctx,
62 self.cell_metrics,
63 line,
64 ))
65 } else {
66 None
67 };
68 self.model_idx += 1;
69
70 next
71 }
72}
73
74impl ModelClipIteratorFactory for ui_model::UiModel {
78 fn get_row_view<'a>(
79 &'a self,
80 ctx: &'a cairo::Context,
81 cell_metrics: &'a CellMetrics,
82 col: usize,
83 ) -> RowView<'a> {
84 RowView::new(col, ctx, cell_metrics, &self.model()[col])
85 }
86
87 fn get_clip_iterator<'a>(
88 &'a self,
89 ctx: &'a cairo::Context,
90 cell_metrics: &'a CellMetrics,
91 ) -> ModelClipIterator<'a> {
92 let model = self.model();
93
94 let (x1, y1, x2, y2) = ctx.clip_extents();
95
96 let model_clip = ui_model::ModelRect::from_area(cell_metrics, x1, y1.max(0.0), x2, y2);
99
100 let model_clip_top = if model_clip.top == 0 {
101 0
102 } else {
103 min(model.len() - 1, model_clip.top - 1)
105 };
106 let model_clip_bot = min(model.len() - 1, model_clip.bot + 1);
107
108 debug_assert!(
109 model_clip_top <= model_clip_bot,
110 "model line index starts at {} but ends at {}. model.len = {}",
111 model_clip_top,
112 model_clip_bot,
113 model.len()
114 );
115
116 ModelClipIterator {
117 model_idx: model_clip_top,
118 model_iter: model[model_clip_top..=model_clip_bot].iter(),
119 ctx,
120 cell_metrics,
121 }
122 }
123}