Basic implementation of tabline
This commit is contained in:
parent
68963ab628
commit
42538027bf
@ -30,6 +30,7 @@ mod cursor;
|
|||||||
mod shell_dlg;
|
mod shell_dlg;
|
||||||
mod popup_menu;
|
mod popup_menu;
|
||||||
mod project;
|
mod project;
|
||||||
|
mod tabline;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use gio::ApplicationExt;
|
use gio::ApplicationExt;
|
||||||
|
29
src/nvim.rs
29
src/nvim.rs
@ -4,8 +4,10 @@ use std::process::{Stdio, Command};
|
|||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ui::UiMutex;
|
|
||||||
use neovim_lib::{Handler, Neovim, NeovimApi, Session, Value, UiAttachOptions, CallError, UiOption};
|
use neovim_lib::{Handler, Neovim, NeovimApi, Session, Value, UiAttachOptions, CallError, UiOption};
|
||||||
|
use neovim_lib::neovim_api::Tabpage;
|
||||||
|
|
||||||
|
use ui::UiMutex;
|
||||||
use ui_model::{ModelRect, ModelRectVec};
|
use ui_model::{ModelRect, ModelRectVec};
|
||||||
use shell;
|
use shell;
|
||||||
use glib;
|
use glib;
|
||||||
@ -51,6 +53,8 @@ pub trait RedrawEvents {
|
|||||||
fn popupmenu_hide(&mut self) -> RepaintMode;
|
fn popupmenu_hide(&mut self) -> RepaintMode;
|
||||||
|
|
||||||
fn popupmenu_select(&mut self, selected: i64) -> RepaintMode;
|
fn popupmenu_select(&mut self, selected: i64) -> RepaintMode;
|
||||||
|
|
||||||
|
fn tabline_update(&mut self, selected: Tabpage, tabs: Vec<(Tabpage, Option<&str>)>) -> RepaintMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GuiApi {
|
pub trait GuiApi {
|
||||||
@ -112,6 +116,7 @@ pub fn initialize(shell: Arc<UiMutex<shell::State>>,
|
|||||||
.start_event_loop_handler(NvimHandler::new(shell));
|
.start_event_loop_handler(NvimHandler::new(shell));
|
||||||
let mut opts = UiAttachOptions::new();
|
let mut opts = UiAttachOptions::new();
|
||||||
opts.set_popupmenu_external(false);
|
opts.set_popupmenu_external(false);
|
||||||
|
opts.set_tabline_external(true);
|
||||||
nvim.ui_attach(80, 24, opts)
|
nvim.ui_attach(80, 24, opts)
|
||||||
.map_err(|e| Error::new(ErrorKind::Other, e))?;
|
.map_err(|e| Error::new(ErrorKind::Other, e))?;
|
||||||
nvim.command("runtime! ginit.vim")
|
nvim.command("runtime! ginit.vim")
|
||||||
@ -275,6 +280,28 @@ fn call(ui: &mut shell::State,
|
|||||||
}
|
}
|
||||||
"popupmenu_hide" => ui.popupmenu_hide(),
|
"popupmenu_hide" => ui.popupmenu_hide(),
|
||||||
"popupmenu_select" => ui.popupmenu_select(try_int!(args[0])),
|
"popupmenu_select" => ui.popupmenu_select(try_int!(args[0])),
|
||||||
|
"tabline_update" => {
|
||||||
|
let tabs_in = args[1].as_array().ok_or("Error get tabline list")?;
|
||||||
|
|
||||||
|
let mut tabs_out = Vec::new();
|
||||||
|
for tab in tabs_in {
|
||||||
|
let tab_attrs = tab.as_map().ok_or("Error get map for tab")?;
|
||||||
|
|
||||||
|
let mut tab_attr = None;
|
||||||
|
let mut name_attr = None;
|
||||||
|
|
||||||
|
for attr in tab_attrs {
|
||||||
|
let key = attr.0.as_str().ok_or("Error get key value")?;
|
||||||
|
if key == "tab" {
|
||||||
|
tab_attr = Some(Tabpage::new(attr.1.clone()));
|
||||||
|
} else if key == "name" {
|
||||||
|
name_attr = attr.1.as_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabs_out.push((tab_attr.unwrap(), name_attr));
|
||||||
|
}
|
||||||
|
ui.tabline_update(Tabpage::new(args[0].clone()), tabs_out)
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
println!("Event {}({:?})", method, args);
|
println!("Event {}({:?})", method, args);
|
||||||
RepaintMode::Nothing
|
RepaintMode::Nothing
|
||||||
|
51
src/shell.rs
51
src/shell.rs
@ -1,7 +1,8 @@
|
|||||||
use std::cell::{Ref, RefMut, RefCell};
|
use std::cell::{RefMut, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync;
|
use std::sync;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use cairo;
|
use cairo;
|
||||||
use pangocairo::CairoContextExt;
|
use pangocairo::CairoContextExt;
|
||||||
@ -10,10 +11,11 @@ use pango::FontDescription;
|
|||||||
use gdk::{ModifierType, EventConfigure, EventButton, EventMotion, EventType, EventScroll};
|
use gdk::{ModifierType, EventConfigure, EventButton, EventMotion, EventType, EventScroll};
|
||||||
use gdk_sys;
|
use gdk_sys;
|
||||||
use glib;
|
use glib;
|
||||||
|
use gtk;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::DrawingArea;
|
|
||||||
|
|
||||||
use neovim_lib::{Neovim, NeovimApi, Value};
|
use neovim_lib::{Neovim, NeovimApi, Value};
|
||||||
|
use neovim_lib::neovim_api::Tabpage;
|
||||||
|
|
||||||
use settings::{Settings, FontSource};
|
use settings::{Settings, FontSource};
|
||||||
use ui_model::{UiModel, Cell, Attrs, Color, ModelRect, COLOR_BLACK, COLOR_WHITE, COLOR_RED};
|
use ui_model::{UiModel, Cell, Attrs, Color, ModelRect, COLOR_BLACK, COLOR_WHITE, COLOR_RED};
|
||||||
@ -25,6 +27,7 @@ use cursor::Cursor;
|
|||||||
use ui;
|
use ui;
|
||||||
use ui::UiMutex;
|
use ui::UiMutex;
|
||||||
use popup_menu::PopupMenu;
|
use popup_menu::PopupMenu;
|
||||||
|
use tabline::Tabline;
|
||||||
|
|
||||||
const DEFAULT_FONT_NAME: &'static str = "DejaVu Sans Mono 12";
|
const DEFAULT_FONT_NAME: &'static str = "DejaVu Sans Mono 12";
|
||||||
|
|
||||||
@ -44,13 +47,15 @@ pub struct State {
|
|||||||
cur_attrs: Option<Attrs>,
|
cur_attrs: Option<Attrs>,
|
||||||
pub mode: NvimMode,
|
pub mode: NvimMode,
|
||||||
mouse_enabled: bool,
|
mouse_enabled: bool,
|
||||||
drawing_area: DrawingArea,
|
|
||||||
nvim: Option<Rc<RefCell<Neovim>>>,
|
nvim: Option<Rc<RefCell<Neovim>>>,
|
||||||
font_desc: FontDescription,
|
font_desc: FontDescription,
|
||||||
cursor: Option<Cursor>,
|
cursor: Option<Cursor>,
|
||||||
popup_menu: RefCell<PopupMenu>,
|
popup_menu: RefCell<PopupMenu>,
|
||||||
settings: Rc<RefCell<Settings>>,
|
settings: Rc<RefCell<Settings>>,
|
||||||
|
|
||||||
|
drawing_area: gtk::DrawingArea,
|
||||||
|
tabs: Tabline,
|
||||||
|
|
||||||
line_height: Option<f64>,
|
line_height: Option<f64>,
|
||||||
char_width: Option<f64>,
|
char_width: Option<f64>,
|
||||||
request_resize: bool,
|
request_resize: bool,
|
||||||
@ -61,12 +66,11 @@ pub struct State {
|
|||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new(settings: Rc<RefCell<Settings>>, parent: &Arc<UiMutex<ui::Components>>) -> State {
|
pub fn new(settings: Rc<RefCell<Settings>>, parent: &Arc<UiMutex<ui::Components>>) -> State {
|
||||||
let drawing_area = DrawingArea::new();
|
let drawing_area = gtk::DrawingArea::new();
|
||||||
let popup_menu = RefCell::new(PopupMenu::new(&drawing_area));
|
let popup_menu = RefCell::new(PopupMenu::new(&drawing_area));
|
||||||
|
|
||||||
State {
|
State {
|
||||||
model: UiModel::new(24, 80),
|
model: UiModel::new(24, 80),
|
||||||
drawing_area,
|
|
||||||
nvim: None,
|
nvim: None,
|
||||||
cur_attrs: None,
|
cur_attrs: None,
|
||||||
bg_color: COLOR_BLACK,
|
bg_color: COLOR_BLACK,
|
||||||
@ -79,6 +83,9 @@ impl State {
|
|||||||
popup_menu,
|
popup_menu,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
|
|
||||||
|
drawing_area,
|
||||||
|
tabs: Tabline::new(),
|
||||||
|
|
||||||
line_height: None,
|
line_height: None,
|
||||||
char_width: None,
|
char_width: None,
|
||||||
resize_timer: None,
|
resize_timer: None,
|
||||||
@ -191,6 +198,8 @@ impl UiState {
|
|||||||
pub struct Shell {
|
pub struct Shell {
|
||||||
pub state: Arc<UiMutex<State>>,
|
pub state: Arc<UiMutex<State>>,
|
||||||
ui_state: Rc<RefCell<UiState>>,
|
ui_state: Rc<RefCell<UiState>>,
|
||||||
|
|
||||||
|
widget: gtk::Box,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shell {
|
impl Shell {
|
||||||
@ -198,6 +207,8 @@ impl Shell {
|
|||||||
let shell = Shell {
|
let shell = Shell {
|
||||||
state: Arc::new(UiMutex::new(State::new(settings, parent))),
|
state: Arc::new(UiMutex::new(State::new(settings, parent))),
|
||||||
ui_state: Rc::new(RefCell::new(UiState::new())),
|
ui_state: Rc::new(RefCell::new(UiState::new())),
|
||||||
|
|
||||||
|
widget: gtk::Box::new(gtk::Orientation::Vertical, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let shell_ref = Arc::downgrade(&shell.state);
|
let shell_ref = Arc::downgrade(&shell.state);
|
||||||
@ -213,6 +224,9 @@ impl Shell {
|
|||||||
state.drawing_area.set_vexpand(true);
|
state.drawing_area.set_vexpand(true);
|
||||||
state.drawing_area.set_can_focus(true);
|
state.drawing_area.set_can_focus(true);
|
||||||
|
|
||||||
|
self.widget.pack_start(&*state.tabs, false, true, 0);
|
||||||
|
self.widget.pack_start(&state.drawing_area, true, true, 0);
|
||||||
|
|
||||||
state
|
state
|
||||||
.drawing_area
|
.drawing_area
|
||||||
.set_events((gdk_sys::GDK_BUTTON_RELEASE_MASK | gdk_sys::GDK_BUTTON_PRESS_MASK |
|
.set_events((gdk_sys::GDK_BUTTON_RELEASE_MASK | gdk_sys::GDK_BUTTON_PRESS_MASK |
|
||||||
@ -284,14 +298,6 @@ impl Shell {
|
|||||||
.connect_focus_out_event(move |_, _| gtk_focus_out(&mut *ref_state.borrow_mut()));
|
.connect_focus_out_event(move |_, _| gtk_focus_out(&mut *ref_state.borrow_mut()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state(&self) -> Ref<State> {
|
|
||||||
self.state.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drawing_area(&self) -> Ref<DrawingArea> {
|
|
||||||
Ref::map(self.state(), |s| &s.drawing_area)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn redraw(&self, mode: &RepaintMode) {
|
pub fn redraw(&self, mode: &RepaintMode) {
|
||||||
self.state.borrow_mut().on_redraw(mode);
|
self.state.borrow_mut().on_redraw(mode);
|
||||||
@ -320,6 +326,10 @@ impl Shell {
|
|||||||
state.nvim = Some(Rc::new(RefCell::new(nvim)));
|
state.nvim = Some(Rc::new(RefCell::new(nvim)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn grab_focus(&self) {
|
||||||
|
self.state.borrow().drawing_area.grab_focus();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn open_file(&self, path: &str) {
|
pub fn open_file(&self, path: &str) {
|
||||||
self.state.borrow().open_file(path);
|
self.state.borrow().open_file(path);
|
||||||
}
|
}
|
||||||
@ -352,6 +362,14 @@ impl Shell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for Shell {
|
||||||
|
type Target = gtk::Box;
|
||||||
|
|
||||||
|
fn deref(&self) -> >k::Box {
|
||||||
|
&self.widget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn gtk_focus_in(state: &mut State) -> Inhibit {
|
fn gtk_focus_in(state: &mut State) -> Inhibit {
|
||||||
state.cursor.as_mut().unwrap().enter_focus();
|
state.cursor.as_mut().unwrap().enter_focus();
|
||||||
let point = state.model.cur_point();
|
let point = state.model.cur_point();
|
||||||
@ -864,6 +882,13 @@ impl RedrawEvents for State {
|
|||||||
self.popup_menu.borrow().select(selected);
|
self.popup_menu.borrow().select(selected);
|
||||||
RepaintMode::Nothing
|
RepaintMode::Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn tabline_update(&mut self, selected: Tabpage, tabs: Vec<(Tabpage, Option<&str>)>) -> RepaintMode {
|
||||||
|
self.tabs.update_tabs(&selected, &tabs);
|
||||||
|
|
||||||
|
RepaintMode::Nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuiApi for State {
|
impl GuiApi for State {
|
||||||
|
55
src/tabline.rs
Normal file
55
src/tabline.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use gtk;
|
||||||
|
use gtk::prelude::*;
|
||||||
|
|
||||||
|
use neovim_lib::neovim_api::Tabpage;
|
||||||
|
|
||||||
|
pub struct Tabline {
|
||||||
|
tabs: gtk::Notebook,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tabline {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let tabs = gtk::Notebook::new();
|
||||||
|
|
||||||
|
tabs.set_can_focus(false);
|
||||||
|
tabs.set_scrollable(true);
|
||||||
|
tabs.set_show_border(false);
|
||||||
|
tabs.set_border_width(0);
|
||||||
|
|
||||||
|
Tabline {
|
||||||
|
tabs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_tabs(&self, selected: &Tabpage, tabs: &Vec<(Tabpage, Option<&str>)>) {
|
||||||
|
let count = self.tabs.get_n_pages() as usize;
|
||||||
|
if count < tabs.len() {
|
||||||
|
for _ in count..tabs.len() {
|
||||||
|
let empty = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||||
|
empty.show_all();
|
||||||
|
self.tabs.append_page(&empty, Some(>k::Label::new("AA")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if count > tabs.len() {
|
||||||
|
for _ in tabs.len()..count {
|
||||||
|
self.tabs.remove_page(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: current page
|
||||||
|
for (idx, tab) in tabs.iter().enumerate() {
|
||||||
|
let tab_child = self.tabs.get_nth_page(Some(idx as u32));
|
||||||
|
self.tabs.set_tab_label_text(&tab_child.unwrap(), &tab.1.unwrap_or("??"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Tabline {
|
||||||
|
type Target = gtk::Notebook;
|
||||||
|
|
||||||
|
fn deref(&self) -> >k::Notebook {
|
||||||
|
&self.tabs
|
||||||
|
}
|
||||||
|
}
|
@ -114,7 +114,7 @@ impl Ui {
|
|||||||
window.set_titlebar(Some(&comps.header_bar));
|
window.set_titlebar(Some(&comps.header_bar));
|
||||||
|
|
||||||
let mut shell = self.shell.borrow_mut();
|
let mut shell = self.shell.borrow_mut();
|
||||||
window.add(&*shell.drawing_area());
|
window.add(&**shell);
|
||||||
|
|
||||||
window.show_all();
|
window.show_all();
|
||||||
window.set_title("Neovim-gtk");
|
window.set_title("Neovim-gtk");
|
||||||
@ -125,6 +125,7 @@ impl Ui {
|
|||||||
|
|
||||||
shell.add_configure_event();
|
shell.add_configure_event();
|
||||||
shell.init_nvim(nvim_bin_path);
|
shell.init_nvim(nvim_bin_path);
|
||||||
|
shell.grab_focus();
|
||||||
|
|
||||||
if open_path.is_some() {
|
if open_path.is_some() {
|
||||||
shell.open_file(open_path.unwrap());
|
shell.open_file(open_path.unwrap());
|
||||||
|
Loading…
Reference in New Issue
Block a user