Merge branch 'wildmenu'
This commit is contained in:
commit
ddc2d36b17
142
src/cmd_line.rs
142
src/cmd_line.rs
@ -2,20 +2,23 @@ use std::collections::HashMap;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::max;
|
use std::cmp::{max, min};
|
||||||
|
|
||||||
use gtk;
|
use gtk;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use cairo;
|
use cairo;
|
||||||
|
use pango;
|
||||||
|
|
||||||
use neovim_lib::Value;
|
use neovim_lib::Value;
|
||||||
|
|
||||||
|
use nvim::{self, NeovimClient};
|
||||||
use mode;
|
use mode;
|
||||||
use ui_model::{Attrs, ModelLayout};
|
use ui_model::{Attrs, ModelLayout};
|
||||||
use ui::UiMutex;
|
use ui::UiMutex;
|
||||||
use render::{self, CellMetrics};
|
use render::{self, CellMetrics};
|
||||||
use shell;
|
use shell;
|
||||||
use cursor;
|
use cursor;
|
||||||
|
use popup_menu;
|
||||||
|
|
||||||
pub struct Level {
|
pub struct Level {
|
||||||
model_layout: ModelLayout,
|
model_layout: ModelLayout,
|
||||||
@ -171,6 +174,7 @@ fn prompt_lines(
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
|
nvim: Option<Rc<nvim::NeovimClient>>,
|
||||||
levels: Vec<Level>,
|
levels: Vec<Level>,
|
||||||
block: Option<Level>,
|
block: Option<Level>,
|
||||||
render_state: Rc<RefCell<shell::RenderState>>,
|
render_state: Rc<RefCell<shell::RenderState>>,
|
||||||
@ -181,6 +185,7 @@ struct State {
|
|||||||
impl State {
|
impl State {
|
||||||
fn new(drawing_area: gtk::DrawingArea, render_state: Rc<RefCell<shell::RenderState>>) -> Self {
|
fn new(drawing_area: gtk::DrawingArea, render_state: Rc<RefCell<shell::RenderState>>) -> Self {
|
||||||
State {
|
State {
|
||||||
|
nvim: None,
|
||||||
levels: Vec::new(),
|
levels: Vec::new(),
|
||||||
block: None,
|
block: None,
|
||||||
render_state,
|
render_state,
|
||||||
@ -262,6 +267,11 @@ impl cursor::CursorRedrawCb for State {
|
|||||||
|
|
||||||
pub struct CmdLine {
|
pub struct CmdLine {
|
||||||
popover: gtk::Popover,
|
popover: gtk::Popover,
|
||||||
|
wild_tree: gtk::TreeView,
|
||||||
|
wild_scroll: gtk::ScrolledWindow,
|
||||||
|
wild_css_provider: gtk::CssProvider,
|
||||||
|
wild_renderer: gtk::CellRendererText,
|
||||||
|
wild_column: gtk::TreeViewColumn,
|
||||||
displyed: bool,
|
displyed: bool,
|
||||||
state: Arc<UiMutex<State>>,
|
state: Arc<UiMutex<State>>,
|
||||||
}
|
}
|
||||||
@ -272,9 +282,10 @@ impl CmdLine {
|
|||||||
popover.set_modal(false);
|
popover.set_modal(false);
|
||||||
popover.set_position(gtk::PositionType::Right);
|
popover.set_position(gtk::PositionType::Right);
|
||||||
|
|
||||||
|
let content = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||||
|
|
||||||
let drawing_area = gtk::DrawingArea::new();
|
let drawing_area = gtk::DrawingArea::new();
|
||||||
drawing_area.show_all();
|
content.pack_start(&drawing_area, true, true, 0);
|
||||||
popover.add(&drawing_area);
|
|
||||||
|
|
||||||
let state = Arc::new(UiMutex::new(State::new(drawing_area.clone(), render_state)));
|
let state = Arc::new(UiMutex::new(State::new(drawing_area.clone(), render_state)));
|
||||||
let weak_cb = Arc::downgrade(&state);
|
let weak_cb = Arc::downgrade(&state);
|
||||||
@ -283,15 +294,76 @@ impl CmdLine {
|
|||||||
|
|
||||||
drawing_area.connect_draw(clone!(state => move |_, ctx| gtk_draw(ctx, &state)));
|
drawing_area.connect_draw(clone!(state => move |_, ctx| gtk_draw(ctx, &state)));
|
||||||
|
|
||||||
|
let (wild_scroll, wild_tree, wild_css_provider, wild_renderer, wild_column) =
|
||||||
|
CmdLine::create_widlmenu(&state);
|
||||||
|
content.pack_start(&wild_scroll, false, true, 0);
|
||||||
|
popover.add(&content);
|
||||||
|
|
||||||
|
drawing_area.show_all();
|
||||||
|
content.show();
|
||||||
|
|
||||||
CmdLine {
|
CmdLine {
|
||||||
popover,
|
popover,
|
||||||
state,
|
state,
|
||||||
displyed: false,
|
displyed: false,
|
||||||
|
wild_scroll,
|
||||||
|
wild_tree,
|
||||||
|
wild_css_provider,
|
||||||
|
wild_renderer,
|
||||||
|
wild_column,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_widlmenu(
|
||||||
|
state: &Arc<UiMutex<State>>,
|
||||||
|
) -> (
|
||||||
|
gtk::ScrolledWindow,
|
||||||
|
gtk::TreeView,
|
||||||
|
gtk::CssProvider,
|
||||||
|
gtk::CellRendererText,
|
||||||
|
gtk::TreeViewColumn,
|
||||||
|
) {
|
||||||
|
let css_provider = gtk::CssProvider::new();
|
||||||
|
|
||||||
|
let tree = gtk::TreeView::new();
|
||||||
|
let style_context = tree.get_style_context().unwrap();
|
||||||
|
style_context.add_provider(&css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
|
|
||||||
|
tree.get_selection().set_mode(gtk::SelectionMode::Single);
|
||||||
|
tree.set_headers_visible(false);
|
||||||
|
tree.set_can_focus(false);
|
||||||
|
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
renderer.set_property_ellipsize(pango::EllipsizeMode::End);
|
||||||
|
|
||||||
|
let column = gtk::TreeViewColumn::new();
|
||||||
|
column.pack_start(&renderer, true);
|
||||||
|
column.add_attribute(&renderer, "text", 0);
|
||||||
|
tree.append_column(&column);
|
||||||
|
|
||||||
|
let scroll = gtk::ScrolledWindow::new(None, None);
|
||||||
|
scroll.set_propagate_natural_height(true);
|
||||||
|
scroll.set_propagate_natural_width(true);
|
||||||
|
|
||||||
|
scroll.add(&tree);
|
||||||
|
|
||||||
|
tree.connect_button_press_event(clone!(state => move |tree, ev| {
|
||||||
|
let state = state.borrow();
|
||||||
|
let nvim = state.nvim.as_ref().unwrap().nvim();
|
||||||
|
if let Some(mut nvim) = nvim {
|
||||||
|
popup_menu::tree_button_press(tree, ev, &mut *nvim, "");
|
||||||
|
}
|
||||||
|
Inhibit(false)
|
||||||
|
}));
|
||||||
|
|
||||||
|
(scroll, tree, css_provider, renderer, column)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn show_level(&mut self, ctx: &CmdLineContext) {
|
pub fn show_level(&mut self, ctx: &CmdLineContext) {
|
||||||
let mut state = self.state.borrow_mut();
|
let mut state = self.state.borrow_mut();
|
||||||
|
if state.nvim.is_none() {
|
||||||
|
state.nvim = Some(ctx.nvim.clone());
|
||||||
|
}
|
||||||
let render_state = state.render_state.clone();
|
let render_state = state.render_state.clone();
|
||||||
let render_state = render_state.borrow();
|
let render_state = render_state.borrow();
|
||||||
|
|
||||||
@ -405,6 +477,65 @@ impl CmdLine {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.set_mode_info(mode_info);
|
.set_mode_info(mode_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show_wildmenu(
|
||||||
|
&self,
|
||||||
|
items: Vec<String>,
|
||||||
|
render_state: &shell::RenderState,
|
||||||
|
max_width: i32,
|
||||||
|
) {
|
||||||
|
// update font/color
|
||||||
|
self.wild_renderer
|
||||||
|
.set_property_font(Some(&render_state.font_ctx.font_description().to_string()));
|
||||||
|
|
||||||
|
self.wild_renderer
|
||||||
|
.set_property_foreground_rgba(Some(&render_state.color_model.pmenu_fg().into()));
|
||||||
|
|
||||||
|
popup_menu::update_css(&self.wild_css_provider, &render_state.color_model);
|
||||||
|
|
||||||
|
// set width
|
||||||
|
// this calculation produce width more then needed, but this is looks ok :)
|
||||||
|
let max_item_width = (items.iter().map(|item| item.len()).max().unwrap() as f64
|
||||||
|
* render_state.font_ctx.cell_metrics().char_width) as i32
|
||||||
|
+ self.state.borrow().levels.last().unwrap().preferred_width;
|
||||||
|
self.wild_column
|
||||||
|
.set_fixed_width(min(max_item_width, max_width));
|
||||||
|
self.wild_scroll.set_max_content_width(max_width);
|
||||||
|
|
||||||
|
// load data
|
||||||
|
let list_store = gtk::ListStore::new(&vec![gtk::Type::String; 1]);
|
||||||
|
for item in items {
|
||||||
|
list_store.insert_with_values(None, &[0], &[&item]);
|
||||||
|
}
|
||||||
|
self.wild_tree.set_model(&list_store);
|
||||||
|
|
||||||
|
// set height
|
||||||
|
let treeview_height =
|
||||||
|
popup_menu::calc_treeview_height(&self.wild_tree, &self.wild_renderer);
|
||||||
|
|
||||||
|
self.wild_scroll.set_max_content_height(treeview_height);
|
||||||
|
|
||||||
|
self.wild_scroll.show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hide_wildmenu(&self) {
|
||||||
|
self.wild_scroll.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wildmenu_select(&self, selected: i64) {
|
||||||
|
if selected >= 0 {
|
||||||
|
let wild_tree = self.wild_tree.clone();
|
||||||
|
idle_add(move || {
|
||||||
|
let selected_path = gtk::TreePath::new_from_string(&format!("{}", selected));
|
||||||
|
wild_tree.get_selection().select_path(&selected_path);
|
||||||
|
wild_tree.scroll_to_cell(&selected_path, None, false, 0.0, 0.0);
|
||||||
|
|
||||||
|
Continue(false)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.wild_tree.get_selection().unselect_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_draw(ctx: &cairo::Context, state: &Arc<UiMutex<State>>) -> Inhibit {
|
fn gtk_draw(ctx: &cairo::Context, state: &Arc<UiMutex<State>>) -> Inhibit {
|
||||||
@ -446,7 +577,8 @@ fn gtk_draw(ctx: &cairo::Context, state: &Arc<UiMutex<State>>) -> Inhibit {
|
|||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CmdLineContext {
|
pub struct CmdLineContext<'a> {
|
||||||
|
pub nvim: &'a Rc<NeovimClient>,
|
||||||
pub content: Vec<(HashMap<String, Value>, String)>,
|
pub content: Vec<(HashMap<String, Value>, String)>,
|
||||||
pub pos: u64,
|
pub pos: u64,
|
||||||
pub firstc: String,
|
pub firstc: String,
|
||||||
@ -460,7 +592,7 @@ pub struct CmdLineContext {
|
|||||||
pub max_width: i32,
|
pub max_width: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CmdLineContext {
|
impl<'a> CmdLineContext<'a> {
|
||||||
fn get_lines(&self) -> LineContent {
|
fn get_lines(&self) -> LineContent {
|
||||||
let content_line: Vec<(Option<Attrs>, Vec<char>)> = self.content
|
let content_line: Vec<(Option<Attrs>, Vec<char>)> = self.content
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -110,6 +110,8 @@ pub fn call_gui_event(
|
|||||||
.ok_or_else(|| "Nvim not initialized".to_owned())
|
.ok_or_else(|| "Nvim not initialized".to_owned())
|
||||||
.and_then(|mut nvim| {
|
.and_then(|mut nvim| {
|
||||||
nvim.set_option(UiOption::ExtCmdline(try_uint!(args[1]) == 1))
|
nvim.set_option(UiOption::ExtCmdline(try_uint!(args[1]) == 1))
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
nvim.set_option(UiOption::ExtWildmenu(try_uint!(args[1]) == 1))
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
})?,
|
})?,
|
||||||
opt => error!("Unknown option {}", opt),
|
opt => error!("Unknown option {}", opt),
|
||||||
@ -229,6 +231,9 @@ pub fn call(
|
|||||||
"cmdline_block_hide" => ui.cmdline_block_hide(),
|
"cmdline_block_hide" => ui.cmdline_block_hide(),
|
||||||
"cmdline_pos" => call!(ui->cmdline_pos(args: uint, uint)),
|
"cmdline_pos" => call!(ui->cmdline_pos(args: uint, uint)),
|
||||||
"cmdline_special_char" => call!(ui->cmdline_special_char(args: str, bool, uint)),
|
"cmdline_special_char" => call!(ui->cmdline_special_char(args: str, bool, uint)),
|
||||||
|
"wildmenu_show" => call!(ui->wildmenu_show(args: ext)),
|
||||||
|
"wildmenu_hide" => ui.wildmenu_hide(),
|
||||||
|
"wildmenu_select" => call!(ui->wildmenu_select(args: int)),
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Event {}({:?})", method, args);
|
warn!("Event {}({:?})", method, args);
|
||||||
RepaintMode::Nothing
|
RepaintMode::Nothing
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
use gtk;
|
use gtk;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
@ -62,11 +63,17 @@ impl State {
|
|||||||
let info_label = gtk::Label::new(None);
|
let info_label = gtk::Label::new(None);
|
||||||
info_label.set_line_wrap(true);
|
info_label.set_line_wrap(true);
|
||||||
|
|
||||||
|
let scroll = gtk::ScrolledWindow::new(None, None);
|
||||||
|
|
||||||
|
tree.connect_size_allocate(
|
||||||
|
clone!(scroll, renderer => move |tree, _| on_treeview_allocate(&scroll, tree, &renderer)),
|
||||||
|
);
|
||||||
|
|
||||||
State {
|
State {
|
||||||
nvim: None,
|
nvim: None,
|
||||||
tree,
|
tree,
|
||||||
scroll: gtk::ScrolledWindow::new(None, None),
|
|
||||||
renderer,
|
renderer,
|
||||||
|
scroll,
|
||||||
css_provider,
|
css_provider,
|
||||||
info_label,
|
info_label,
|
||||||
word_column,
|
word_column,
|
||||||
@ -82,6 +89,7 @@ impl State {
|
|||||||
|
|
||||||
self.scroll.set_max_content_width(ctx.max_width);
|
self.scroll.set_max_content_width(ctx.max_width);
|
||||||
self.scroll.set_propagate_natural_width(true);
|
self.scroll.set_propagate_natural_width(true);
|
||||||
|
self.scroll.set_propagate_natural_height(true);
|
||||||
self.update_tree(&ctx);
|
self.update_tree(&ctx);
|
||||||
self.select(ctx.selected);
|
self.select(ctx.selected);
|
||||||
}
|
}
|
||||||
@ -99,27 +107,29 @@ impl State {
|
|||||||
let (word_max_width, _) = layout.get_pixel_size();
|
let (word_max_width, _) = layout.get_pixel_size();
|
||||||
let word_column_width = word_max_width + xpad * 2 + DEFAULT_PADDING;
|
let word_column_width = word_max_width + xpad * 2 + DEFAULT_PADDING;
|
||||||
|
|
||||||
|
|
||||||
if kind_exists {
|
if kind_exists {
|
||||||
layout.set_text("[v]");
|
layout.set_text("[v]");
|
||||||
let (kind_width, _) = layout.get_pixel_size();
|
let (kind_width, _) = layout.get_pixel_size();
|
||||||
|
|
||||||
self.kind_column.set_fixed_width(kind_width + xpad * 2 + DEFAULT_PADDING);
|
self.kind_column
|
||||||
|
.set_fixed_width(kind_width + xpad * 2 + DEFAULT_PADDING);
|
||||||
self.kind_column.set_visible(true);
|
self.kind_column.set_visible(true);
|
||||||
|
|
||||||
self.word_column.set_fixed_width(min(max_width - kind_width, word_column_width));
|
self.word_column
|
||||||
|
.set_fixed_width(min(max_width - kind_width, word_column_width));
|
||||||
} else {
|
} else {
|
||||||
self.kind_column.set_visible(false);
|
self.kind_column.set_visible(false);
|
||||||
self.word_column.set_fixed_width(min(max_width, word_column_width));
|
self.word_column
|
||||||
|
.set_fixed_width(min(max_width, word_column_width));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let max_menu_line = ctx.menu_items.iter().max_by_key(|m| m.menu.len()).unwrap();
|
let max_menu_line = ctx.menu_items.iter().max_by_key(|m| m.menu.len()).unwrap();
|
||||||
|
|
||||||
if max_menu_line.menu.len() > 0 {
|
if max_menu_line.menu.len() > 0 {
|
||||||
layout.set_text(max_menu_line.menu);
|
layout.set_text(max_menu_line.menu);
|
||||||
let (menu_max_width, _) = layout.get_pixel_size();
|
let (menu_max_width, _) = layout.get_pixel_size();
|
||||||
self.menu_column.set_fixed_width(menu_max_width + xpad * 2 + DEFAULT_PADDING);
|
self.menu_column
|
||||||
|
.set_fixed_width(menu_max_width + xpad * 2 + DEFAULT_PADDING);
|
||||||
self.menu_column.set_visible(true);
|
self.menu_column.set_visible(true);
|
||||||
} else {
|
} else {
|
||||||
self.menu_column.set_visible(false);
|
self.menu_column.set_visible(false);
|
||||||
@ -133,16 +143,14 @@ impl State {
|
|||||||
|
|
||||||
self.limit_column_widths(ctx);
|
self.limit_column_widths(ctx);
|
||||||
|
|
||||||
self.renderer.set_property_font(
|
self.renderer
|
||||||
Some(&ctx.font_ctx.font_description().to_string()),
|
.set_property_font(Some(&ctx.font_ctx.font_description().to_string()));
|
||||||
);
|
|
||||||
|
|
||||||
let color_model = &ctx.color_model;
|
let color_model = &ctx.color_model;
|
||||||
self.renderer.set_property_foreground_rgba(
|
self.renderer
|
||||||
Some(&color_model.pmenu_fg().into()),
|
.set_property_foreground_rgba(Some(&color_model.pmenu_fg().into()));
|
||||||
);
|
|
||||||
|
|
||||||
self.update_css(color_model);
|
update_css(&self.css_provider, color_model);
|
||||||
|
|
||||||
let list_store = gtk::ListStore::new(&vec![gtk::Type::String; 4]);
|
let list_store = gtk::ListStore::new(&vec![gtk::Type::String; 4]);
|
||||||
let all_column_ids: Vec<u32> = (0..4).map(|i| i as u32).collect();
|
let all_column_ids: Vec<u32> = (0..4).map(|i| i as u32).collect();
|
||||||
@ -152,42 +160,17 @@ impl State {
|
|||||||
list_store.insert_with_values(None, &all_column_ids, &line_array[..]);
|
list_store.insert_with_values(None, &all_column_ids, &line_array[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tree.set_model(Some(&list_store));
|
self.tree.set_model(&list_store);
|
||||||
}
|
|
||||||
|
|
||||||
fn update_css(&self, color_model: &ColorModel) {
|
|
||||||
let bg = color_model.pmenu_bg_sel();
|
|
||||||
let fg = color_model.pmenu_fg_sel();
|
|
||||||
|
|
||||||
match gtk::CssProviderExt::load_from_data(
|
|
||||||
&self.css_provider,
|
|
||||||
&format!(
|
|
||||||
".view :selected {{ color: {}; background-color: {};}}\n
|
|
||||||
.view {{ background-color: {}; }}",
|
|
||||||
fg.to_hex(),
|
|
||||||
bg.to_hex(),
|
|
||||||
color_model.pmenu_bg().to_hex(),
|
|
||||||
).as_bytes(),
|
|
||||||
) {
|
|
||||||
Err(e) => error!("Can't update css {}", e),
|
|
||||||
Ok(_) => (),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select(&self, selected: i64) {
|
fn select(&self, selected: i64) {
|
||||||
if selected >= 0 {
|
if selected >= 0 {
|
||||||
let selected_path = gtk::TreePath::new_from_string(&format!("{}", selected));
|
let selected_path = gtk::TreePath::new_from_string(&format!("{}", selected));
|
||||||
self.tree.get_selection().select_path(&selected_path);
|
self.tree.get_selection().select_path(&selected_path);
|
||||||
self.tree.scroll_to_cell(
|
self.tree
|
||||||
Some(&selected_path),
|
.scroll_to_cell(Some(&selected_path), None, false, 0.0, 0.0);
|
||||||
None,
|
|
||||||
false,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.show_info_column(&selected_path);
|
self.show_info_column(&selected_path);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.tree.get_selection().unselect_all();
|
self.tree.get_selection().unselect_all();
|
||||||
self.info_label.hide();
|
self.info_label.hide();
|
||||||
@ -212,17 +195,6 @@ impl State {
|
|||||||
self.info_label.hide();
|
self.info_label.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_treeview_height(&self) -> i32 {
|
|
||||||
let (_, natural_size) = self.renderer.get_preferred_height(&self.tree);
|
|
||||||
let (_, ypad) = self.renderer.get_padding();
|
|
||||||
|
|
||||||
let row_height = natural_size + ypad;
|
|
||||||
|
|
||||||
let actual_count = self.tree.get_model().unwrap().iter_n_children(None);
|
|
||||||
|
|
||||||
row_height * min(actual_count, MAX_VISIBLE_ROWS) as i32
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PopupMenu {
|
pub struct PopupMenu {
|
||||||
@ -243,11 +215,9 @@ impl PopupMenu {
|
|||||||
state.tree.set_headers_visible(false);
|
state.tree.set_headers_visible(false);
|
||||||
state.tree.set_can_focus(false);
|
state.tree.set_can_focus(false);
|
||||||
|
|
||||||
|
state
|
||||||
state.scroll.set_policy(
|
.scroll
|
||||||
gtk::PolicyType::Automatic,
|
.set_policy(gtk::PolicyType::Automatic, gtk::PolicyType::Automatic);
|
||||||
gtk::PolicyType::Automatic,
|
|
||||||
);
|
|
||||||
|
|
||||||
state.scroll.add(&state.tree);
|
state.scroll.add(&state.tree);
|
||||||
state.scroll.show_all();
|
state.scroll.show_all();
|
||||||
@ -259,22 +229,17 @@ impl PopupMenu {
|
|||||||
|
|
||||||
let state = Rc::new(RefCell::new(state));
|
let state = Rc::new(RefCell::new(state));
|
||||||
let state_ref = state.clone();
|
let state_ref = state.clone();
|
||||||
state.borrow().tree.connect_button_press_event(
|
state
|
||||||
move |tree, ev| {
|
.borrow()
|
||||||
|
.tree
|
||||||
|
.connect_button_press_event(move |tree, ev| {
|
||||||
let state = state_ref.borrow();
|
let state = state_ref.borrow();
|
||||||
let nvim = state.nvim.as_ref().unwrap().nvim();
|
let nvim = state.nvim.as_ref().unwrap().nvim();
|
||||||
if let Some(mut nvim) = nvim {
|
if let Some(mut nvim) = nvim {
|
||||||
tree_button_press(tree, ev, &mut *nvim)
|
tree_button_press(tree, ev, &mut *nvim, "<C-y>");
|
||||||
} else {
|
|
||||||
Inhibit(false)
|
|
||||||
}
|
}
|
||||||
},
|
Inhibit(false)
|
||||||
);
|
});
|
||||||
|
|
||||||
let state_ref = state.clone();
|
|
||||||
state.borrow().tree.connect_size_allocate(move |_, _| {
|
|
||||||
on_treeview_allocate(state_ref.clone())
|
|
||||||
});
|
|
||||||
|
|
||||||
let state_ref = state.clone();
|
let state_ref = state.clone();
|
||||||
popover.connect_key_press_event(move |_, ev| {
|
popover.connect_key_press_event(move |_, ev| {
|
||||||
@ -337,15 +302,24 @@ pub struct PopupMenuContext<'a> {
|
|||||||
pub max_width: i32,
|
pub max_width: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tree_button_press(tree: >k::TreeView, ev: &EventButton, nvim: &mut Neovim) -> Inhibit {
|
pub fn tree_button_press(
|
||||||
|
tree: >k::TreeView,
|
||||||
|
ev: &EventButton,
|
||||||
|
nvim: &mut Neovim,
|
||||||
|
last_command: &str,
|
||||||
|
) {
|
||||||
if ev.get_event_type() != EventType::ButtonPress {
|
if ev.get_event_type() != EventType::ButtonPress {
|
||||||
return Inhibit(false);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (paths, ..) = tree.get_selection().get_selected_rows();
|
let (paths, ..) = tree.get_selection().get_selected_rows();
|
||||||
let selected_idx = if !paths.is_empty() {
|
let selected_idx = if !paths.is_empty() {
|
||||||
let ids = paths[0].get_indices();
|
let ids = paths[0].get_indices();
|
||||||
if !ids.is_empty() { ids[0] } else { -1 }
|
if !ids.is_empty() {
|
||||||
|
ids[0]
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
-1
|
-1
|
||||||
};
|
};
|
||||||
@ -356,21 +330,20 @@ fn tree_button_press(tree: >k::TreeView, ev: &EventButton, nvim: &mut Neovim)
|
|||||||
|
|
||||||
let scroll_count = find_scroll_count(selected_idx, target_idx);
|
let scroll_count = find_scroll_count(selected_idx, target_idx);
|
||||||
|
|
||||||
let mut apply_command = String::new();
|
let mut apply_command: String = if target_idx > selected_idx {
|
||||||
|
(0..scroll_count)
|
||||||
for _ in 0..scroll_count {
|
.map(|_| "<C-n>")
|
||||||
if target_idx > selected_idx {
|
.chain(iter::once(last_command))
|
||||||
apply_command.push_str("<C-n>");
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
apply_command.push_str("<C-p>");
|
(0..scroll_count)
|
||||||
}
|
.map(|_| "<C-p>")
|
||||||
}
|
.chain(iter::once(last_command))
|
||||||
apply_command.push_str("<C-y>");
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
nvim.input(&apply_command).report_err();
|
nvim.input(&apply_command).report_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
Inhibit(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_scroll_count(selected_idx: i32, target_idx: i32) -> i32 {
|
fn find_scroll_count(selected_idx: i32, target_idx: i32) -> i32 {
|
||||||
@ -383,22 +356,46 @@ fn find_scroll_count(selected_idx: i32, target_idx: i32) -> i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_treeview_allocate(
|
||||||
|
scroll: >k::ScrolledWindow,
|
||||||
|
tree: >k::TreeView,
|
||||||
|
renderer: >k::CellRendererText,
|
||||||
|
) {
|
||||||
|
let treeview_height = calc_treeview_height(tree, renderer);
|
||||||
|
|
||||||
fn on_treeview_allocate(state: Rc<RefCell<State>>) {
|
idle_add(clone!(scroll => move || {
|
||||||
let treeview_height = state.borrow().calc_treeview_height();
|
scroll
|
||||||
|
.set_max_content_height(treeview_height);
|
||||||
idle_add(move || {
|
|
||||||
let state = state.borrow();
|
|
||||||
|
|
||||||
// strange solution to make gtk assertions happy
|
|
||||||
let previous_height = state.scroll.get_max_content_height();
|
|
||||||
if previous_height < treeview_height {
|
|
||||||
state.scroll.set_max_content_height(treeview_height);
|
|
||||||
state.scroll.set_min_content_height(treeview_height);
|
|
||||||
} else if previous_height > treeview_height {
|
|
||||||
state.scroll.set_min_content_height(treeview_height);
|
|
||||||
state.scroll.set_max_content_height(treeview_height);
|
|
||||||
}
|
|
||||||
Continue(false)
|
Continue(false)
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_css(css_provider: >k::CssProvider, color_model: &ColorModel) {
|
||||||
|
let bg = color_model.pmenu_bg_sel();
|
||||||
|
let fg = color_model.pmenu_fg_sel();
|
||||||
|
|
||||||
|
match gtk::CssProviderExt::load_from_data(
|
||||||
|
css_provider,
|
||||||
|
&format!(
|
||||||
|
".view :selected {{ color: {}; background-color: {};}}\n
|
||||||
|
.view {{ background-color: {}; }}",
|
||||||
|
fg.to_hex(),
|
||||||
|
bg.to_hex(),
|
||||||
|
color_model.pmenu_bg().to_hex(),
|
||||||
|
).as_bytes(),
|
||||||
|
) {
|
||||||
|
Err(e) => error!("Can't update css {}", e),
|
||||||
|
Ok(_) => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calc_treeview_height(tree: >k::TreeView, renderer: >k::CellRendererText) -> i32 {
|
||||||
|
let (_, natural_size) = renderer.get_preferred_height(tree);
|
||||||
|
let (_, ypad) = renderer.get_padding();
|
||||||
|
|
||||||
|
let row_height = natural_size + ypad;
|
||||||
|
|
||||||
|
let actual_count = tree.get_model().unwrap().iter_n_children(None);
|
||||||
|
|
||||||
|
row_height * min(actual_count, MAX_VISIBLE_ROWS) as i32
|
||||||
}
|
}
|
||||||
|
17
src/shell.rs
17
src/shell.rs
@ -1364,6 +1364,7 @@ impl State {
|
|||||||
let render_state = self.render_state.borrow();
|
let render_state = self.render_state.borrow();
|
||||||
let (x, y, width, height) = cursor.to_area(render_state.font_ctx.cell_metrics());
|
let (x, y, width, height) = cursor.to_area(render_state.font_ctx.cell_metrics());
|
||||||
let ctx = CmdLineContext {
|
let ctx = CmdLineContext {
|
||||||
|
nvim: &self.nvim,
|
||||||
content,
|
content,
|
||||||
pos,
|
pos,
|
||||||
firstc,
|
firstc,
|
||||||
@ -1421,6 +1422,22 @@ impl State {
|
|||||||
self.cmd_line.special_char(&*render_state, c, shift, level);
|
self.cmd_line.special_char(&*render_state, c, shift, level);
|
||||||
RepaintMode::Nothing
|
RepaintMode::Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn wildmenu_show(&self, items: Vec<String>) -> RepaintMode {
|
||||||
|
self.cmd_line
|
||||||
|
.show_wildmenu(items, &*self.render_state.borrow(), self.max_popup_width());
|
||||||
|
RepaintMode::Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wildmenu_hide(&self) -> RepaintMode {
|
||||||
|
self.cmd_line.hide_wildmenu();
|
||||||
|
RepaintMode::Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wildmenu_select(&self, selected: i64) -> RepaintMode {
|
||||||
|
self.cmd_line.wildmenu_select(selected);
|
||||||
|
RepaintMode::Nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CursorRedrawCb for State {
|
impl CursorRedrawCb for State {
|
||||||
|
Loading…
Reference in New Issue
Block a user