From 83061366dd5ddea1654a9a969ed19b1e0705c899 Mon Sep 17 00:00:00 2001 From: daa Date: Wed, 3 Jan 2018 01:26:04 +0300 Subject: [PATCH] Wrap text, hide popover --- src/cmd_line.rs | 81 +++++++++++++++++++----------------- src/nvim/redraw_handler.rs | 6 +++ src/shell.rs | 5 +++ src/ui_model/mod.rs | 2 + src/ui_model/model_layout.rs | 45 ++++++++++++++++++++ 5 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 src/ui_model/model_layout.rs diff --git a/src/cmd_line.rs b/src/cmd_line.rs index 9e6ed1b..3756896 100644 --- a/src/cmd_line.rs +++ b/src/cmd_line.rs @@ -9,19 +9,17 @@ use cairo; use neovim_lib::Value; -use ui_model::{UiModel, Attrs}; +use ui_model::{Attrs, ModelLayout}; use ui::UiMutex; use render; use shell; use cursor; pub struct Level { - model: UiModel, + model_layout: ModelLayout, } impl Level { - const COLUMNS_STEP: u64 = 50; - const ROWS_STEP: u64 = 10; pub fn from( content: Vec<(HashMap, String)>, @@ -33,57 +31,41 @@ impl Level { //TODO: double width chars //TODO: im - let prompt = prompt_lines(firstc, prompt, indent); - let content: Vec<(Attrs, Vec)> = content + let content_line: Vec<(Option, Vec)> = content .iter() - .map(|c| (Attrs::from_value_map(&c.0), c.1.chars().collect())) + .map(|c| (Some(Attrs::from_value_map(&c.0)), c.1.chars().collect())) .collect(); + let prompt_lines = prompt_lines(firstc, prompt, indent); - let width = (content.iter().map(|c| c.1.len()).count() + - prompt.last().map_or(0, |p| p.len())) as u64; - let columns = ((width / Level::COLUMNS_STEP) + 1) * Level::COLUMNS_STEP; - let rows = ((prompt.len() as u64 / Level::ROWS_STEP) + 1) * Level::ROWS_STEP; + let mut content: Vec<_> = prompt_lines.into_iter().map(|line| vec![line]).collect(); - let mut model = UiModel::new(rows, columns); - - for (row_idx, prompt_line) in prompt.iter().enumerate() { - for (col_idx, &ch) in prompt_line.iter().enumerate() { - model.set_cursor(row_idx, col_idx); - model.put(ch, false, None); - } - } - - let mut col_idx = 0; - let row_idx = if prompt.len() > 0 { - prompt.len() - 1 + if content.is_empty() { + content.push(content_line); } else { - 0 - }; - for (attr, ch_list) in content { - for ch in ch_list { - model.set_cursor(row_idx, col_idx); - model.put(ch, false, Some(&attr)); - col_idx += 1; - } + content.last_mut().map(|line| line.extend(content_line)); } - Level { model } + let mut model_layout = ModelLayout::new(); + // TODO: calculate width + model_layout.layout(content, 5); + + Level { model_layout } } fn update_cache(&mut self, render_state: &shell::RenderState) { render::shape_dirty( &render_state.font_ctx, - &mut self.model, + &mut self.model_layout.model, &render_state.color_model, ); } } -fn prompt_lines(firstc: String, prompt: String, indent: u64) -> Vec> { +fn prompt_lines(firstc: String, prompt: String, indent: u64) -> Vec<(Option, Vec)> { if !firstc.is_empty() { - vec![firstc.chars().chain((0..indent).map(|_| ' ')).collect()] + vec![(None, firstc.chars().chain((0..indent).map(|_| ' ')).collect())] } else if !prompt.is_empty() { - prompt.lines().map(|l| l.chars().collect()).collect() + prompt.lines().map(|l| (None, l.chars().collect())).collect() } else { vec![] } @@ -121,10 +103,12 @@ 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); + let edit_frame = gtk::Frame::new(None); edit_frame.set_shadow_type(gtk::ShadowType::In); let drawing_area = gtk::DrawingArea::new(); - drawing_area.set_size_request(50, 50); + drawing_area.set_size_request(150, 50); edit_frame.add(&drawing_area); edit_frame.show_all(); @@ -166,11 +150,32 @@ impl CmdLine { 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, + }); + self.popover.popup(); } else { state.drawing_area.queue_draw() } } + + pub fn hide_level(&mut self, level_idx: u64) { + let mut state = self.state.borrow_mut(); + + if level_idx as usize == state.levels.len() { + state.levels.pop(); + } + + if state.levels.is_empty() { + self.popover.hide(); + self.displyed = false; + } + } } fn gtk_draw( @@ -188,7 +193,7 @@ fn gtk_draw( ctx, cursor, &render_state.font_ctx, - &level.model, + &level.model_layout.model, &render_state.color_model, &render_state.mode, ); diff --git a/src/nvim/redraw_handler.rs b/src/nvim/redraw_handler.rs index be846c1..86432e7 100644 --- a/src/nvim/redraw_handler.rs +++ b/src/nvim/redraw_handler.rs @@ -76,6 +76,11 @@ pub trait RedrawEvents { indent: u64, level: u64, ) -> RepaintMode; + + fn cmdline_hide( + &mut self, + level: u64, + ) -> RepaintMode; } pub trait GuiApi { @@ -256,6 +261,7 @@ pub fn call( ui.mode_info_set(try_bool!(args[0]), mode_info) } "cmdline_show" => call!(ui->cmdline_show(args: ext, uint, str, str, uint, uint)), + "cmdline_hide" => call!(ui->cmdline_hide(args: uint)), _ => { println!("Event {}({:?})", method, args); RepaintMode::Nothing diff --git a/src/shell.rs b/src/shell.rs index 3c866e3..67589b8 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -1189,6 +1189,11 @@ impl RedrawEvents for State { self.cmd_line.show_level(content, pos, firstc, prompt, indent, level); RepaintMode::Nothing } + + fn cmdline_hide(&mut self, level: u64) -> RepaintMode { + self.cmd_line.hide_level(level); + RepaintMode::Nothing + } } impl CursorRedrawCb for State { diff --git a/src/ui_model/mod.rs b/src/ui_model/mod.rs index 19cdc52..277ae25 100644 --- a/src/ui_model/mod.rs +++ b/src/ui_model/mod.rs @@ -2,11 +2,13 @@ mod cell; mod line; mod item; mod model_rect; +mod model_layout; pub use self::cell::{Cell, Attrs}; pub use self::line::{Line, StyledLine}; pub use self::item::Item; pub use self::model_rect::{ModelRect, ModelRectVec}; +pub use self::model_layout::ModelLayout; pub struct UiModel { diff --git a/src/ui_model/model_layout.rs b/src/ui_model/model_layout.rs new file mode 100644 index 0000000..b4506e7 --- /dev/null +++ b/src/ui_model/model_layout.rs @@ -0,0 +1,45 @@ +use ui_model::{UiModel, Attrs}; + +pub struct ModelLayout { + pub model: UiModel, +} + +impl ModelLayout { + const COLUMNS_STEP: u64 = 50; + const ROWS_STEP: u64 = 10; + + pub fn new() -> Self { + ModelLayout { model: UiModel::new(ModelLayout::ROWS_STEP, ModelLayout::COLUMNS_STEP) } + } + + /// 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) * + ModelLayout::COLUMNS_STEP; + let model_rows = ((lines.len() as u64 / ModelLayout::ROWS_STEP) + 1) * + ModelLayout::ROWS_STEP; + + self.model = UiModel::new(model_rows, model_cols); + } + + + 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 { + col_idx = 0; + row_idx += 1; + } + + self.model.set_cursor(row_idx, col_idx as usize); + self.model.put(ch, false, attr.as_ref()); + col_idx += 1; + } + } + row_idx += 1; + } + } +}