Refactoring for remove global variables.
This commit is contained in:
parent
057fad0e87
commit
ade1f9a5de
@ -1,9 +1,10 @@
|
|||||||
use cairo;
|
use cairo;
|
||||||
use ui_model::Color;
|
use ui_model::Color;
|
||||||
use ui::{SH, UiMutex};
|
use ui::UiMutex;
|
||||||
use shell::{Shell, NvimMode};
|
use shell;
|
||||||
|
use shell::NvimMode;
|
||||||
use nvim::{RepaintMode, RedrawEvents};
|
use nvim::{RepaintMode, RedrawEvents};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
use glib;
|
use glib;
|
||||||
|
|
||||||
@ -43,15 +44,17 @@ enum AnimPhase {
|
|||||||
struct State {
|
struct State {
|
||||||
alpha: Alpha,
|
alpha: Alpha,
|
||||||
anim_phase: AnimPhase,
|
anim_phase: AnimPhase,
|
||||||
|
shell: Weak<UiMutex<shell::State>>,
|
||||||
|
|
||||||
timer: Option<glib::SourceId>,
|
timer: Option<glib::SourceId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
fn new() -> State {
|
fn new(shell: Weak<UiMutex<shell::State>>) -> State {
|
||||||
State {
|
State {
|
||||||
alpha: Alpha(1.0),
|
alpha: Alpha(1.0),
|
||||||
anim_phase: AnimPhase::Shown,
|
anim_phase: AnimPhase::Shown,
|
||||||
|
shell: shell,
|
||||||
timer: None,
|
timer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,8 +74,8 @@ pub struct Cursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Cursor {
|
impl Cursor {
|
||||||
pub fn new() -> Cursor {
|
pub fn new(shell: Weak<UiMutex<shell::State>>) -> Cursor {
|
||||||
Cursor { state: Arc::new(UiMutex::new(State::new())) }
|
Cursor { state: Arc::new(UiMutex::new(State::new(shell))) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
@ -85,7 +88,7 @@ impl Cursor {
|
|||||||
pub fn reset_state(&mut self) {
|
pub fn reset_state(&mut self) {
|
||||||
self.start();
|
self.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_focus(&mut self) {
|
pub fn enter_focus(&mut self) {
|
||||||
self.start();
|
self.start();
|
||||||
}
|
}
|
||||||
@ -104,7 +107,7 @@ impl Cursor {
|
|||||||
|
|
||||||
pub fn draw(&self,
|
pub fn draw(&self,
|
||||||
ctx: &cairo::Context,
|
ctx: &cairo::Context,
|
||||||
shell: &Shell,
|
shell: &shell::State,
|
||||||
char_width: f64,
|
char_width: f64,
|
||||||
line_height: f64,
|
line_height: f64,
|
||||||
line_y: f64,
|
line_y: f64,
|
||||||
@ -140,7 +143,6 @@ impl Cursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn anim_step(state: &Arc<UiMutex<State>>) -> glib::Continue {
|
fn anim_step(state: &Arc<UiMutex<State>>) -> glib::Continue {
|
||||||
let moved_state = state.clone();
|
|
||||||
let mut mut_state = state.borrow_mut();
|
let mut mut_state = state.borrow_mut();
|
||||||
|
|
||||||
let next_event = match mut_state.anim_phase {
|
let next_event = match mut_state.anim_phase {
|
||||||
@ -175,13 +177,14 @@ fn anim_step(state: &Arc<UiMutex<State>>) -> glib::Continue {
|
|||||||
AnimPhase::Busy => None,
|
AnimPhase::Busy => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
SHELL!(&shell = {
|
let shell = mut_state.shell.upgrade().unwrap();
|
||||||
let point = shell.model.cur_point();
|
let shell = shell.borrow();
|
||||||
shell.on_redraw(&RepaintMode::Area(point));
|
let point = shell.model.cur_point();
|
||||||
});
|
shell.on_redraw(&RepaintMode::Area(point));
|
||||||
|
|
||||||
|
|
||||||
if let Some(timeout) = next_event {
|
if let Some(timeout) = next_event {
|
||||||
|
let moved_state = state.clone();
|
||||||
mut_state.timer = Some(glib::timeout_add(timeout, move || anim_step(&moved_state)));
|
mut_state.timer = Some(glib::timeout_add(timeout, move || anim_step(&moved_state)));
|
||||||
|
|
||||||
glib::Continue(false)
|
glib::Continue(false)
|
||||||
|
60
src/main.rs
60
src/main.rs
@ -9,7 +9,7 @@ extern crate pango;
|
|||||||
extern crate pangocairo;
|
extern crate pangocairo;
|
||||||
extern crate neovim_lib;
|
extern crate neovim_lib;
|
||||||
extern crate phf;
|
extern crate phf;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
@ -23,12 +23,10 @@ mod settings;
|
|||||||
mod cursor;
|
mod cursor;
|
||||||
mod shell_dlg;
|
mod shell_dlg;
|
||||||
|
|
||||||
use std::thread;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use gio::ApplicationExt;
|
use gio::ApplicationExt;
|
||||||
|
|
||||||
use shell::Shell;
|
use ui::Ui;
|
||||||
use ui::SH;
|
|
||||||
|
|
||||||
const BIN_PATH_ARG: &'static str = "--nvim-bin-path";
|
const BIN_PATH_ARG: &'static str = "--nvim-bin-path";
|
||||||
|
|
||||||
@ -41,8 +39,10 @@ fn main() {
|
|||||||
app.connect_activate(activate);
|
app.connect_activate(activate);
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let mut argv: Vec<&str> =
|
let mut argv: Vec<&str> = args.iter()
|
||||||
args.iter().filter(|a| !a.starts_with(BIN_PATH_ARG)).map(String::as_str).collect();
|
.filter(|a| !a.starts_with(BIN_PATH_ARG))
|
||||||
|
.map(String::as_str)
|
||||||
|
.collect();
|
||||||
if open_arg().is_some() {
|
if open_arg().is_some() {
|
||||||
argv.pop();
|
argv.pop();
|
||||||
}
|
}
|
||||||
@ -50,24 +50,11 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn activate(app: >k::Application) {
|
fn activate(app: >k::Application) {
|
||||||
ui::UI.with(|ui_cell| {
|
let mut ui = Ui::new();
|
||||||
let mut ui = ui_cell.borrow_mut();
|
|
||||||
if !ui.initialized {
|
|
||||||
ui.init(app);
|
|
||||||
|
|
||||||
let path = nvim_bin_path(std::env::args());
|
ui.init(app,
|
||||||
SHELL!(shell = {
|
nvim_bin_path(std::env::args()).as_ref(),
|
||||||
nvim::initialize(&mut shell, path.as_ref())
|
open_arg().as_ref());
|
||||||
.expect("Can't start nvim instance");
|
|
||||||
|
|
||||||
guard_dispatch_thread(&mut shell);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SHELL!(shell = {
|
|
||||||
nvim::open_file(shell.nvim(), open_arg().as_ref());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nvim_bin_path<I>(args: I) -> Option<String>
|
fn nvim_bin_path<I>(args: I) -> Option<String>
|
||||||
@ -89,24 +76,13 @@ fn open_arg_impl<I>(args: I) -> Option<String>
|
|||||||
args.skip(1)
|
args.skip(1)
|
||||||
.last()
|
.last()
|
||||||
.map(|a| if !a.starts_with("-") {
|
.map(|a| if !a.starts_with("-") {
|
||||||
Some(a.to_owned())
|
Some(a.to_owned())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guard_dispatch_thread(shell: &mut Shell) {
|
|
||||||
let guard = shell.nvim().session.take_dispatch_guard();
|
|
||||||
thread::spawn(move || {
|
|
||||||
guard.join().expect("Can't join dispatch thread");
|
|
||||||
glib::idle_add(move || {
|
|
||||||
ui::UI.with(|ui_cell| { ui_cell.borrow().close_window(); });
|
|
||||||
glib::Continue(false)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -115,8 +91,8 @@ mod tests {
|
|||||||
fn test_bin_path_arg() {
|
fn test_bin_path_arg() {
|
||||||
assert_eq!(Some("/test_path".to_string()),
|
assert_eq!(Some("/test_path".to_string()),
|
||||||
nvim_bin_path(vec!["neovim-gtk", "--nvim-bin-path=/test_path"]
|
nvim_bin_path(vec!["neovim-gtk", "--nvim-bin-path=/test_path"]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_string())));
|
.map(|s| s.to_string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -125,8 +101,8 @@ mod tests {
|
|||||||
open_arg_impl(vec!["neovim-gtk",
|
open_arg_impl(vec!["neovim-gtk",
|
||||||
"--nvim-bin-path=/test_path",
|
"--nvim-bin-path=/test_path",
|
||||||
"some_file.txt"]
|
"some_file.txt"]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_string())));
|
.map(|s| s.to_string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
247
src/nvim.rs
247
src/nvim.rs
@ -1,9 +1,11 @@
|
|||||||
use neovim_lib::{Handler, Neovim, NeovimApi, Session, Value, UiAttachOptions, CallError};
|
|
||||||
use std::io::{Result, Error, ErrorKind};
|
use std::io::{Result, Error, ErrorKind};
|
||||||
use std::result;
|
use std::result;
|
||||||
use ui_model::{UiModel, ModelRect};
|
use std::sync::Arc;
|
||||||
use ui::SH;
|
|
||||||
use shell::Shell;
|
use ui::UiMutex;
|
||||||
|
use neovim_lib::{Handler, Neovim, NeovimApi, Session, Value, UiAttachOptions, CallError};
|
||||||
|
use ui_model::ModelRect;
|
||||||
|
use shell;
|
||||||
use glib;
|
use glib;
|
||||||
|
|
||||||
pub trait RedrawEvents {
|
pub trait RedrawEvents {
|
||||||
@ -63,98 +65,111 @@ macro_rules! try_uint {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize(ui: &mut Shell, nvim_bin_path: Option<&String>) -> Result<()> {
|
pub fn initialize(shell: Arc<UiMutex<shell::State>>,
|
||||||
|
nvim_bin_path: Option<&String>)
|
||||||
|
-> Result<Neovim> {
|
||||||
let session = if let Some(path) = nvim_bin_path {
|
let session = if let Some(path) = nvim_bin_path {
|
||||||
Session::new_child_path(path)?
|
Session::new_child_path(path)?
|
||||||
} else {
|
} else {
|
||||||
Session::new_child()?
|
Session::new_child()?
|
||||||
};
|
};
|
||||||
|
|
||||||
let nvim = Neovim::new(session);
|
let mut nvim = Neovim::new(session);
|
||||||
ui.set_nvim(nvim);
|
|
||||||
ui.model = UiModel::new(24, 80);
|
|
||||||
|
|
||||||
let mut nvim = ui.nvim();
|
nvim.session
|
||||||
|
.start_event_loop_handler(NvimHandler::new(shell));
|
||||||
|
nvim.ui_attach(80, 24, UiAttachOptions::new())
|
||||||
|
.map_err(|e| Error::new(ErrorKind::Other, e))?;
|
||||||
|
nvim.command("runtime! ginit.vim")
|
||||||
|
.map_err(|e| Error::new(ErrorKind::Other, e))?;
|
||||||
|
|
||||||
nvim.session.start_event_loop_handler(NvimHandler::new());
|
Ok(nvim)
|
||||||
nvim.ui_attach(80, 24, UiAttachOptions::new()).map_err(|e| Error::new(ErrorKind::Other, e))?;
|
|
||||||
nvim.command("runtime! ginit.vim").map_err(|e| Error::new(ErrorKind::Other, e))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_file(nvim: &mut NeovimApi, file: Option<&String>) {
|
pub struct NvimHandler {
|
||||||
if let Some(file_name) = file {
|
shell: Arc<UiMutex<shell::State>>,
|
||||||
nvim.command(&format!("e {}", file_name)).report_err(nvim);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NvimHandler {}
|
|
||||||
|
|
||||||
impl NvimHandler {
|
impl NvimHandler {
|
||||||
pub fn new() -> NvimHandler {
|
pub fn new(shell: Arc<UiMutex<shell::State>>) -> NvimHandler {
|
||||||
NvimHandler {}
|
NvimHandler { shell: shell }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nvim_cb(&self, method: &str, params: Vec<Value>) {
|
||||||
|
match method {
|
||||||
|
"redraw" => {
|
||||||
|
self.safe_call(move |ui| {
|
||||||
|
let mut repaint_mode = RepaintMode::Nothing;
|
||||||
|
|
||||||
|
for ev in ¶ms {
|
||||||
|
if let Some(ev_args) = ev.as_array() {
|
||||||
|
if let Some(ev_name) = ev_args[0].as_str() {
|
||||||
|
for ref local_args in ev_args.iter().skip(1) {
|
||||||
|
let args = match *local_args {
|
||||||
|
&Value::Array(ref ar) => ar.clone(),
|
||||||
|
_ => vec![],
|
||||||
|
};
|
||||||
|
let call_reapint_mode = call(ui, ev_name, &args)?;
|
||||||
|
repaint_mode = repaint_mode.join(&call_reapint_mode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Unsupported event {:?}", ev_args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Unsupported event type {:?}", ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.on_redraw(&repaint_mode);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"Gui" => {
|
||||||
|
if params.len() > 0 {
|
||||||
|
if let Some(ev_name) = params[0].as_str().map(String::from) {
|
||||||
|
let args = params.iter().skip(1).cloned().collect();
|
||||||
|
self.safe_call(move |ui| {
|
||||||
|
call_gui_event(ui, &ev_name, &args)?;
|
||||||
|
ui.on_redraw(&RepaintMode::All);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
println!("Unsupported event {:?}", params);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Unsupported event {:?}", params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("Notification {}({:?})", method, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn safe_call<F>(&self, cb: F)
|
||||||
|
where F: Fn(&mut shell::State) -> result::Result<(), String> + 'static + Send
|
||||||
|
{
|
||||||
|
let shell = self.shell.clone();
|
||||||
|
glib::idle_add(move || {
|
||||||
|
if let Err(msg) = cb(&mut shell.borrow_mut()) {
|
||||||
|
println!("Error call function: {}", msg);
|
||||||
|
}
|
||||||
|
glib::Continue(false)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler for NvimHandler {
|
impl Handler for NvimHandler {
|
||||||
fn handle_notify(&mut self, name: &str, args: &Vec<Value>) {
|
fn handle_notify(&mut self, name: &str, args: &Vec<Value>) {
|
||||||
nvim_cb(name, args.clone());
|
self.nvim_cb(name, args.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nvim_cb(method: &str, params: Vec<Value>) {
|
|
||||||
match method {
|
|
||||||
"redraw" => {
|
|
||||||
safe_call(move |ui| {
|
|
||||||
let mut repaint_mode = RepaintMode::Nothing;
|
|
||||||
|
|
||||||
for ev in ¶ms {
|
fn call_gui_event(ui: &mut shell::State,
|
||||||
if let Some(ev_args) = ev.as_array() {
|
method: &str,
|
||||||
if let Some(ev_name) = ev_args[0].as_str() {
|
args: &Vec<Value>)
|
||||||
for ref local_args in ev_args.iter().skip(1) {
|
-> result::Result<(), String> {
|
||||||
let args = match *local_args {
|
|
||||||
&Value::Array(ref ar) => ar.clone(),
|
|
||||||
_ => vec![],
|
|
||||||
};
|
|
||||||
let call_reapint_mode = call(ui, ev_name, &args)?;
|
|
||||||
repaint_mode = repaint_mode.join(&call_reapint_mode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Unsupported event {:?}", ev_args);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Unsupported event type {:?}", ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.on_redraw(&repaint_mode);
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
"Gui" => {
|
|
||||||
if params.len() > 0 {
|
|
||||||
if let Some(ev_name) = params[0].as_str().map(String::from) {
|
|
||||||
let args = params.iter().skip(1).cloned().collect();
|
|
||||||
safe_call(move |ui| {
|
|
||||||
call_gui_event(ui, &ev_name, &args)?;
|
|
||||||
ui.on_redraw(&RepaintMode::All);
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
println!("Unsupported event {:?}", params);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Unsupported event {:?}", params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
println!("Notification {}({:?})", method, params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_gui_event(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Result<(), String> {
|
|
||||||
match method {
|
match method {
|
||||||
"Font" => ui.set_font(try_str!(args[0])),
|
"Font" => ui.set_font(try_str!(args[0])),
|
||||||
_ => return Err(format!("Unsupported event {}({:?})", method, args)),
|
_ => return Err(format!("Unsupported event {}({:?})", method, args)),
|
||||||
@ -162,55 +177,45 @@ fn call_gui_event(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Re
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Result<RepaintMode, String> {
|
fn call(ui: &mut shell::State,
|
||||||
|
method: &str,
|
||||||
|
args: &Vec<Value>)
|
||||||
|
-> result::Result<RepaintMode, String> {
|
||||||
Ok(match method {
|
Ok(match method {
|
||||||
"cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])),
|
"cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])),
|
||||||
"put" => ui.on_put(try_str!(args[0])),
|
"put" => ui.on_put(try_str!(args[0])),
|
||||||
"clear" => ui.on_clear(),
|
"clear" => ui.on_clear(),
|
||||||
"resize" => ui.on_resize(try_uint!(args[0]), try_uint!(args[1])),
|
"resize" => ui.on_resize(try_uint!(args[0]), try_uint!(args[1])),
|
||||||
"highlight_set" => {
|
"highlight_set" => {
|
||||||
if let Value::Map(ref attrs) = args[0] {
|
if let Value::Map(ref attrs) = args[0] {
|
||||||
ui.on_highlight_set(attrs);
|
ui.on_highlight_set(attrs);
|
||||||
} else {
|
} else {
|
||||||
panic!("Supports only map value as argument");
|
panic!("Supports only map value as argument");
|
||||||
}
|
|
||||||
RepaintMode::Nothing
|
|
||||||
}
|
}
|
||||||
"eol_clear" => ui.on_eol_clear(),
|
RepaintMode::Nothing
|
||||||
"set_scroll_region" => {
|
}
|
||||||
ui.on_set_scroll_region(try_uint!(args[0]),
|
"eol_clear" => ui.on_eol_clear(),
|
||||||
try_uint!(args[1]),
|
"set_scroll_region" => {
|
||||||
try_uint!(args[2]),
|
ui.on_set_scroll_region(try_uint!(args[0]),
|
||||||
try_uint!(args[3]));
|
try_uint!(args[1]),
|
||||||
RepaintMode::Nothing
|
try_uint!(args[2]),
|
||||||
}
|
try_uint!(args[3]));
|
||||||
"scroll" => ui.on_scroll(try_int!(args[0])),
|
RepaintMode::Nothing
|
||||||
"update_bg" => ui.on_update_bg(try_int!(args[0])),
|
}
|
||||||
"update_fg" => ui.on_update_fg(try_int!(args[0])),
|
"scroll" => ui.on_scroll(try_int!(args[0])),
|
||||||
"update_sp" => ui.on_update_sp(try_int!(args[0])),
|
"update_bg" => ui.on_update_bg(try_int!(args[0])),
|
||||||
"mode_change" => ui.on_mode_change(try_str!(args[0])),
|
"update_fg" => ui.on_update_fg(try_int!(args[0])),
|
||||||
"mouse_on" => ui.on_mouse(true),
|
"update_sp" => ui.on_update_sp(try_int!(args[0])),
|
||||||
"mouse_off" => ui.on_mouse(false),
|
"mode_change" => ui.on_mode_change(try_str!(args[0])),
|
||||||
"busy_start" => ui.on_busy(true),
|
"mouse_on" => ui.on_mouse(true),
|
||||||
"busy_stop" => ui.on_busy(false),
|
"mouse_off" => ui.on_mouse(false),
|
||||||
_ => {
|
"busy_start" => ui.on_busy(true),
|
||||||
println!("Event {}({:?})", method, args);
|
"busy_stop" => ui.on_busy(false),
|
||||||
RepaintMode::Nothing
|
_ => {
|
||||||
}
|
println!("Event {}({:?})", method, args);
|
||||||
})
|
RepaintMode::Nothing
|
||||||
}
|
}
|
||||||
|
})
|
||||||
fn safe_call<F>(cb: F)
|
|
||||||
where F: Fn(&mut Shell) -> result::Result<(), String> + 'static + Send
|
|
||||||
{
|
|
||||||
glib::idle_add(move || {
|
|
||||||
SHELL!(shell = {
|
|
||||||
if let Err(msg) = cb(&mut shell) {
|
|
||||||
println!("Error call function: {}", msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
glib::Continue(false)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ErrorReport {
|
pub trait ErrorReport {
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
#[cfg(unix)]
|
use std::rc::{Rc, Weak};
|
||||||
use ui::{SET, SH};
|
use std::cell::RefCell;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use nvim::RepaintMode;
|
use nvim::RepaintMode;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
use nvim::RedrawEvents;
|
|
||||||
|
|
||||||
use shell::Shell;
|
use shell::Shell;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use gio;
|
use gio;
|
||||||
@ -19,37 +16,27 @@ pub enum FontSource {
|
|||||||
Default,
|
Default,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct State {
|
||||||
pub struct Settings {
|
|
||||||
font_source: FontSource,
|
font_source: FontSource,
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
gnome_interface_settings: gio::Settings,
|
gnome_interface_settings: gio::Settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl State {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn new() -> Settings {
|
pub fn new() -> State {
|
||||||
Settings {
|
State {
|
||||||
font_source: FontSource::Default,
|
font_source: FontSource::Default,
|
||||||
gnome_interface_settings: gio::Settings::new("org.gnome.desktop.interface"),
|
gnome_interface_settings: gio::Settings::new("org.gnome.desktop.interface"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn new() -> Settings {
|
pub fn new() -> State {
|
||||||
Settings { font_source: FontSource::Default }
|
State { font_source: FontSource::Default }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn init(&mut self, shell: &mut Shell) {
|
|
||||||
self.gnome_interface_settings.connect_changed(|_, _| monospace_font_changed());
|
|
||||||
self.update_font(shell);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub fn init(&mut self, _: &mut Shell) {}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn update_font(&mut self, shell: &mut Shell) {
|
fn update_font(&mut self, shell: &mut Shell) {
|
||||||
// rpc is priority for font
|
// rpc is priority for font
|
||||||
@ -64,22 +51,49 @@ impl Settings {
|
|||||||
self.font_source = FontSource::Gnome;
|
self.font_source = FontSource::Gnome;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Settings {
|
||||||
|
shell: Option<Weak<RefCell<Shell>>>,
|
||||||
|
state: Rc<RefCell<State>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings {
|
||||||
|
pub fn new() -> Settings {
|
||||||
|
Settings {
|
||||||
|
shell: None,
|
||||||
|
state: Rc::new(RefCell::new(State::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_shell(&mut self, shell: Weak<RefCell<Shell>>) {
|
||||||
|
self.shell = Some(shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
let shell = Weak::upgrade(self.shell.as_ref().unwrap()).unwrap();
|
||||||
|
let state = self.state.clone();
|
||||||
|
self.state.borrow_mut().update_font(&mut *shell.borrow_mut());
|
||||||
|
self.state
|
||||||
|
.borrow()
|
||||||
|
.gnome_interface_settings
|
||||||
|
.connect_changed(move |_, _| monospace_font_changed(&mut *shell.borrow_mut(), &mut *state.borrow_mut()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub fn init(&mut self) {}
|
||||||
|
|
||||||
pub fn set_font_source(&mut self, src: FontSource) {
|
pub fn set_font_source(&mut self, src: FontSource) {
|
||||||
self.font_source = src;
|
self.state.borrow_mut().font_source = src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn monospace_font_changed() {
|
fn monospace_font_changed(mut shell: &mut Shell, state: &mut State) {
|
||||||
SET.with(|set_cell| {
|
// rpc is priority for font
|
||||||
let mut set = set_cell.borrow_mut();
|
if state.font_source != FontSource::Rpc {
|
||||||
// rpc is priority for font
|
state.update_font(&mut shell);
|
||||||
if set.font_source != FontSource::Rpc {
|
shell.redraw(&RepaintMode::All);
|
||||||
SHELL!(shell = {
|
}
|
||||||
set.update_font(&mut shell);
|
|
||||||
shell.on_redraw(&RepaintMode::All);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
597
src/shell.rs
597
src/shell.rs
@ -1,11 +1,14 @@
|
|||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
use std::cell::{Ref, RefMut, RefCell};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cairo;
|
use cairo;
|
||||||
use pangocairo as pc;
|
use pangocairo as pc;
|
||||||
use pango;
|
use pango;
|
||||||
use pango::FontDescription;
|
use pango::FontDescription;
|
||||||
use gdk::{ModifierType, EventKey, EventConfigure, EventButton, EventMotion, EventType, EventScroll,
|
use gdk::{ModifierType, EventKey, EventConfigure, EventButton, EventMotion, EventType,
|
||||||
ScrollDirection, EventFocus};
|
EventScroll, ScrollDirection};
|
||||||
use gdk_sys;
|
use gdk_sys;
|
||||||
use glib;
|
use glib;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
@ -13,12 +16,14 @@ use gtk::DrawingArea;
|
|||||||
|
|
||||||
use neovim_lib::{Neovim, NeovimApi, Value};
|
use neovim_lib::{Neovim, NeovimApi, Value};
|
||||||
|
|
||||||
use settings;
|
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};
|
||||||
use nvim::{RedrawEvents, GuiApi, RepaintMode};
|
use nvim;
|
||||||
|
use nvim::{RedrawEvents, GuiApi, RepaintMode, ErrorReport};
|
||||||
use input::{convert_key, keyval_to_input_string};
|
use input::{convert_key, keyval_to_input_string};
|
||||||
use ui::{UI, SH, SET};
|
|
||||||
use cursor::Cursor;
|
use cursor::Cursor;
|
||||||
|
use ui;
|
||||||
|
use ui::UiMutex;
|
||||||
|
|
||||||
const DEFAULT_FONT_NAME: &'static str = "DejaVu Sans Mono 12";
|
const DEFAULT_FONT_NAME: &'static str = "DejaVu Sans Mono 12";
|
||||||
|
|
||||||
@ -30,78 +35,49 @@ pub enum NvimMode {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Shell {
|
pub struct State {
|
||||||
pub model: UiModel,
|
pub model: UiModel,
|
||||||
pub drawing_area: DrawingArea,
|
|
||||||
nvim: Option<Neovim>,
|
|
||||||
cur_attrs: Option<Attrs>,
|
|
||||||
bg_color: Color,
|
bg_color: Color,
|
||||||
fg_color: Color,
|
fg_color: Color,
|
||||||
sp_color: Color,
|
sp_color: Color,
|
||||||
|
cur_attrs: Option<Attrs>,
|
||||||
|
pub mode: NvimMode,
|
||||||
|
mouse_enabled: bool,
|
||||||
|
drawing_area: DrawingArea,
|
||||||
|
nvim: Option<Neovim>,
|
||||||
|
font_desc: FontDescription,
|
||||||
|
cursor: Option<Cursor>,
|
||||||
|
settings: Rc<RefCell<Settings>>,
|
||||||
|
|
||||||
line_height: Option<f64>,
|
line_height: Option<f64>,
|
||||||
char_width: Option<f64>,
|
char_width: Option<f64>,
|
||||||
request_width: bool,
|
request_width: bool,
|
||||||
pub mode: NvimMode,
|
|
||||||
mouse_enabled: bool,
|
|
||||||
mouse_pressed: bool,
|
|
||||||
font_desc: FontDescription,
|
|
||||||
resize_timer: Option<glib::SourceId>,
|
resize_timer: Option<glib::SourceId>,
|
||||||
cursor: Cursor,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shell {
|
impl State {
|
||||||
pub fn new() -> Shell {
|
pub fn new(settings: Rc<RefCell<Settings>>) -> State {
|
||||||
Shell {
|
State {
|
||||||
model: UiModel::empty(),
|
model: UiModel::new(24, 80),
|
||||||
drawing_area: DrawingArea::new(),
|
drawing_area: DrawingArea::new(),
|
||||||
nvim: None,
|
nvim: None,
|
||||||
cur_attrs: None,
|
cur_attrs: None,
|
||||||
bg_color: COLOR_BLACK,
|
bg_color: COLOR_BLACK,
|
||||||
fg_color: COLOR_WHITE,
|
fg_color: COLOR_WHITE,
|
||||||
sp_color: COLOR_RED,
|
sp_color: COLOR_RED,
|
||||||
line_height: None,
|
|
||||||
char_width: None,
|
|
||||||
request_width: true,
|
|
||||||
mode: NvimMode::Normal,
|
mode: NvimMode::Normal,
|
||||||
mouse_enabled: true,
|
mouse_enabled: true,
|
||||||
mouse_pressed: false,
|
|
||||||
font_desc: FontDescription::from_string(DEFAULT_FONT_NAME),
|
font_desc: FontDescription::from_string(DEFAULT_FONT_NAME),
|
||||||
|
cursor: None,
|
||||||
|
settings: settings,
|
||||||
|
|
||||||
|
line_height: None,
|
||||||
|
char_width: None,
|
||||||
resize_timer: None,
|
resize_timer: None,
|
||||||
cursor: Cursor::new(),
|
request_width: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&mut self) {
|
|
||||||
self.drawing_area.set_size_request(500, 300);
|
|
||||||
self.drawing_area.set_hexpand(true);
|
|
||||||
self.drawing_area.set_vexpand(true);
|
|
||||||
self.drawing_area.set_can_focus(true);
|
|
||||||
|
|
||||||
self.drawing_area
|
|
||||||
.set_events((gdk_sys::GDK_BUTTON_RELEASE_MASK | gdk_sys::GDK_BUTTON_PRESS_MASK |
|
|
||||||
gdk_sys::GDK_BUTTON_MOTION_MASK |
|
|
||||||
gdk_sys::GDK_SCROLL_MASK)
|
|
||||||
.bits() as i32);
|
|
||||||
self.drawing_area.connect_button_press_event(gtk_button_press);
|
|
||||||
self.drawing_area.connect_button_release_event(gtk_button_release);
|
|
||||||
self.drawing_area.connect_motion_notify_event(gtk_motion_notify);
|
|
||||||
self.drawing_area.connect_draw(gtk_draw);
|
|
||||||
self.drawing_area.connect_key_press_event(gtk_key_press);
|
|
||||||
self.drawing_area.connect_scroll_event(gtk_scroll_event);
|
|
||||||
self.drawing_area.connect_focus_in_event(gtk_focus_in);
|
|
||||||
self.drawing_area.connect_focus_out_event(gtk_focus_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_configure_event(&mut self) {
|
|
||||||
self.drawing_area.connect_configure_event(gtk_configure_event);
|
|
||||||
|
|
||||||
self.cursor.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_nvim(&mut self, nvim: Neovim) {
|
|
||||||
self.nvim = Some(nvim);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nvim(&mut self) -> &mut Neovim {
|
pub fn nvim(&mut self) -> &mut Neovim {
|
||||||
self.nvim.as_mut().unwrap()
|
self.nvim.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
@ -110,17 +86,7 @@ impl Shell {
|
|||||||
self.font_desc.clone()
|
self.font_desc.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_width(&mut self) {
|
fn colors<'a>(&'a self, cell: &'a Cell) -> (&'a Color, &'a Color) {
|
||||||
self.request_width = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_font_desc(&mut self, desc: &str) {
|
|
||||||
self.font_desc = FontDescription::from_string(desc);
|
|
||||||
self.line_height = None;
|
|
||||||
self.char_width = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn colors<'a>(&'a self, cell: &'a Cell) -> (&'a Color, &'a Color) {
|
|
||||||
let bg = if let Some(ref bg) = cell.attrs.background {
|
let bg = if let Some(ref bg) = cell.attrs.background {
|
||||||
bg
|
bg
|
||||||
} else {
|
} else {
|
||||||
@ -138,142 +104,323 @@ impl Shell {
|
|||||||
(bg, fg)
|
(bg, fg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_font_desc(&mut self, desc: &str) {
|
||||||
|
self.font_desc = FontDescription::from_string(desc);
|
||||||
|
self.line_height = None;
|
||||||
|
self.char_width = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_width(&mut self) {
|
||||||
|
self.request_width = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_focus_in(_: &DrawingArea, _: &EventFocus) -> Inhibit {
|
pub struct UiState {
|
||||||
SHELL!(shell = {
|
mouse_pressed: bool,
|
||||||
shell.cursor.enter_focus();
|
}
|
||||||
let point = shell.model.cur_point();
|
|
||||||
shell.on_redraw(&RepaintMode::Area(point));
|
impl UiState {
|
||||||
});
|
pub fn new() -> UiState {
|
||||||
|
UiState { mouse_pressed: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Shell {
|
||||||
|
state: Arc<UiMutex<State>>,
|
||||||
|
ui_state: Rc<RefCell<UiState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shell {
|
||||||
|
pub fn new(settings: Rc<RefCell<Settings>>) -> Shell {
|
||||||
|
let shell = Shell {
|
||||||
|
state: Arc::new(UiMutex::new(State::new(settings))),
|
||||||
|
ui_state: Rc::new(RefCell::new(UiState::new())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let shell_ref = Arc::downgrade(&shell.state);
|
||||||
|
shell.state.borrow_mut().cursor = Some(Cursor::new(shell_ref));
|
||||||
|
|
||||||
|
shell
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self, parent: Arc<UiMutex<ui::Components>>) {
|
||||||
|
let state = self.state.borrow_mut();
|
||||||
|
state.drawing_area.set_size_request(500, 300);
|
||||||
|
state.drawing_area.set_hexpand(true);
|
||||||
|
state.drawing_area.set_vexpand(true);
|
||||||
|
state.drawing_area.set_can_focus(true);
|
||||||
|
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.set_events((gdk_sys::GDK_BUTTON_RELEASE_MASK | gdk_sys::GDK_BUTTON_PRESS_MASK |
|
||||||
|
gdk_sys::GDK_BUTTON_MOTION_MASK |
|
||||||
|
gdk_sys::GDK_SCROLL_MASK)
|
||||||
|
.bits() as i32);
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
let ref_ui_state = self.ui_state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_button_press_event(move |_, ev| {
|
||||||
|
gtk_button_press(&mut *ref_state.borrow_mut(),
|
||||||
|
&mut *ref_ui_state.borrow_mut(),
|
||||||
|
ev)
|
||||||
|
});
|
||||||
|
|
||||||
|
let ref_ui_state = self.ui_state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_button_release_event(move |_, _| {
|
||||||
|
gtk_button_release(&mut *ref_ui_state.borrow_mut())
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
let ref_ui_state = self.ui_state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_motion_notify_event(move |_, ev| {
|
||||||
|
gtk_motion_notify(&mut *ref_state.borrow_mut(),
|
||||||
|
&mut *ref_ui_state.borrow_mut(),
|
||||||
|
ev)
|
||||||
|
});
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_draw(move |_, ctx| {
|
||||||
|
gtk_draw(&*parent.borrow(), &mut *ref_state.borrow_mut(), ctx)
|
||||||
|
});
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_key_press_event(move |_, ev| gtk_key_press(&mut *ref_state.borrow_mut(), ev));
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
let ref_ui_state = self.ui_state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_scroll_event(move |_, ev| {
|
||||||
|
gtk_scroll_event(&mut *ref_state.borrow_mut(),
|
||||||
|
&mut *ref_ui_state.borrow_mut(),
|
||||||
|
ev)
|
||||||
|
});
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_focus_in_event(move |_, _| gtk_focus_in(&mut *ref_state.borrow_mut()));
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn redraw(&self, mode: &RepaintMode) {
|
||||||
|
self.state.borrow_mut().on_redraw(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_font_desc(&self, font_name: &str) {
|
||||||
|
self.state.borrow_mut().set_font_desc(font_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_configure_event(&mut self) {
|
||||||
|
let mut state = self.state.borrow_mut();
|
||||||
|
|
||||||
|
let ref_state = self.state.clone();
|
||||||
|
state
|
||||||
|
.drawing_area
|
||||||
|
.connect_configure_event(move |_, ev| gtk_configure_event(&ref_state, ev));
|
||||||
|
|
||||||
|
state.cursor.as_mut().unwrap().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_nvim(&mut self, nvim_bin_path: Option<&String>) {
|
||||||
|
let nvim =
|
||||||
|
nvim::initialize(self.state.clone(), nvim_bin_path).expect("Can't start nvim instance");
|
||||||
|
let mut state = self.state.borrow_mut();
|
||||||
|
state.nvim = Some(nvim);
|
||||||
|
state.request_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_file(&self, path: &str) {
|
||||||
|
let mut nvim = self.nvim();
|
||||||
|
nvim.command(&format!("e {}", path))
|
||||||
|
.report_err(&mut *nvim);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn detach_ui(&mut self) {
|
||||||
|
self.nvim().ui_detach().expect("Error in ui_detach");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn edit_paste(&self) {
|
||||||
|
let mut state = self.state.borrow_mut();
|
||||||
|
let paste_command = if state.mode == NvimMode::Normal {
|
||||||
|
"\"*p"
|
||||||
|
} else {
|
||||||
|
"<Esc>\"*pa"
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut nvim = state.nvim();
|
||||||
|
nvim.input(paste_command).report_err(nvim);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn edit_save_all(&self) {
|
||||||
|
let mut nvim = &mut *self.nvim();
|
||||||
|
nvim.command(":wa").report_err(nvim);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nvim(&self) -> RefMut<Neovim> {
|
||||||
|
let state = self.state.borrow_mut();
|
||||||
|
RefMut::map(state, |s| s.nvim())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gtk_focus_in(state: &mut State) -> Inhibit {
|
||||||
|
state.cursor.as_mut().unwrap().enter_focus();
|
||||||
|
let point = state.model.cur_point();
|
||||||
|
state.on_redraw(&RepaintMode::Area(point));
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_focus_out(_: &DrawingArea, _: &EventFocus) -> Inhibit {
|
fn gtk_focus_out(state: &mut State) -> Inhibit {
|
||||||
SHELL!(shell = {
|
state.cursor.as_mut().unwrap().leave_focus();
|
||||||
shell.cursor.leave_focus();
|
let point = state.model.cur_point();
|
||||||
let point = shell.model.cur_point();
|
state.on_redraw(&RepaintMode::Area(point));
|
||||||
shell.on_redraw(&RepaintMode::Area(point));
|
|
||||||
});
|
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_scroll_event(_: &DrawingArea, ev: &EventScroll) -> Inhibit {
|
fn gtk_scroll_event(state: &mut State, ui_state: &mut UiState, ev: &EventScroll) -> Inhibit {
|
||||||
SHELL!(shell = {
|
if state.mouse_enabled {
|
||||||
if !shell.mouse_enabled {
|
return Inhibit(false);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
match ev.as_ref().direction {
|
||||||
|
ScrollDirection::Right => {
|
||||||
|
mouse_input(state,
|
||||||
|
ui_state,
|
||||||
|
"ScrollWheelRight",
|
||||||
|
ev.get_state(),
|
||||||
|
ev.get_position())
|
||||||
}
|
}
|
||||||
|
ScrollDirection::Left => {
|
||||||
match ev.as_ref().direction {
|
mouse_input(state,
|
||||||
ScrollDirection::Right => {
|
ui_state,
|
||||||
mouse_input(&mut shell,
|
"ScrollWheelLeft",
|
||||||
"ScrollWheelRight",
|
ev.get_state(),
|
||||||
ev.get_state(),
|
ev.get_position())
|
||||||
ev.get_position())
|
|
||||||
}
|
|
||||||
ScrollDirection::Left => {
|
|
||||||
mouse_input(&mut shell,
|
|
||||||
"ScrollWheelLeft",
|
|
||||||
ev.get_state(),
|
|
||||||
ev.get_position())
|
|
||||||
}
|
|
||||||
ScrollDirection::Up => {
|
|
||||||
mouse_input(&mut shell,
|
|
||||||
"ScrollWheelUp",
|
|
||||||
ev.get_state(),
|
|
||||||
ev.get_position())
|
|
||||||
}
|
|
||||||
ScrollDirection::Down => {
|
|
||||||
mouse_input(&mut shell,
|
|
||||||
"ScrollWheelDown",
|
|
||||||
ev.get_state(),
|
|
||||||
ev.get_position())
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
});
|
ScrollDirection::Up => {
|
||||||
|
mouse_input(state,
|
||||||
|
ui_state,
|
||||||
|
"ScrollWheelUp",
|
||||||
|
ev.get_state(),
|
||||||
|
ev.get_position())
|
||||||
|
}
|
||||||
|
ScrollDirection::Down => {
|
||||||
|
mouse_input(state,
|
||||||
|
ui_state,
|
||||||
|
"ScrollWheelDown",
|
||||||
|
ev.get_state(),
|
||||||
|
ev.get_position())
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_button_press(_: &DrawingArea, ev: &EventButton) -> Inhibit {
|
fn gtk_button_press(shell: &mut State, ui_state: &mut UiState, ev: &EventButton) -> Inhibit {
|
||||||
if ev.get_event_type() != EventType::ButtonPress {
|
if ev.get_event_type() != EventType::ButtonPress {
|
||||||
return Inhibit(false);
|
return Inhibit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL!(shell = {
|
if shell.mouse_enabled {
|
||||||
if !shell.mouse_enabled {
|
mouse_input(shell,
|
||||||
return;
|
ui_state,
|
||||||
}
|
"LeftMouse",
|
||||||
|
ev.get_state(),
|
||||||
mouse_input(&mut shell, "LeftMouse", ev.get_state(), ev.get_position());
|
ev.get_position());
|
||||||
});
|
}
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_input(shell: &mut Shell, input: &str, state: ModifierType, position: (f64, f64)) {
|
fn mouse_input(shell: &mut State,
|
||||||
|
ui_state: &mut UiState,
|
||||||
|
input: &str,
|
||||||
|
state: ModifierType,
|
||||||
|
position: (f64, f64)) {
|
||||||
if let Some(line_height) = shell.line_height {
|
if let Some(line_height) = shell.line_height {
|
||||||
if let Some(char_width) = shell.char_width {
|
if let Some(char_width) = shell.char_width {
|
||||||
shell.mouse_pressed = true;
|
ui_state.mouse_pressed = true;
|
||||||
|
|
||||||
let nvim = shell.nvim();
|
let nvim = shell.nvim();
|
||||||
let (x, y) = position;
|
let (x, y) = position;
|
||||||
let col = (x / char_width).trunc() as u64;
|
let col = (x / char_width).trunc() as u64;
|
||||||
let row = (y / line_height).trunc() as u64;
|
let row = (y / line_height).trunc() as u64;
|
||||||
let input_str = format!("{}<{},{}>", keyval_to_input_string(input, state), col, row);
|
let input_str = format!("{}<{},{}>", keyval_to_input_string(input, state), col, row);
|
||||||
nvim.input(&input_str).expect("Can't send mouse input event");
|
nvim.input(&input_str)
|
||||||
|
.expect("Can't send mouse input event");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_button_release(_: &DrawingArea, _: &EventButton) -> Inhibit {
|
fn gtk_button_release(ui_state: &mut UiState) -> Inhibit {
|
||||||
SHELL!(shell = {
|
ui_state.mouse_pressed = false;
|
||||||
shell.mouse_pressed = false;
|
|
||||||
});
|
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_motion_notify(_: &DrawingArea, ev: &EventMotion) -> Inhibit {
|
fn gtk_motion_notify(shell: &mut State, ui_state: &mut UiState, ev: &EventMotion) -> Inhibit {
|
||||||
SHELL!(shell = {
|
if shell.mouse_enabled && ui_state.mouse_pressed {
|
||||||
if !shell.mouse_enabled || !shell.mouse_pressed {
|
mouse_input(shell,
|
||||||
return;
|
ui_state,
|
||||||
}
|
"LeftDrag",
|
||||||
|
ev.get_state(),
|
||||||
mouse_input(&mut shell, "LeftDrag", ev.get_state(), ev.get_position());
|
ev.get_position());
|
||||||
});
|
}
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_key_press(_: &DrawingArea, ev: &EventKey) -> Inhibit {
|
fn gtk_key_press(shell: &mut State, ev: &EventKey) -> Inhibit {
|
||||||
if let Some(input) = convert_key(ev) {
|
if let Some(input) = convert_key(ev) {
|
||||||
SHELL!(shell = {
|
debug!("nvim_input -> {}", input);
|
||||||
debug!("nvim_input -> {}", input);
|
shell
|
||||||
shell.nvim().input(&input).expect("Error run input command to nvim");
|
.nvim()
|
||||||
shell.cursor.reset_state();
|
.input(&input)
|
||||||
});
|
.expect("Error run input command to nvim");
|
||||||
|
shell.cursor.as_mut().unwrap().reset_state();
|
||||||
Inhibit(true)
|
Inhibit(true)
|
||||||
} else {
|
} else {
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_draw(_: &DrawingArea, ctx: &cairo::Context) -> Inhibit {
|
fn gtk_draw(parent: &ui::Components, state: &mut State, ctx: &cairo::Context) -> Inhibit {
|
||||||
SHELL!(shell = {
|
if state.line_height.is_none() {
|
||||||
if shell.line_height.is_none() {
|
let (width, height) = calc_char_bounds(state, ctx);
|
||||||
let (width, height) = calc_char_bounds(&shell, ctx);
|
state.line_height = Some(height as f64);
|
||||||
shell.line_height = Some(height as f64);
|
state.char_width = Some(width as f64);
|
||||||
shell.char_width = Some(width as f64);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
draw(&shell, ctx);
|
draw(state, ctx);
|
||||||
request_width(&mut shell);
|
request_width(parent, state);
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn draw_joined_rect(shell: &Shell,
|
fn draw_joined_rect(state: &State,
|
||||||
ctx: &cairo::Context,
|
ctx: &cairo::Context,
|
||||||
from_col_idx: usize,
|
from_col_idx: usize,
|
||||||
col_idx: usize,
|
col_idx: usize,
|
||||||
@ -283,7 +430,7 @@ fn draw_joined_rect(shell: &Shell,
|
|||||||
let current_point = ctx.get_current_point();
|
let current_point = ctx.get_current_point();
|
||||||
let rect_width = char_width * (col_idx - from_col_idx) as f64;
|
let rect_width = char_width * (col_idx - from_col_idx) as f64;
|
||||||
|
|
||||||
if &shell.bg_color != color {
|
if &state.bg_color != color {
|
||||||
ctx.set_source_rgb(color.0, color.1, color.2);
|
ctx.set_source_rgb(color.0, color.1, color.2);
|
||||||
ctx.rectangle(current_point.0, current_point.1, rect_width, line_height);
|
ctx.rectangle(current_point.0, current_point.1, rect_width, line_height);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
@ -292,29 +439,29 @@ fn draw_joined_rect(shell: &Shell,
|
|||||||
ctx.move_to(current_point.0 + rect_width, current_point.1);
|
ctx.move_to(current_point.0 + rect_width, current_point.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(shell: &Shell, ctx: &cairo::Context) {
|
fn draw(state: &State, ctx: &cairo::Context) {
|
||||||
ctx.set_source_rgb(shell.bg_color.0, shell.bg_color.1, shell.bg_color.2);
|
ctx.set_source_rgb(state.bg_color.0, state.bg_color.1, state.bg_color.2);
|
||||||
ctx.paint();
|
ctx.paint();
|
||||||
|
|
||||||
let line_height = shell.line_height.unwrap();
|
let line_height = state.line_height.unwrap();
|
||||||
let char_width = shell.char_width.unwrap();
|
let char_width = state.char_width.unwrap();
|
||||||
let clip = ctx.clip_extents();
|
let clip = ctx.clip_extents();
|
||||||
let mut model_clip =
|
let mut model_clip =
|
||||||
ModelRect::from_area(line_height, char_width, clip.0, clip.1, clip.2, clip.3);
|
ModelRect::from_area(line_height, char_width, clip.0, clip.1, clip.2, clip.3);
|
||||||
shell.model.limit_to_model(&mut model_clip);
|
state.model.limit_to_model(&mut model_clip);
|
||||||
|
|
||||||
let line_x = model_clip.left as f64 * char_width;
|
let line_x = model_clip.left as f64 * char_width;
|
||||||
let mut line_y: f64 = model_clip.top as f64 * line_height;
|
let mut line_y: f64 = model_clip.top as f64 * line_height;
|
||||||
|
|
||||||
let (row, col) = shell.model.get_cursor();
|
let (row, col) = state.model.get_cursor();
|
||||||
let mut buf = String::with_capacity(4);
|
let mut buf = String::with_capacity(4);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let layout = pc::create_layout(ctx);
|
let layout = pc::create_layout(ctx);
|
||||||
let mut desc = shell.create_pango_font();
|
let mut desc = state.create_pango_font();
|
||||||
|
|
||||||
for (line_idx, line) in shell.model.clip_model(&model_clip) {
|
for (line_idx, line) in state.model.clip_model(&model_clip) {
|
||||||
ctx.move_to(line_x, line_y);
|
ctx.move_to(line_x, line_y);
|
||||||
|
|
||||||
// first draw background
|
// first draw background
|
||||||
@ -323,13 +470,13 @@ fn draw(shell: &Shell, ctx: &cairo::Context) {
|
|||||||
let mut from_col_idx = model_clip.left;
|
let mut from_col_idx = model_clip.left;
|
||||||
let mut from_bg = None;
|
let mut from_bg = None;
|
||||||
for (col_idx, cell) in line.iter() {
|
for (col_idx, cell) in line.iter() {
|
||||||
let (bg, _) = shell.colors(cell);
|
let (bg, _) = state.colors(cell);
|
||||||
|
|
||||||
if from_bg.is_none() {
|
if from_bg.is_none() {
|
||||||
from_bg = Some(bg);
|
from_bg = Some(bg);
|
||||||
from_col_idx = col_idx;
|
from_col_idx = col_idx;
|
||||||
} else if from_bg != Some(bg) {
|
} else if from_bg != Some(bg) {
|
||||||
draw_joined_rect(shell,
|
draw_joined_rect(state,
|
||||||
ctx,
|
ctx,
|
||||||
from_col_idx,
|
from_col_idx,
|
||||||
col_idx,
|
col_idx,
|
||||||
@ -340,7 +487,7 @@ fn draw(shell: &Shell, ctx: &cairo::Context) {
|
|||||||
from_col_idx = col_idx;
|
from_col_idx = col_idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
draw_joined_rect(shell,
|
draw_joined_rect(state,
|
||||||
ctx,
|
ctx,
|
||||||
from_col_idx,
|
from_col_idx,
|
||||||
model_clip.right + 1,
|
model_clip.right + 1,
|
||||||
@ -351,19 +498,25 @@ fn draw(shell: &Shell, ctx: &cairo::Context) {
|
|||||||
ctx.move_to(line_x, line_y);
|
ctx.move_to(line_x, line_y);
|
||||||
|
|
||||||
for (col_idx, cell) in line.iter() {
|
for (col_idx, cell) in line.iter() {
|
||||||
let double_width = line.get(col_idx + 1).map(|c| c.attrs.double_width).unwrap_or(false);
|
let double_width = line.get(col_idx + 1)
|
||||||
|
.map(|c| c.attrs.double_width)
|
||||||
|
.unwrap_or(false);
|
||||||
let current_point = ctx.get_current_point();
|
let current_point = ctx.get_current_point();
|
||||||
|
|
||||||
let (bg, fg) = shell.colors(cell);
|
let (bg, fg) = state.colors(cell);
|
||||||
|
|
||||||
if row == line_idx && col == col_idx {
|
if row == line_idx && col == col_idx {
|
||||||
shell.cursor.draw(ctx,
|
state
|
||||||
shell,
|
.cursor
|
||||||
char_width,
|
.as_ref()
|
||||||
line_height,
|
.unwrap()
|
||||||
line_y,
|
.draw(ctx,
|
||||||
double_width,
|
state,
|
||||||
bg);
|
char_width,
|
||||||
|
line_height,
|
||||||
|
line_y,
|
||||||
|
double_width,
|
||||||
|
bg);
|
||||||
|
|
||||||
ctx.move_to(current_point.0, current_point.1);
|
ctx.move_to(current_point.0, current_point.1);
|
||||||
}
|
}
|
||||||
@ -400,7 +553,7 @@ fn draw(shell: &Shell, ctx: &cairo::Context) {
|
|||||||
let sp = if let Some(ref sp) = cell.attrs.special {
|
let sp = if let Some(ref sp) = cell.attrs.special {
|
||||||
sp
|
sp
|
||||||
} else {
|
} else {
|
||||||
&shell.sp_color
|
&state.sp_color
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7);
|
ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7);
|
||||||
@ -437,7 +590,7 @@ fn update_font_description(desc: &mut FontDescription, attrs: &Attrs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_char_bounds(shell: &Shell, ctx: &cairo::Context) -> (i32, i32) {
|
fn calc_char_bounds(shell: &State, ctx: &cairo::Context) -> (i32, i32) {
|
||||||
let layout = pc::create_layout(ctx);
|
let layout = pc::create_layout(ctx);
|
||||||
|
|
||||||
let desc = shell.create_pango_font();
|
let desc = shell.create_pango_font();
|
||||||
@ -447,31 +600,27 @@ fn calc_char_bounds(shell: &Shell, ctx: &cairo::Context) -> (i32, i32) {
|
|||||||
layout.get_pixel_size()
|
layout.get_pixel_size()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_width(shell: &mut Shell) {
|
fn request_width(parent: &ui::Components, state: &mut State) {
|
||||||
if !shell.request_width {
|
if !state.request_width {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if shell.resize_timer.is_some() {
|
if state.resize_timer.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
shell.request_width = false;
|
state.request_width = false;
|
||||||
|
|
||||||
let width = shell.drawing_area.get_allocated_width();
|
let width = state.drawing_area.get_allocated_width();
|
||||||
let height = shell.drawing_area.get_allocated_height();
|
let height = state.drawing_area.get_allocated_height();
|
||||||
let request_height = (shell.model.rows as f64 * shell.line_height.unwrap()) as i32;
|
let request_height = (state.model.rows as f64 * state.line_height.unwrap()) as i32;
|
||||||
let request_width = (shell.model.columns as f64 * shell.char_width.unwrap()) as i32;
|
let request_width = (state.model.columns as f64 * state.char_width.unwrap()) as i32;
|
||||||
|
|
||||||
if width != request_width || height != request_height {
|
if width != request_width || height != request_height {
|
||||||
UI.with(|ui_cell| {
|
let window = parent.window();
|
||||||
let ui = ui_cell.borrow();
|
let (win_width, win_height) = window.get_size();
|
||||||
|
let h_border = win_width - width;
|
||||||
let window = ui.window.as_ref().unwrap();
|
let v_border = win_height - height;
|
||||||
let (win_width, win_height) = window.get_size();
|
window.resize(request_width + h_border, request_height + v_border);
|
||||||
let h_border = win_width - width;
|
|
||||||
let v_border = win_height - height;
|
|
||||||
window.resize(request_width + h_border, request_height + v_border);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,39 +631,41 @@ fn split_color(indexed_color: u64) -> Color {
|
|||||||
Color(r / 255.0, g / 255.0, b / 255.0)
|
Color(r / 255.0, g / 255.0, b / 255.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtk_configure_event(_: &DrawingArea, ev: &EventConfigure) -> bool {
|
fn gtk_configure_event(state: &Arc<UiMutex<State>>, ev: &EventConfigure) -> bool {
|
||||||
SHELL!(shell = {
|
let (width, height) = ev.get_size();
|
||||||
let (width, height) = ev.get_size();
|
|
||||||
|
|
||||||
if let Some(timer) = shell.resize_timer {
|
let mut state_ref = state.borrow_mut();
|
||||||
glib::source_remove(timer);
|
|
||||||
|
if let Some(timer) = state_ref.resize_timer {
|
||||||
|
glib::source_remove(timer);
|
||||||
|
}
|
||||||
|
if let Some(line_height) = state_ref.line_height {
|
||||||
|
if let Some(char_width) = state_ref.char_width {
|
||||||
|
|
||||||
|
let state = state.clone();
|
||||||
|
state_ref.resize_timer = Some(glib::timeout_add(250, move || {
|
||||||
|
let mut state_ref = state.borrow_mut();
|
||||||
|
|
||||||
|
state_ref.resize_timer = None;
|
||||||
|
|
||||||
|
let rows = (height as f64 / line_height).trunc() as usize;
|
||||||
|
let columns = (width as f64 / char_width).trunc() as usize;
|
||||||
|
if state_ref.model.rows != rows || state_ref.model.columns != columns {
|
||||||
|
if let Err(err) = state_ref
|
||||||
|
.nvim()
|
||||||
|
.ui_try_resize(columns as u64, rows as u64) {
|
||||||
|
println!("Error trying resize nvim {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state_ref.request_width();
|
||||||
|
Continue(false)
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
if let Some(line_height) = shell.line_height {
|
}
|
||||||
if let Some(char_width) = shell.char_width {
|
|
||||||
|
|
||||||
shell.resize_timer = Some(glib::timeout_add(250, move || {
|
|
||||||
SHELL!(shell = {
|
|
||||||
shell.resize_timer = None;
|
|
||||||
|
|
||||||
let rows = (height as f64 / line_height).trunc() as usize;
|
|
||||||
let columns = (width as f64 / char_width).trunc() as usize;
|
|
||||||
if shell.model.rows != rows || shell.model.columns != columns {
|
|
||||||
if let Err(err) = shell.nvim()
|
|
||||||
.ui_try_resize(columns as u64, rows as u64) {
|
|
||||||
println!("Error trying resize nvim {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shell.request_width();
|
|
||||||
});
|
|
||||||
Continue(false)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedrawEvents for Shell {
|
impl RedrawEvents for State {
|
||||||
fn on_cursor_goto(&mut self, row: u64, col: u64) -> RepaintMode {
|
fn on_cursor_goto(&mut self, row: u64, col: u64) -> RepaintMode {
|
||||||
RepaintMode::Area(self.model.set_cursor(row as usize, col as usize))
|
RepaintMode::Area(self.model.set_cursor(row as usize, col as usize))
|
||||||
}
|
}
|
||||||
@ -643,21 +794,19 @@ impl RedrawEvents for Shell {
|
|||||||
|
|
||||||
fn on_busy(&mut self, busy: bool) -> RepaintMode {
|
fn on_busy(&mut self, busy: bool) -> RepaintMode {
|
||||||
if busy {
|
if busy {
|
||||||
self.cursor.busy_on();
|
self.cursor.as_mut().unwrap().busy_on();
|
||||||
} else {
|
} else {
|
||||||
self.cursor.busy_off();
|
self.cursor.as_mut().unwrap().busy_off();
|
||||||
}
|
}
|
||||||
RepaintMode::Area(self.model.cur_point())
|
RepaintMode::Area(self.model.cur_point())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuiApi for Shell {
|
impl GuiApi for State {
|
||||||
fn set_font(&mut self, font_desc: &str) {
|
fn set_font(&mut self, font_desc: &str) {
|
||||||
self.set_font_desc(font_desc);
|
self.set_font_desc(font_desc);
|
||||||
|
|
||||||
SET.with(|settings| {
|
let mut settings = self.settings.borrow_mut();
|
||||||
let mut settings = settings.borrow_mut();
|
settings.set_font_source(FontSource::Rpc);
|
||||||
settings.set_font_source(settings::FontSource::Rpc);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
101
src/shell_dlg.rs
101
src/shell_dlg.rs
@ -1,14 +1,18 @@
|
|||||||
use ui::{SH, Ui};
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use ui::{Components, UiMutex};
|
||||||
|
use shell::Shell;
|
||||||
use neovim_lib::{NeovimApi, CallError, Value};
|
use neovim_lib::{NeovimApi, CallError, Value};
|
||||||
use gtk;
|
use gtk;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{MessageDialog, MessageType, ButtonsType};
|
use gtk::{MessageDialog, MessageType, ButtonsType};
|
||||||
|
|
||||||
pub fn can_close_window(ui: &Ui) -> bool {
|
pub fn can_close_window(comps: &UiMutex<Components>, shell: &RefCell<Shell>) -> bool {
|
||||||
match get_changed_buffers() {
|
let shell = shell.borrow();
|
||||||
|
match get_changed_buffers(&*shell) {
|
||||||
Ok(vec) => {
|
Ok(vec) => {
|
||||||
if !vec.is_empty() {
|
if !vec.is_empty() {
|
||||||
show_not_saved_dlg(ui, &vec)
|
show_not_saved_dlg(comps, &*shell, &vec)
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -20,14 +24,18 @@ pub fn can_close_window(ui: &Ui) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_not_saved_dlg(ui: &Ui, changed_bufs: &Vec<String>) -> bool {
|
fn show_not_saved_dlg(comps: &UiMutex<Components>,
|
||||||
let mut changed_files = changed_bufs.iter()
|
shell: &Shell,
|
||||||
|
changed_bufs: &Vec<String>)
|
||||||
|
-> bool {
|
||||||
|
let mut changed_files = changed_bufs
|
||||||
|
.iter()
|
||||||
.map(|n| if n.is_empty() { "<No name>" } else { n })
|
.map(|n| if n.is_empty() { "<No name>" } else { n })
|
||||||
.fold(String::new(), |acc, v| acc + v + "\n");
|
.fold(String::new(), |acc, v| acc + v + "\n");
|
||||||
changed_files.pop();
|
changed_files.pop();
|
||||||
|
|
||||||
let flags = gtk::DIALOG_MODAL | gtk::DIALOG_DESTROY_WITH_PARENT;
|
let flags = gtk::DIALOG_MODAL | gtk::DIALOG_DESTROY_WITH_PARENT;
|
||||||
let dlg = MessageDialog::new(ui.window.as_ref(),
|
let dlg = MessageDialog::new(Some(comps.borrow().window()),
|
||||||
flags,
|
flags,
|
||||||
MessageType::Question,
|
MessageType::Question,
|
||||||
ButtonsType::None,
|
ButtonsType::None,
|
||||||
@ -37,21 +45,21 @@ fn show_not_saved_dlg(ui: &Ui, changed_bufs: &Vec<String>) -> bool {
|
|||||||
const CLOSE_WITHOUT_SAVE: i32 = 1;
|
const CLOSE_WITHOUT_SAVE: i32 = 1;
|
||||||
const CANCEL_ID: i32 = 2;
|
const CANCEL_ID: i32 = 2;
|
||||||
|
|
||||||
dlg.add_buttons(&[("_Yes", SAVE_ID), ("_No", CLOSE_WITHOUT_SAVE), ("_Cancel", CANCEL_ID)]);
|
dlg.add_buttons(&[("_Yes", SAVE_ID),
|
||||||
|
("_No", CLOSE_WITHOUT_SAVE),
|
||||||
|
("_Cancel", CANCEL_ID)]);
|
||||||
|
|
||||||
let res = match dlg.run() {
|
let res = match dlg.run() {
|
||||||
SAVE_ID => {
|
SAVE_ID => {
|
||||||
SHELL!(shell = {
|
let mut nvim = shell.nvim();
|
||||||
let mut nvim = shell.nvim();
|
match nvim.command("wa") {
|
||||||
match nvim.command("wa") {
|
Err(ref err) => {
|
||||||
Err(ref err) => {
|
println!("Error: {}", err);
|
||||||
println!("Error: {}", err);
|
false
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => true
|
|
||||||
}
|
}
|
||||||
})
|
_ => true,
|
||||||
},
|
}
|
||||||
|
}
|
||||||
CLOSE_WITHOUT_SAVE => true,
|
CLOSE_WITHOUT_SAVE => true,
|
||||||
CANCEL_ID => false,
|
CANCEL_ID => false,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -62,34 +70,33 @@ fn show_not_saved_dlg(ui: &Ui, changed_bufs: &Vec<String>) -> bool {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_changed_buffers() -> Result<Vec<String>, CallError> {
|
fn get_changed_buffers(shell: &Shell) -> Result<Vec<String>, CallError> {
|
||||||
SHELL!(shell = {
|
let mut nvim = shell.nvim();
|
||||||
let mut nvim = shell.nvim();
|
let buffers = nvim.get_buffers().unwrap();
|
||||||
let buffers = nvim.get_buffers().unwrap();
|
|
||||||
|
|
||||||
Ok(buffers.iter()
|
Ok(buffers
|
||||||
.map(|buf| {
|
.iter()
|
||||||
(match buf.get_option(&mut nvim, "modified") {
|
.map(|buf| {
|
||||||
Ok(Value::Boolean(val)) => val,
|
(match buf.get_option(&mut nvim, "modified") {
|
||||||
Ok(_) => {
|
Ok(Value::Boolean(val)) => val,
|
||||||
println!("Value must be boolean");
|
Ok(_) => {
|
||||||
false
|
println!("Value must be boolean");
|
||||||
}
|
false
|
||||||
Err(ref err) => {
|
}
|
||||||
println!("Something going wrong while getting buffer option: {}", err);
|
Err(ref err) => {
|
||||||
false
|
println!("Something going wrong while getting buffer option: {}", err);
|
||||||
}
|
false
|
||||||
},
|
}
|
||||||
match buf.get_name(&mut nvim) {
|
},
|
||||||
Ok(name) => name,
|
match buf.get_name(&mut nvim) {
|
||||||
Err(ref err) => {
|
Ok(name) => name,
|
||||||
println!("Something going wrong while getting buffer name: {}", err);
|
Err(ref err) => {
|
||||||
"<Error>".to_owned()
|
println!("Something going wrong while getting buffer name: {}", err);
|
||||||
}
|
"<Error>".to_owned()
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
.filter(|e| e.0)
|
})
|
||||||
.map(|e| e.1)
|
.filter(|e| e.0)
|
||||||
.collect())
|
.map(|e| e.1)
|
||||||
})
|
.collect())
|
||||||
}
|
}
|
||||||
|
263
src/ui.rs
263
src/ui.rs
@ -1,61 +1,36 @@
|
|||||||
use std::cell::{RefCell, Ref, RefMut};
|
use std::cell::{RefCell, Ref, RefMut};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use gtk;
|
use gtk;
|
||||||
use gtk_sys;
|
use gtk_sys;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{ApplicationWindow, HeaderBar, ToolButton, Image, AboutDialog};
|
use gtk::{ApplicationWindow, HeaderBar, ToolButton, Image, AboutDialog};
|
||||||
use gdk::Event;
|
|
||||||
use gio::{Menu, MenuItem, SimpleAction};
|
use gio::{Menu, MenuItem, SimpleAction};
|
||||||
use glib::variant::Variant;
|
use glib;
|
||||||
|
|
||||||
use neovim_lib::NeovimApi;
|
use settings::Settings;
|
||||||
|
use shell::Shell;
|
||||||
use settings;
|
|
||||||
use shell::{Shell, NvimMode};
|
|
||||||
use shell_dlg;
|
use shell_dlg;
|
||||||
use nvim::ErrorReport;
|
|
||||||
|
|
||||||
macro_rules! ui_thread_var {
|
|
||||||
($id:ident, $ty:ty, $expr:expr) => (thread_local!(pub static $id: RefCell<$ty> = {
|
|
||||||
assert_ui_thread();
|
|
||||||
RefCell::new($expr)
|
|
||||||
});)
|
|
||||||
}
|
|
||||||
|
|
||||||
ui_thread_var!(UI, Ui, Ui::new());
|
|
||||||
ui_thread_var!(SH, Shell, Shell::new());
|
|
||||||
ui_thread_var!(SET, settings::Settings, settings::Settings::new());
|
|
||||||
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! SHELL {
|
|
||||||
(&$id:ident = $expr:expr) => (
|
|
||||||
SH.with(|shell_cell| {
|
|
||||||
let $id = &shell_cell.borrow();
|
|
||||||
$expr
|
|
||||||
});
|
|
||||||
);
|
|
||||||
($id:ident = $expr:expr) => (
|
|
||||||
SH.with(|shell_cell| {
|
|
||||||
let mut $id = &mut shell_cell.borrow_mut();
|
|
||||||
$expr
|
|
||||||
});
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
pub initialized: bool,
|
initialized: bool,
|
||||||
pub window: Option<ApplicationWindow>,
|
comps: Arc<UiMutex<Components>>,
|
||||||
|
settings: Rc<RefCell<Settings>>,
|
||||||
|
shell: Rc<RefCell<Shell>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Components {
|
||||||
|
window: Option<ApplicationWindow>,
|
||||||
header_bar: HeaderBar,
|
header_bar: HeaderBar,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
impl Components {
|
||||||
pub fn new() -> Ui {
|
fn new() -> Components {
|
||||||
Ui {
|
Components {
|
||||||
window: None,
|
window: None,
|
||||||
header_bar: HeaderBar::new(),
|
header_bar: HeaderBar::new(),
|
||||||
initialized: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,14 +38,29 @@ impl Ui {
|
|||||||
self.window.as_ref().unwrap().destroy();
|
self.window.as_ref().unwrap().destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(&mut self) {
|
pub fn window(&self) -> &ApplicationWindow {
|
||||||
self.close_window();
|
self.window.as_ref().unwrap()
|
||||||
SHELL!(shell = {
|
}
|
||||||
shell.nvim().ui_detach().expect("Error in ui_detach");
|
}
|
||||||
});
|
|
||||||
|
impl Ui {
|
||||||
|
pub fn new() -> Ui {
|
||||||
|
let settings = Rc::new(RefCell::new(Settings::new()));
|
||||||
|
let shell = Rc::new(RefCell::new(Shell::new(settings.clone())));
|
||||||
|
settings.borrow_mut().set_shell(Rc::downgrade(&shell));
|
||||||
|
|
||||||
|
Ui {
|
||||||
|
initialized: false,
|
||||||
|
comps: Arc::new(UiMutex::new(Components::new())),
|
||||||
|
shell: shell.clone(),
|
||||||
|
settings: settings,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&mut self, app: >k::Application) {
|
pub fn init(&mut self,
|
||||||
|
app: >k::Application,
|
||||||
|
nvim_bin_path: Option<&String>,
|
||||||
|
open_path: Option<&String>) {
|
||||||
if self.initialized {
|
if self.initialized {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -78,39 +68,66 @@ impl Ui {
|
|||||||
|
|
||||||
self.create_main_menu(app);
|
self.create_main_menu(app);
|
||||||
|
|
||||||
SHELL!(shell = {
|
let mut settings = self.settings.borrow_mut();
|
||||||
SET.with(|settings| {
|
settings.init();
|
||||||
let mut settings = settings.borrow_mut();
|
|
||||||
settings.init(&mut shell);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.header_bar.set_show_close_button(true);
|
let mut comps = self.comps.borrow_mut();
|
||||||
|
|
||||||
let save_image = Image::new_from_icon_name("document-save",
|
comps.header_bar.set_show_close_button(true);
|
||||||
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32);
|
|
||||||
let save_btn = ToolButton::new(Some(&save_image), None);
|
|
||||||
save_btn.connect_clicked(|_| edit_save_all());
|
|
||||||
self.header_bar.pack_start(&save_btn);
|
|
||||||
|
|
||||||
let paste_image = Image::new_from_icon_name("edit-paste",
|
let save_image = Image::new_from_icon_name("document-save",
|
||||||
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32);
|
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32);
|
||||||
let paste_btn = ToolButton::new(Some(&paste_image), None);
|
let save_btn = ToolButton::new(Some(&save_image), None);
|
||||||
paste_btn.connect_clicked(|_| edit_paste());
|
|
||||||
self.header_bar.pack_start(&paste_btn);
|
|
||||||
|
|
||||||
shell.init();
|
let shell = self.shell.clone();
|
||||||
|
save_btn.connect_clicked(move |_| { shell.borrow_mut().edit_save_all(); });
|
||||||
|
comps.header_bar.pack_start(&save_btn);
|
||||||
|
|
||||||
self.window = Some(ApplicationWindow::new(app));
|
let paste_image = Image::new_from_icon_name("edit-paste",
|
||||||
let window = self.window.as_ref().unwrap();
|
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32);
|
||||||
|
let paste_btn = ToolButton::new(Some(&paste_image), None);
|
||||||
|
let shell = self.shell.clone();
|
||||||
|
paste_btn.connect_clicked(move |_| { shell.borrow_mut().edit_paste(); });
|
||||||
|
comps.header_bar.pack_start(&paste_btn);
|
||||||
|
|
||||||
window.set_titlebar(Some(&self.header_bar));
|
self.shell.borrow_mut().init(self.comps.clone());
|
||||||
window.add(&shell.drawing_area);
|
|
||||||
window.show_all();
|
|
||||||
window.connect_delete_event(gtk_delete);
|
|
||||||
window.set_title("Neovim-gtk");
|
|
||||||
|
|
||||||
shell.add_configure_event();
|
comps.window = Some(ApplicationWindow::new(app));
|
||||||
});
|
let window = comps.window.as_ref().unwrap();
|
||||||
|
|
||||||
|
window.set_titlebar(Some(&comps.header_bar));
|
||||||
|
|
||||||
|
let mut shell = self.shell.borrow_mut();
|
||||||
|
window.add(&*shell.drawing_area());
|
||||||
|
|
||||||
|
window.show_all();
|
||||||
|
window.set_title("Neovim-gtk");
|
||||||
|
|
||||||
|
let comps_ref = self.comps.clone();
|
||||||
|
let shell_ref = self.shell.clone();
|
||||||
|
window.connect_delete_event(move |_, _| gtk_delete(&*comps_ref, &*shell_ref));
|
||||||
|
|
||||||
|
shell.add_configure_event();
|
||||||
|
shell.init_nvim(nvim_bin_path);
|
||||||
|
|
||||||
|
if open_path.is_some() {
|
||||||
|
shell.open_file(open_path.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.guard_dispatch_thread(&mut shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn guard_dispatch_thread(&self, shell: &mut Shell) {
|
||||||
|
let guard = shell.nvim().session.take_dispatch_guard();
|
||||||
|
|
||||||
|
let comps = self.comps.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
guard.join().expect("Can't join dispatch thread");
|
||||||
|
glib::idle_add(move || {
|
||||||
|
comps.borrow().close_window();
|
||||||
|
glib::Continue(false)
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_main_menu(&self, app: >k::Application) {
|
fn create_main_menu(&self, app: >k::Application) {
|
||||||
@ -128,96 +145,76 @@ impl Ui {
|
|||||||
|
|
||||||
|
|
||||||
let about_action = SimpleAction::new("HelpAbout", None);
|
let about_action = SimpleAction::new("HelpAbout", None);
|
||||||
about_action.connect_activate(on_help_about);
|
let comps = self.comps.clone();
|
||||||
|
about_action.connect_activate(move |_, _| on_help_about(&*comps.borrow()));
|
||||||
about_action.set_enabled(true);
|
about_action.set_enabled(true);
|
||||||
app.add_action(&about_action);
|
app.add_action(&about_action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_help_about(_: &SimpleAction, _: &Option<Variant>) {
|
fn on_help_about(comps: &Components) {
|
||||||
UI.with(|ui_cell| {
|
let about = AboutDialog::new();
|
||||||
let ui = ui_cell.borrow();
|
about.set_transient_for(comps.window.as_ref());
|
||||||
|
about.set_program_name("NeovimGtk");
|
||||||
|
about.set_version(env!("CARGO_PKG_VERSION"));
|
||||||
|
about.set_logo(None);
|
||||||
|
about.set_authors(&[env!("CARGO_PKG_AUTHORS")]);
|
||||||
|
|
||||||
let about = AboutDialog::new();
|
about.connect_response(|about, _| about.destroy());
|
||||||
about.set_transient_for(ui.window.as_ref());
|
about.show();
|
||||||
about.set_program_name("NeovimGtk");
|
|
||||||
about.set_version(env!("CARGO_PKG_VERSION"));
|
|
||||||
about.set_logo(None);
|
|
||||||
about.set_authors(&[env!("CARGO_PKG_AUTHORS")]);
|
|
||||||
|
|
||||||
about.connect_response(|about, _| about.destroy());
|
|
||||||
about.show();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_paste() {
|
fn gtk_delete(comps: &UiMutex<Components>, shell: &RefCell<Shell>) -> Inhibit {
|
||||||
SHELL!(shell = {
|
Inhibit(if shell_dlg::can_close_window(comps, shell) {
|
||||||
let paste_command = if shell.mode == NvimMode::Normal {
|
let comps = comps.borrow();
|
||||||
"\"*p"
|
comps.close_window();
|
||||||
} else {
|
shell.borrow_mut().detach_ui();
|
||||||
"<Esc>\"*pa"
|
false
|
||||||
};
|
} else {
|
||||||
|
true
|
||||||
let mut nvim = shell.nvim();
|
})
|
||||||
nvim.input(paste_command).report_err(nvim);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn edit_save_all() {
|
|
||||||
SHELL!(shell = {
|
|
||||||
let mut nvim = shell.nvim();
|
|
||||||
nvim.command(":wa").report_err(nvim);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn gtk_delete(_: &ApplicationWindow, _: &Event) -> Inhibit {
|
|
||||||
Inhibit(UI.with(|ui_cell| {
|
|
||||||
let mut ui = ui_cell.borrow_mut();
|
|
||||||
if shell_dlg::can_close_window(&ui) {
|
|
||||||
ui.destroy();
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct UiMutex<T: ?Sized> {
|
pub struct UiMutex<T: ?Sized> {
|
||||||
|
thread: String,
|
||||||
data: RefCell<T>,
|
data: RefCell<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: ?Sized + Send> Send for UiMutex<T> {}
|
unsafe impl<T: ?Sized> Send for UiMutex<T> {}
|
||||||
unsafe impl<T: ?Sized + Send> Sync for UiMutex<T> {}
|
unsafe impl<T: ?Sized> Sync for UiMutex<T> {}
|
||||||
|
|
||||||
impl<T> UiMutex<T> {
|
impl<T> UiMutex<T> {
|
||||||
pub fn new(t: T) -> UiMutex<T> {
|
pub fn new(t: T) -> UiMutex<T> {
|
||||||
UiMutex { data: RefCell::new(t) }
|
UiMutex {
|
||||||
|
thread: thread::current()
|
||||||
|
.name()
|
||||||
|
.expect("Can create UI only from main thread, current thiread has no name")
|
||||||
|
.to_owned(),
|
||||||
|
data: RefCell::new(t),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> UiMutex<T> {
|
impl<T: ?Sized> UiMutex<T> {
|
||||||
pub fn borrow(&self) -> Ref<T> {
|
pub fn borrow(&self) -> Ref<T> {
|
||||||
assert_ui_thread();
|
self.assert_ui_thread();
|
||||||
self.data.borrow()
|
self.data.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn borrow_mut(&self) -> RefMut<T> {
|
pub fn borrow_mut(&self) -> RefMut<T> {
|
||||||
assert_ui_thread();
|
self.assert_ui_thread();
|
||||||
self.data.borrow_mut()
|
self.data.borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
#[inline]
|
||||||
#[inline]
|
fn assert_ui_thread(&self) {
|
||||||
fn assert_ui_thread() {
|
match thread::current().name() {
|
||||||
match thread::current().name() {
|
Some(name) if name == self.thread => (),
|
||||||
Some("main") => (),
|
Some(name) => {
|
||||||
Some(ref name) => {
|
panic!("Can create UI only from main thread, {}", name);
|
||||||
panic!("Can create UI only from main thread, {}", name);
|
}
|
||||||
|
None => panic!("Can create UI only from main thread, current thread has no name"),
|
||||||
}
|
}
|
||||||
None => panic!("Can create UI only from main thread, current thiread has no name"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,20 +81,6 @@ pub struct UiModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UiModel {
|
impl UiModel {
|
||||||
pub fn empty() -> UiModel {
|
|
||||||
UiModel {
|
|
||||||
columns: 0,
|
|
||||||
rows: 0,
|
|
||||||
cur_row: 0,
|
|
||||||
cur_col: 0,
|
|
||||||
model: vec![],
|
|
||||||
top: 0,
|
|
||||||
bot: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(rows: u64, columns: u64) -> UiModel {
|
pub fn new(rows: u64, columns: u64) -> UiModel {
|
||||||
let mut model = Vec::with_capacity(rows as usize);
|
let mut model = Vec::with_capacity(rows as usize);
|
||||||
for i in 0..rows as usize {
|
for i in 0..rows as usize {
|
||||||
@ -314,21 +300,13 @@ impl ModelRect {
|
|||||||
} else {
|
} else {
|
||||||
x1
|
x1
|
||||||
};
|
};
|
||||||
let x2 = if x2 > 0.0 {
|
let x2 = if x2 > 0.0 { x2 - 1.0 } else { x2 };
|
||||||
x2 - 1.0
|
|
||||||
} else {
|
|
||||||
x2
|
|
||||||
};
|
|
||||||
let y1 = if y1 > 0.0 {
|
let y1 = if y1 > 0.0 {
|
||||||
y1 // - 1.0
|
y1 // - 1.0
|
||||||
} else {
|
} else {
|
||||||
y1
|
y1
|
||||||
};
|
};
|
||||||
let y2 = if y2 > 0.0 {
|
let y2 = if y2 > 0.0 { y2 - 1.0 } else { y2 };
|
||||||
y2 - 1.0
|
|
||||||
} else {
|
|
||||||
y2
|
|
||||||
};
|
|
||||||
let left = (x1 / char_width) as usize;
|
let left = (x1 / char_width) as usize;
|
||||||
let right = (x2 / char_width) as usize;
|
let right = (x2 / char_width) as usize;
|
||||||
let top = (y1 / line_height) as usize;
|
let top = (y1 / line_height) as usize;
|
||||||
@ -359,7 +337,9 @@ impl<'a> Iterator for ClipRowIterator<'a> {
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<(usize, ClipLine<'a>)> {
|
fn next(&mut self) -> Option<(usize, ClipLine<'a>)> {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
self.iter.next().map(|line| (self.rect.top + self.pos - 1, ClipLine::new(line, self.rect)))
|
self.iter
|
||||||
|
.next()
|
||||||
|
.map(|line| (self.rect.top + self.pos - 1, ClipLine::new(line, self.rect)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +386,9 @@ impl<'a> Iterator for ClipColIterator<'a> {
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<(usize, &'a Cell)> {
|
fn next(&mut self) -> Option<(usize, &'a Cell)> {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
self.iter.next().map(|line| (self.rect.left + self.pos - 1, line))
|
self.iter
|
||||||
|
.next()
|
||||||
|
.map(|line| (self.rect.left + self.pos - 1, line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user