From 17063d52169d0cdd2000fb7b77b2d8c904bde850 Mon Sep 17 00:00:00 2001 From: daa84 Date: Thu, 24 Aug 2017 17:41:20 +0300 Subject: [PATCH] Itemizer --- src/render/context.rs | 37 ++++++++++++++++ src/render/mod.rs | 12 +++--- src/sys/pango/mod.rs | 21 ++++------ src/ui_model/line.rs | 98 +++++++++++++++++++++++++++++++++++++++++-- src/ui_model/mod.rs | 17 ++++---- 5 files changed, 155 insertions(+), 30 deletions(-) create mode 100644 src/render/context.rs diff --git a/src/render/context.rs b/src/render/context.rs new file mode 100644 index 0000000..7e319d4 --- /dev/null +++ b/src/render/context.rs @@ -0,0 +1,37 @@ +use std::ffi::CString; + +use pangocairo::FontMap; +use pango::prelude::*; +use pango; + +use sys::pango::*; + +use ui_model::StyledLine; + +pub struct Context { + pango_context: pango::Context, +} + +impl Context { + pub fn new(font_desc: &pango::FontDescription) -> Self { + Context { + pango_context: create_pango_context(font_desc), + } + } + + pub fn update(&mut self, font_desc: &pango::FontDescription) { + self.pango_context = create_pango_context(font_desc); + } + + pub fn itemize(&self, line: &StyledLine)-> Vec { + pango_itemize(&self.pango_context, &line.line_str, &line.attr_list) + } +} + +fn create_pango_context(font_desc: &pango::FontDescription) -> pango::Context { + let font_map = FontMap::get_default(); + let pango_context = font_map.create_context().unwrap(); + pango_context.set_font_description(&font_desc); + + pango_context +} diff --git a/src/render/mod.rs b/src/render/mod.rs index 8ba40db..1003592 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,28 +1,30 @@ +mod context; + use sys::pango::*; use pango; use pango::prelude::*; use cairo; use pangocairo::{CairoContextExt, FontMap}; use std::ffi::CString; +use ui_model; pub fn render(ctx: &cairo::Context, font_desc: pango::FontDescription) { let font_map = FontMap::get_default(); let pango_context = font_map.create_context().unwrap(); pango_context.set_font_description(&font_desc); - let text = "TEST String".to_owned().into_bytes(); - let len = text.len(); - let text = CString::new(text).unwrap(); + let text = "TEST String".to_owned(); let attr_list = pango::AttrList::new(); ctx.move_to(0.0, 50.0); - let items = pango_itemize(&pango_context, &text, 0, len, &attr_list); + let items = pango_itemize(&pango_context, &text, &attr_list); for item in items { let mut glyphs = pango::GlyphString::new(); let analysis = item.analysis(); - pango_shape(&text, len, &analysis, &mut glyphs); + pango_shape(&text, &analysis, &mut glyphs); let font = analysis.font(); let (ink, logical) = glyphs.extents(&font); ctx.show_glyph_string(&font, &glyphs); } } + diff --git a/src/sys/pango/mod.rs b/src/sys/pango/mod.rs index 8d49a77..a6f09f1 100644 --- a/src/sys/pango/mod.rs +++ b/src/sys/pango/mod.rs @@ -1,4 +1,4 @@ -mod item; +pub mod item; mod analysis; use std::ptr; @@ -11,17 +11,15 @@ use glib::translate::*; pub fn pango_itemize( context: &pango::Context, - text: &CStr, - start_index: usize, - length: usize, - attrs: &pango::AttrList, + text: &String, + attrs: &pango::AttrList ) -> Vec { unsafe { FromGlibPtrContainer::from_glib_container(pango_sys::pango_itemize( context.to_glib_none().0, - text.as_ptr(), - start_index as i32, - length as i32, + text.as_ptr() as *const i8, + 0, + text.len() as i32, attrs.to_glib_none().0, ptr::null_mut(), )) @@ -29,15 +27,14 @@ pub fn pango_itemize( } pub fn pango_shape( - text: &CStr, - length: usize, + text: &String, analysis: &analysis::Analysis, glyphs: &mut pango::GlyphString, ) { unsafe { pango_sys::pango_shape( - text.as_ptr(), - length as i32, + text.as_ptr() as *const i8, + text.len() as i32, analysis.to_glib_ptr(), glyphs.to_glib_none_mut().0, ); diff --git a/src/ui_model/line.rs b/src/ui_model/line.rs index 6fd4fee..5972f7e 100644 --- a/src/ui_model/line.rs +++ b/src/ui_model/line.rs @@ -1,23 +1,113 @@ +use std::ops::{Index, IndexMut}; + use super::cell::Cell; -use pango::Item; +use pango; + +pub struct Item { + item: pango::Item, + glyph_string: Option, +} + +impl Item { + pub fn new(item: pango::Item) -> Self { + Item { + item, + glyph_string: None, + } + } +} pub struct Line { - line: Box<[Cell]>, + pub line: Box<[Cell]>, item_line: Option>, cell_to_item: Box<[usize]>, } impl Line { pub fn new(columns: usize) -> Self { - let line = Vec::with_capacity(columns); + let mut line = Vec::with_capacity(columns); for _ in 0..columns { line.push(Cell::new(' ')); } - Line { + Line { cell_to_item: Vec::with_capacity(line.len()).into_boxed_slice(), line: line.into_boxed_slice(), item_line: None, } } + + pub fn clear(&mut self, left: usize, right: usize) { + for cell in &mut self.line[left..right + 1] { + cell.clear(); + } + + } +} + +impl Index for Line { + type Output = Cell; + + fn index(&self, index: usize) -> &Cell { + &self.line[index] + } +} + +impl IndexMut for Line { + fn index_mut(&mut self, index: usize) -> &mut Cell { + &mut self.line[index] + } +} + +pub struct StyledLine { + pub line_str: String, + cell_to_byte: Box<[usize]>, + pub attr_list: pango::AttrList, +} + +impl StyledLine { + pub fn from(line: &Line) -> Self { + let mut line_str = String::new(); + let mut cell_to_byte = Vec::new(); + let attr_list = pango::AttrList::new(); + let mut byte_offset = 0; + + for (cell_idx, cell) in line.line.iter().enumerate() { + if cell.attrs.double_width { + continue; + } + + line_str.push(cell.ch); + let len = line_str.len(); + + for i in byte_offset..byte_offset + len { + cell_to_byte.push(cell_idx); + } + + insert_attrs(cell, &attr_list, byte_offset as u32, (byte_offset + len) as u32); + + byte_offset += len; + } + + StyledLine { + line_str, + cell_to_byte: cell_to_byte.into_boxed_slice(), + attr_list, + } + } +} + +fn insert_attrs(cell: &Cell, attr_list: &pango::AttrList, start_idx: u32, end_idx: u32) { + if cell.attrs.italic { + let mut attr = pango::Attribute::new_style(pango::Style::Italic).unwrap(); + attr.set_start_index(start_idx); + attr.set_end_index(end_idx); + attr_list.insert(attr); + } + if cell.attrs.bold { + let mut attr = pango::Attribute::new_weight(pango::Weight::Bold).unwrap(); + attr.set_start_index(start_idx); + attr.set_end_index(end_idx); + attr_list.insert(attr); + } } diff --git a/src/ui_model/mod.rs b/src/ui_model/mod.rs index 7017179..202ba1f 100644 --- a/src/ui_model/mod.rs +++ b/src/ui_model/mod.rs @@ -2,6 +2,7 @@ mod cell; mod line; pub use self::cell::{Cell, Attrs}; +pub use self::line::{Item, StyledLine}; use self::line::Line; use std::slice::Iter; @@ -158,9 +159,7 @@ impl UiModel { fn clear_region(&mut self, top: usize, bot: usize, left: usize, right: usize) { for row in &mut self.model[top..bot + 1] { - for cell in &mut row[left..right + 1] { - cell.clear(); - } + row.clear(left, right); } } } @@ -321,7 +320,7 @@ impl AsRef for ModelRect { pub struct ClipRowIterator<'a> { rect: &'a ModelRect, pos: usize, - iter: Iter<'a, Vec>, + iter: Iter<'a, Line>, } impl<'a> ClipRowIterator<'a> { @@ -347,11 +346,11 @@ impl<'a> Iterator for ClipRowIterator<'a> { pub struct ClipLine<'a> { rect: &'a ModelRect, - line: &'a [Cell], + line: &'a Line, } impl<'a> ClipLine<'a> { - pub fn new(model: &'a [Cell], rect: &'a ModelRect) -> ClipLine<'a> { + pub fn new(model: &'a Line, rect: &'a ModelRect) -> ClipLine<'a> { ClipLine { line: model, rect: rect, @@ -366,7 +365,7 @@ impl<'a> ClipLine<'a> { } pub fn get(&self, idx: usize) -> Option<&Cell> { - self.line.get(idx) + self.line.line.get(idx) } pub fn iter(&self) -> ClipColIterator<'a> { @@ -381,11 +380,11 @@ pub struct ClipColIterator<'a> { } impl<'a> ClipColIterator<'a> { - pub fn new(model: &'a [Cell], rect: &'a ModelRect) -> ClipColIterator<'a> { + pub fn new(model: &'a Line, rect: &'a ModelRect) -> ClipColIterator<'a> { ClipColIterator { rect: rect, pos: 0, - iter: model[rect.left..rect.right + 1].iter(), + iter: model.line[rect.left..rect.right + 1].iter(), } } }