From c27fbff586462e862213706c6135204cae0c99ff Mon Sep 17 00:00:00 2001 From: daa Date: Wed, 3 Jan 2018 12:04:01 +0300 Subject: [PATCH] Point to cursor --- src/cmd_line.rs | 73 +++++++++++++++++++++--------------- src/shell.rs | 21 ++++++++++- src/ui_model/model_layout.rs | 17 +++++++-- 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/cmd_line.rs b/src/cmd_line.rs index 3756896..bd154a5 100644 --- a/src/cmd_line.rs +++ b/src/cmd_line.rs @@ -11,31 +11,27 @@ use neovim_lib::Value; use ui_model::{Attrs, ModelLayout}; use ui::UiMutex; -use render; +use render::{self, CellMetrics}; use shell; use cursor; pub struct Level { model_layout: ModelLayout, + preferred_width: i32, + preferred_height: i32, } impl Level { - pub fn from( - content: Vec<(HashMap, String)>, - pos: u64, - firstc: String, - prompt: String, - indent: u64, - ) -> Self { - //TODO: double width chars + pub fn from(ctx: &CmdLineContext, render_state: &shell::RenderState) -> Self { + //TODO: double width chars render, also note in text wrapping //TODO: im - let content_line: Vec<(Option, Vec)> = content + let content_line: Vec<(Option, Vec)> = ctx.content .iter() .map(|c| (Some(Attrs::from_value_map(&c.0)), c.1.chars().collect())) .collect(); - let prompt_lines = prompt_lines(firstc, prompt, indent); + let prompt_lines = prompt_lines(&ctx.firstc, &ctx.prompt, ctx.indent); let mut content: Vec<_> = prompt_lines.into_iter().map(|line| vec![line]).collect(); @@ -45,11 +41,20 @@ impl Level { content.last_mut().map(|line| line.extend(content_line)); } - let mut model_layout = ModelLayout::new(); - // TODO: calculate width - model_layout.layout(content, 5); + let &CellMetrics { + line_height, + char_width, + .. + } = render_state.font_ctx.cell_metrics(); - Level { model_layout } + let max_width_chars = (ctx.max_width as f64 / char_width) as u64; + + let mut model_layout = ModelLayout::new(); + let (columns, rows) = model_layout.layout(content, max_width_chars); + + let preferred_width = (char_width * columns as f64) as i32; + let preferred_height = (line_height * rows as f64) as i32; + Level { model_layout, preferred_width, preferred_height } } fn update_cache(&mut self, render_state: &shell::RenderState) { @@ -61,7 +66,7 @@ impl Level { } } -fn prompt_lines(firstc: String, prompt: String, indent: u64) -> Vec<(Option, Vec)> { +fn prompt_lines(firstc: &str, prompt: &str, indent: u64) -> Vec<(Option, Vec)> { if !firstc.is_empty() { vec![(None, firstc.chars().chain((0..indent).map(|_| ' ')).collect())] } else if !prompt.is_empty() { @@ -103,7 +108,7 @@ impl CmdLine { pub fn new(drawing: >k::DrawingArea, render_state: Rc>) -> Self { let popover = gtk::Popover::new(Some(drawing)); popover.set_modal(false); - popover.set_position(gtk::PositionType::Top); + popover.set_position(gtk::PositionType::Right); let edit_frame = gtk::Frame::new(None); edit_frame.set_shadow_type(gtk::ShadowType::In); @@ -131,31 +136,25 @@ impl CmdLine { pub fn show_level( &mut self, - content: Vec<(HashMap, String)>, - pos: u64, - firstc: String, - prompt: String, - indent: u64, - level_idx: u64, + ctx: &CmdLineContext, ) { let mut state = self.state.borrow_mut(); - let mut level = Level::from(content, pos, firstc, prompt, indent); + let mut level = Level::from(ctx, &*state.render_state.borrow()); level.update_cache(&*state.render_state.borrow()); - if level_idx as usize == state.levels.len() { + if ctx.level_idx as usize == state.levels.len() { // TODO: update level state.levels.pop(); } state.levels.push(level); if !self.displyed { self.displyed = true; - let allocation = self.popover.get_relative_to().unwrap().get_allocation(); self.popover.set_pointing_to(>k::Rectangle { - x: allocation.width / 2, - y: allocation.height / 2, - width: 1, - height: 1, + x: ctx.x, + y: ctx.y, + width: ctx.width, + height: ctx.height, }); self.popover.popup(); @@ -200,3 +199,17 @@ fn gtk_draw( } Inhibit(false) } + +pub struct CmdLineContext { + pub content: Vec<(HashMap, String)>, + pub pos: u64, + pub firstc: String, + pub prompt: String, + pub indent: u64, + pub level_idx: u64, + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32, + pub max_width: i32, +} diff --git a/src/shell.rs b/src/shell.rs index 67589b8..46c3faf 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -30,7 +30,7 @@ use cursor::{Cursor, CursorRedrawCb}; use ui::UiMutex; use popup_menu::{self, PopupMenu}; use tabline::Tabline; -use cmd_line::CmdLine; +use cmd_line::{CmdLine, CmdLineContext}; use error; use mode; use render; @@ -1186,7 +1186,24 @@ impl RedrawEvents for State { indent: u64, level: u64, ) -> RepaintMode { - self.cmd_line.show_level(content, pos, firstc, prompt, indent, level); + let cursor = self.model.cur_point(); + let render_state = self.render_state.borrow(); + let (x, y, width, height) = cursor.to_area(render_state.font_ctx.cell_metrics()); + let ctx = CmdLineContext { + content, + pos, + firstc, + prompt, + indent, + level_idx: level, + x, + y, + width, + height, + max_width: self.drawing_area.get_allocated_width() - 20, + }; + + self.cmd_line.show_level(&ctx); RepaintMode::Nothing } diff --git a/src/ui_model/model_layout.rs b/src/ui_model/model_layout.rs index b4506e7..f7667a5 100644 --- a/src/ui_model/model_layout.rs +++ b/src/ui_model/model_layout.rs @@ -13,9 +13,11 @@ impl ModelLayout { } /// Wrap all lines into model - pub fn layout(&mut self, lines: Vec, Vec)>>, columns: u64) { - if lines.len() > self.model.rows || columns as usize > self.model.columns { - let model_cols = ((columns / ModelLayout::COLUMNS_STEP) + 1) * + /// + /// returns actual width + pub fn layout(&mut self, lines: Vec, Vec)>>, max_columns: u64) -> (u64, u64) { + if lines.len() > self.model.rows || max_columns as usize > self.model.columns { + let model_cols = ((max_columns / ModelLayout::COLUMNS_STEP) + 1) * ModelLayout::COLUMNS_STEP; let model_rows = ((lines.len() as u64 / ModelLayout::ROWS_STEP) + 1) * ModelLayout::ROWS_STEP; @@ -24,16 +26,21 @@ impl ModelLayout { } + let mut max_col_idx = 0; let mut col_idx = 0; let mut row_idx = 0; for content in lines { for (attr, ch_list) in content { for ch in ch_list { - if col_idx >= columns { + if col_idx >= max_columns { col_idx = 0; row_idx += 1; } + if max_col_idx < col_idx { + max_col_idx = col_idx; + } + self.model.set_cursor(row_idx, col_idx as usize); self.model.put(ch, false, attr.as_ref()); col_idx += 1; @@ -41,5 +48,7 @@ impl ModelLayout { } row_idx += 1; } + + (max_col_idx + 1, row_idx as u64) } }