Fix redraw clip rect calculation
This commit is contained in:
parent
a00d1ff65c
commit
837fcb7b45
@ -69,11 +69,17 @@ pub struct CellMetrics {
|
||||
pub line_height: f64,
|
||||
pub char_width: f64,
|
||||
pub ascent: f64,
|
||||
pub pango_ascent: i32,
|
||||
pub pango_descent: i32,
|
||||
pub pango_char_width: i32,
|
||||
}
|
||||
|
||||
impl CellMetrics {
|
||||
fn new(font_metrics: &pango::FontMetrics) -> Self {
|
||||
CellMetrics {
|
||||
pango_ascent: font_metrics.get_ascent(),
|
||||
pango_descent: font_metrics.get_descent(),
|
||||
pango_char_width: font_metrics.get_approximate_digit_width(),
|
||||
ascent: font_metrics.get_ascent() as f64 / pango::SCALE as f64,
|
||||
line_height: (font_metrics.get_ascent() + font_metrics.get_descent()) as f64 /
|
||||
pango::SCALE as f64,
|
||||
|
@ -119,7 +119,7 @@ pub fn shape_dirty(
|
||||
);
|
||||
}
|
||||
|
||||
item.set_glyphs(glyphs);
|
||||
item.set_glyphs(ctx, glyphs);
|
||||
}
|
||||
}
|
||||
|
||||
|
11
src/shell.rs
11
src/shell.rs
@ -176,11 +176,16 @@ impl State {
|
||||
}
|
||||
|
||||
fn queue_draw_area<M: AsRef<ModelRect>>(&mut self, rect_list: &[M]) {
|
||||
//FIXME: extends by items before, then after
|
||||
// extends by items before, then after changes
|
||||
|
||||
let rects: Vec<_> = rect_list.iter().map(|rect| rect.as_ref().clone()).map(|mut rect| {
|
||||
rect.extend_by_items(&self.model);
|
||||
rect
|
||||
}).collect();
|
||||
|
||||
self.update_dirty_glyphs();
|
||||
|
||||
for rect in rect_list {
|
||||
let mut rect = rect.as_ref().clone();
|
||||
for mut rect in rects {
|
||||
rect.extend_by_items(&self.model);
|
||||
|
||||
let (x, y, width, height) =
|
||||
|
@ -1,3 +1,4 @@
|
||||
use render;
|
||||
|
||||
use sys::pango as sys_pango;
|
||||
use pango;
|
||||
@ -5,18 +6,22 @@ use pango;
|
||||
#[derive(Clone)]
|
||||
pub struct Item {
|
||||
pub item: sys_pango::Item,
|
||||
pub cells_count: usize,
|
||||
pub glyphs: Option<pango::GlyphString>,
|
||||
pub ink_rect: Option<pango::Rectangle>,
|
||||
pub ink_overflow: Option<InkOverflow>,
|
||||
font: pango::Font,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn new(item: sys_pango::Item) -> Self {
|
||||
pub fn new(item: sys_pango::Item, cells_count: usize) -> Self {
|
||||
debug_assert!(cells_count > 0);
|
||||
|
||||
Item {
|
||||
font: item.analysis().font(),
|
||||
item,
|
||||
cells_count,
|
||||
glyphs: None,
|
||||
ink_rect: None,
|
||||
ink_overflow: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,14 +29,13 @@ impl Item {
|
||||
self.font = item.analysis().font();
|
||||
self.item = item;
|
||||
self.glyphs = None;
|
||||
self.ink_rect = None;
|
||||
self.ink_overflow = None;
|
||||
}
|
||||
|
||||
pub fn set_glyphs(&mut self, glyphs: pango::GlyphString) {
|
||||
pub fn set_glyphs(&mut self, ctx: &render::Context, glyphs: pango::GlyphString) {
|
||||
let mut glyphs = glyphs;
|
||||
// FIXME: pango units
|
||||
let (ink_rect, _) = glyphs.extents(&self.font);
|
||||
self.ink_rect = Some(ink_rect);
|
||||
self.ink_overflow = InkOverflow::from(ctx, &ink_rect, self.cells_count as i32);
|
||||
self.glyphs = Some(glyphs);
|
||||
}
|
||||
|
||||
@ -43,3 +47,52 @@ impl Item {
|
||||
self.item.analysis()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InkOverflow {
|
||||
pub left: f64,
|
||||
pub right: f64,
|
||||
pub top: f64,
|
||||
pub bot: f64,
|
||||
}
|
||||
|
||||
impl InkOverflow {
|
||||
pub fn from(
|
||||
ctx: &render::Context,
|
||||
ink_rect: &pango::Rectangle,
|
||||
cells_count: i32,
|
||||
) -> Option<Self> {
|
||||
let cell_metrix = ctx.cell_metrics();
|
||||
|
||||
let ink_descent = ink_rect.y + ink_rect.height;
|
||||
let ink_ascent = ink_rect.y.abs();
|
||||
|
||||
let mut top = ink_ascent - cell_metrix.pango_ascent;
|
||||
if top < 0 {
|
||||
top = 0;
|
||||
}
|
||||
|
||||
let mut bot = ink_descent - cell_metrix.pango_descent;
|
||||
if bot < 0 {
|
||||
bot = 0;
|
||||
}
|
||||
|
||||
let left = if ink_rect.x < 0 { ink_rect.x.abs() } else { 0 };
|
||||
|
||||
let mut right = ink_rect.width - cells_count * cell_metrix.pango_char_width;
|
||||
if right < 0 {
|
||||
right = 0;
|
||||
}
|
||||
|
||||
if left == 0 && right == 0 && top == 0 && right == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(InkOverflow {
|
||||
left: left as f64 / pango::SCALE as f64,
|
||||
right: right as f64 / pango::SCALE as f64,
|
||||
top: top as f64 / pango::SCALE as f64,
|
||||
bot: bot as f64 / pango::SCALE as f64,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ impl Line {
|
||||
for i in start_cell + 1..end_cell + 1 {
|
||||
self.item_line[i] = None;
|
||||
}
|
||||
self.item_line[start_cell] = Some(Item::new(new_item.clone()));
|
||||
self.item_line[start_cell] = Some(Item::new(new_item.clone(), end_cell - start_cell + 1));
|
||||
}
|
||||
|
||||
pub fn mark_dirty_cell(&mut self, idx: usize) {
|
||||
|
@ -128,59 +128,73 @@ impl ModelRect {
|
||||
|
||||
fn extend_left_right_area(&self, model: &UiModel, cell_metrics: &CellMetrics) -> (i32, i32) {
|
||||
let x = self.left as i32 * cell_metrics.char_width as i32;
|
||||
let mut x2 = (self.right + 1) as i32 * cell_metrics.char_width as i32;
|
||||
let mut min_x_offset = 0;
|
||||
let x2 = (self.right + 1) as i32 * cell_metrics.char_width as i32;
|
||||
let mut min_x_offset = 0.0;
|
||||
let mut max_x_offset = 0.0;
|
||||
|
||||
for row in self.top..self.bot + 1 {
|
||||
|
||||
// FIXME: use original, not extended rect here
|
||||
// left
|
||||
let line = &model.model[row];
|
||||
if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(self.left) {
|
||||
if ink_rect.x < min_x_offset {
|
||||
min_x_offset = x;
|
||||
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) =
|
||||
line.item_line[self.left].as_ref()
|
||||
{
|
||||
if min_x_offset < overflow.left {
|
||||
min_x_offset = overflow.left;
|
||||
}
|
||||
}
|
||||
|
||||
// right
|
||||
let line = &model.model[row];
|
||||
if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(self.right) {
|
||||
let ink_x = x + ink_rect.x + ink_rect.width;
|
||||
if x2 < ink_x {
|
||||
x2 = ink_x;
|
||||
// check if this item ends here
|
||||
if self.right < model.columns - 1 &&
|
||||
line.cell_to_item(self.right) != line.cell_to_item(self.right + 1)
|
||||
{
|
||||
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) =
|
||||
line.get_item(self.left)
|
||||
{
|
||||
if max_x_offset < overflow.right {
|
||||
max_x_offset = overflow.right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(x + min_x_offset, x2)
|
||||
(
|
||||
x - min_x_offset.ceil() as i32,
|
||||
x2 + max_x_offset.ceil() as i32,
|
||||
)
|
||||
}
|
||||
|
||||
fn extend_top_bottom_area(&self, model: &UiModel, cell_metrics: &CellMetrics) -> (i32, i32) {
|
||||
let y = self.top as i32 * cell_metrics.line_height as i32;
|
||||
let mut y2 = (self.bot + 1) as i32 * cell_metrics.line_height as i32;
|
||||
let mut min_y_offset = 0;
|
||||
let y2 = (self.bot + 1) as i32 * cell_metrics.line_height as i32;
|
||||
let mut min_y_offset = 0.0;
|
||||
let mut max_y_offset = 0.0;
|
||||
|
||||
for col in self.left..self.right + 1 {
|
||||
|
||||
// top
|
||||
let line = &model.model[self.top];
|
||||
if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(col) {
|
||||
if ink_rect.y < min_y_offset {
|
||||
min_y_offset = ink_rect.y;
|
||||
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = line.get_item(col) {
|
||||
if min_y_offset < overflow.top {
|
||||
min_y_offset = overflow.top;
|
||||
}
|
||||
}
|
||||
|
||||
// bottom
|
||||
let line = &model.model[self.bot];
|
||||
if let Some(&Item { ink_rect: Some(ref ink_rect), .. }) = line.get_item(col) {
|
||||
let ink_y = y + ink_rect.y + ink_rect.height;
|
||||
if y2 < ink_y {
|
||||
y2 = ink_y;
|
||||
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = line.get_item(col) {
|
||||
if max_y_offset < overflow.top {
|
||||
max_y_offset = overflow.top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(y + min_y_offset, y2)
|
||||
(
|
||||
y - min_y_offset.ceil() as i32,
|
||||
y2 + max_y_offset.ceil() as i32,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn join(&mut self, rect: &ModelRect) {
|
||||
|
Loading…
Reference in New Issue
Block a user