diff --git a/src/render/context.rs b/src/render/context.rs index f5ff9ca..ff356a1 100644 --- a/src/render/context.rs +++ b/src/render/context.rs @@ -22,7 +22,7 @@ impl Context { } pub fn itemize(&self, line: &StyledLine) -> Vec { - sys_pango::pango_itemize(&self.pango_context, &line.line_str, &line.attr_list) + sys_pango::pango_itemize(&self.pango_context, line.line_str.trim_right(), &line.attr_list) } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 482539d..50f75e2 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -52,7 +52,6 @@ pub fn shape_dirty(ctx: &context::Context, ui_model: &mut ui_model::UiModel) { for i in 0..line.line.len() { if line[i].dirty { - // FIXME: dont shape/render empty items(space cells) if let Some(mut item) = line.get_item_mut(i) { let mut glyphs = pango::GlyphString::new(); { diff --git a/src/sys/pango/item.rs b/src/sys/pango/item.rs index 015cd88..aadaf94 100644 --- a/src/sys/pango/item.rs +++ b/src/sys/pango/item.rs @@ -39,4 +39,8 @@ impl Item { pub fn offset(&self) -> (usize, usize, usize) { (self.0.offset as usize, self.0.length as usize, self.0.num_chars as usize) } + + pub fn length(&self) -> i32 { + self.0.length + } } diff --git a/src/sys/pango/mod.rs b/src/sys/pango/mod.rs index f5dc4a5..01c0788 100644 --- a/src/sys/pango/mod.rs +++ b/src/sys/pango/mod.rs @@ -13,7 +13,7 @@ use glib::translate::*; pub fn pango_itemize( context: &pango::Context, - text: &String, + text: &str, attrs: &pango::AttrList ) -> Vec { unsafe { @@ -29,7 +29,7 @@ pub fn pango_itemize( } pub fn pango_shape( - text: &String, + text: &str, offset: usize, length: usize, analysis: &Analysis, diff --git a/src/ui_model/line.rs b/src/ui_model/line.rs index ef613e0..ea0fa1e 100644 --- a/src/ui_model/line.rs +++ b/src/ui_model/line.rs @@ -75,6 +75,13 @@ impl Line { } } + pub fn copy_to(&self, target: &mut Self, left: usize, right: usize) { + target.line[left..right + 1].clone_from_slice(&self.line[left..right + 1]); + // don't update items, but mark line as dirty to force item recalculation + // all work must be done in merge function + target.dirty_line = true; + } + pub fn clear(&mut self, left: usize, right: usize) { for cell in &mut self.line[left..right + 1] { cell.clear(); @@ -93,30 +100,41 @@ impl Line { } } - fn set_cell_to_item(&mut self, pango_item: &PangoItemPosition) -> bool { - let start_item = self.cell_to_item(pango_item.start_cell); - let end_item = self.cell_to_item(pango_item.end_cell); - //FIXME: check start cell - //FIXME: check length - //FIXME: don't check start_item != end_item + fn set_cell_to_item(&mut self, new_item: &PangoItemPosition) -> bool { + let start_item_idx = self.cell_to_item(new_item.start_cell); + let start_item_len = if start_item_idx > 0 { + self.item_line[start_item_idx as usize] + .as_ref() + .unwrap() + .item + .length() + } else { + -1 + }; + let end_item_idx = self.cell_to_item(new_item.end_cell); + + // start_item == idx of item start cell // in case different item length was in previous iteration // mark all item as dirty - if start_item != end_item || start_item == -1 || end_item == -1 { - self.initialize_cell_item(pango_item.start_cell, pango_item.end_cell, pango_item.item); + if start_item_idx != new_item.start_cell as i32 || + new_item.item.length() != start_item_len || start_item_idx == -1 || + end_item_idx == -1 + { + self.initialize_cell_item(new_item.start_cell, new_item.end_cell, new_item.item); true } else { // update only if cell marked as dirty - if self.line[pango_item.start_cell..pango_item.end_cell + 1] + if self.line[new_item.start_cell..new_item.end_cell + 1] .iter() .find(|c| c.dirty) .is_some() { - self.item_line[pango_item.start_cell] + self.item_line[new_item.start_cell] .as_mut() .unwrap() - .update(pango_item.item.clone()); - self.line[pango_item.start_cell].dirty = true; + .update(new_item.item.clone()); + self.line[new_item.start_cell].dirty = true; true } else { false diff --git a/src/ui_model/mod.rs b/src/ui_model/mod.rs index 6a5864d..342fa64 100644 --- a/src/ui_model/mod.rs +++ b/src/ui_model/mod.rs @@ -123,12 +123,24 @@ impl UiModel { } #[inline] - fn copy_row(&mut self, row: i64, offset: i64, left: usize, right: usize) { - for col in left..right + 1 { - let from_row = (row + offset) as usize; - let from_cell = self.model[from_row][col].clone(); - self.model[row as usize][col] = from_cell; - } + fn copy_row(&mut self, target_row: i64, offset: i64, left_col: usize, right_col: usize) { + debug_assert!(offset != 0); + + let from_row = (target_row + offset) as usize; + + let (left, right) = if offset > 0 { + self.model.split_at_mut(from_row) + } else { + self.model.split_at_mut(target_row as usize) + }; + + let (source_row, target_row) = if offset > 0 { + (&right[0], &mut left[target_row as usize]) + } else { + (&left[from_row], &mut right[0]) + }; + + source_row.copy_to(target_row, left_col, right_col); } pub fn scroll(&mut self, count: i64) -> ModelRect {