diff --git a/src/model/listing/layout.rs b/src/model/listing/layout.rs index 989c38e..732f209 100644 --- a/src/model/listing/layout.rs +++ b/src/model/listing/layout.rs @@ -44,7 +44,7 @@ enum LinePushResult { #[derive(Clone)] pub struct Line { - ty: LineType, + pub ty: LineType, } pub trait LineView { diff --git a/src/view/listing/line.rs b/src/view/listing/line.rs index da485cb..5e89b77 100644 --- a/src/view/listing/line.rs +++ b/src/view/listing/line.rs @@ -3,10 +3,13 @@ use std::sync; use std::task; use std::vec; +use crate::model::addr; use crate::model::document; +use crate::model::document::structure; use crate::model::listing::layout; use crate::model::listing::token; use crate::model::selection; +use crate::util; use crate::view::gsc; use crate::view::helpers; use crate::view::listing; @@ -17,21 +20,42 @@ use gtk::prelude::*; use gtk::graphene; use gtk::gsk; +enum LineViewType { + Empty, + Blank(token_view::TokenView), + Title(token_view::TokenView), + Hexdump { + title: Option, + node: sync::Arc, + line_extent: addr::Extent, + tokens: Vec, + }, + Hexstring { + title: Option, + token: token_view::TokenView, + }, + Summary { + title: Option, + tokens: Vec, + }, +} + pub struct Line { ev_draw: facet::Event, ev_work: facet::Event, current_document: Option>, + + ty: LineViewType, - tokens: vec::Vec, render_serial: u64, selection_hash: u64, render_node: Option, } impl layout::LineView for Line { - type TokenIterator = iter::Map, fn(token_view::TokenView) -> token::Token>; - type BorrowingTokenIterator<'a> = iter::Map, fn(&'a token_view::TokenView) -> &'a token::Token>; + type BorrowingTokenIterator<'a> = LineViewBorrowingTokenIterator<'a>; + type TokenIterator = LineViewTokenIterator; fn from_line(line: layout::Line) -> Self { Line { @@ -39,8 +63,9 @@ impl layout::LineView for Line { ev_work: facet::Event::new_wanted(), current_document: None, + + ty: LineViewType::from(line), - tokens: line.to_tokens().map(token_view::TokenView::from).collect(), render_serial: 0, selection_hash: 0, render_node: None, @@ -48,11 +73,98 @@ impl layout::LineView for Line { } fn iter_tokens(&self) -> Self::BorrowingTokenIterator<'_> { - self.tokens.iter().map(|t| t.token()) + self.ty.iter_tokens() } fn to_tokens(self) -> Self::TokenIterator { - self.tokens.into_iter().map(|t| t.into_token()) + self.ty.to_tokens() + } +} + +type LineViewBorrowingTokenIterator<'a> = iter::Map + , + iter::Once<&'a token_view::TokenView>, + iter::Chain, std::slice::Iter<'a, token_view::TokenView>>, + iter::Chain, iter::Once<&'a token_view::TokenView>>>, + fn(&'a token_view::TokenView) -> &'a token::Token>; + +type LineViewTokenIterator = iter::Map + , + iter::Once, + iter::Chain, vec::IntoIter>, + iter::Chain, iter::Once>>, + fn(token_view::TokenView) -> token::Token>; + +impl LineViewType { + fn from(line: layout::Line) -> Self { + match line.ty { + layout::LineType::Empty => Self::Empty, + layout::LineType::Blank(tok) => Self::Blank(token_view::TokenView::from(tok)), + layout::LineType::Title(tok) => Self::Title(token_view::TokenView::from(tok)), + layout::LineType::Hexdump { title, node, line_extent, tokens } => Self::Hexdump { + title: title.map(token_view::TokenView::from), + node, + line_extent, + tokens: tokens.into_iter().map(token_view::TokenView::from).collect() + }, + layout::LineType::Hexstring { title, token } => Self::Hexstring { + title: title.map(token_view::TokenView::from), + token: token_view::TokenView::from(token), + }, + layout::LineType::Summary { title, tokens } => Self::Summary { + title: title.map(token_view::TokenView::from), + tokens: tokens.into_iter().map(token_view::TokenView::from).collect() + }, + } + } + + fn iter_tokens(&self) -> LineViewBorrowingTokenIterator<'_> { + match &self { + Self::Empty => util::PhiIterator::I1(iter::empty()), + Self::Blank(t) | Self::Title(t) => util::PhiIterator::I2(iter::once(t)), + Self::Hexdump { title, tokens, .. } => util::PhiIterator::I3(title.iter().chain(tokens.iter())), + Self::Hexstring { title, token, .. } => util::PhiIterator::I4(title.iter().chain(iter::once(token))), + Self::Summary { title, tokens, .. } => util::PhiIterator::I3(title.iter().chain(tokens.iter())), + }.map(token_view::TokenView::token) + } + + fn to_tokens(self) -> LineViewTokenIterator { + match self { + Self::Empty => util::PhiIterator::I1(iter::empty()), + Self::Blank(t) | Self::Title(t) => util::PhiIterator::I2(iter::once(t)), + Self::Hexdump { title, tokens, .. } => util::PhiIterator::I3(title.into_iter().chain(tokens.into_iter())), + Self::Hexstring { title, token, .. } => util::PhiIterator::I4(title.into_iter().chain(iter::once(token))), + Self::Summary { title, tokens, .. } => util::PhiIterator::I3(title.into_iter().chain(tokens.into_iter())), + }.map(token_view::TokenView::into_token) + } + + fn contains_cursor(&self, cursor: &cursor::Cursor) -> bool { + match self { + Self::Empty => false, + Self::Blank(t) | Self::Title(t) => cursor.is_over(t.token()), + Self::Hexdump { title, tokens, .. } => title.map_or(false, |tv| cursor.is_over(tv.token())) || tokens.iter().any(|tv| cursor.is_over(tv.token())), + Self::Hexstring { title, token, .. } => title.map_or(false, |tv| cursor.is_over(tv.token())) || cursor.is_over(token.token()), + Self::Summary { title, tokens, .. } => title.map_or(false, |tv| cursor.is_over(tv.token())) || tokens.iter().any(|tv| cursor.is_over(tv.token())), + } + } + + fn indentation(&self) -> usize { + match self { + Self::Empty => 0, + Self::Blank(t) | Self::Title(t) => t.token().depth, + + Self::Hexdump { title: Some(t), .. } => t.token().depth, + Self::Hexstring { title: Some(t), .. } => t.token().depth, + Self::Summary { title: Some(t), .. } => t.token().depth, + + Self::Hexdump { tokens, .. } => tokens[0].token().depth, + Self::Hexstring { token, .. } => token.token().depth, + Self::SUmmary { tokens, .. } => tokens[0].token().depth, + } } } @@ -63,7 +175,7 @@ impl Line { pub fn render(&mut self, cursor: &facet::cursor::CursorView, selection: &selection::listing::Mode, render: &listing::RenderDetail) -> Option { /* check if the cursor is on any of the tokens on this line */ - let has_cursor = self.tokens.iter().any(|t| t.contains_cursor(&cursor.cursor)); + let has_cursor = self.ty.contains_cursor(&cursor.cursor); let selection_hash = { let mut state = std::collections::hash_map::DefaultHasher::default(); @@ -89,13 +201,12 @@ impl Line { /* begin rendering asciidump content wherever configured */ ascii_position.set_x(render.ascii_pane_position + render.config.padding as f32); - /* indent by first token */ - if let Some(first) = self.tokens.get(0) { - main_position.set_x( - main_position.x() + + /* indent */ + main_position.set_x( + main_position.x() + + self.ty.indentation() as f32 * render.config.indentation_width * - helpers::pango_unscale(render.gsc_mono.space_width()) * - first.get_indentation() as f32); + helpers::pango_unscale(render.gsc_mono.space_width())); } let mut visible_address = None; diff --git a/src/view/listing/token_view/mod.rs b/src/view/listing/token_view/mod.rs index 3c2906f..2a6904b 100644 --- a/src/view/listing/token_view/mod.rs +++ b/src/view/listing/token_view/mod.rs @@ -31,6 +31,17 @@ pub struct TokenView { logical_bounds_asciidump: Option, } +struct CommonContext<'a> { + snapshot: &'a gtk::Snapshot, + cursor: &'a CursorView, + selection: &'a selection::listing::Mode, + render: &'a listing::RenderDetail +} + +trait RenderForBucket { + fn render(&mut self, ctx: &CommonContext<'_>, bucket: &mut Bucket); +} + impl TokenView { pub fn from(token: token::Token) -> TokenView { TokenView { @@ -91,6 +102,12 @@ impl TokenView { ); } } + + pub fn render_for_blank(); + pub fn render_for_title(); + pub fn render_for_hexdump(); + pub fn render_for_hexstring(); + pub fn render_for_summary(); pub fn render( &mut self,