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