2016-03-31 10:09:34 +00:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::thread;
|
2016-03-31 16:19:08 +00:00
|
|
|
use std::collections::HashMap;
|
2016-04-03 10:06:35 +00:00
|
|
|
use std::string::String;
|
2016-03-31 16:19:08 +00:00
|
|
|
|
2016-03-16 15:25:25 +00:00
|
|
|
use cairo;
|
2017-03-05 22:28:07 +00:00
|
|
|
use pangocairo as pc;
|
|
|
|
use pango;
|
|
|
|
use pango::FontDescription;
|
2016-03-16 15:25:25 +00:00
|
|
|
use gtk;
|
|
|
|
use gtk::prelude::*;
|
2017-03-07 14:12:22 +00:00
|
|
|
use gtk::{ApplicationWindow, HeaderBar, DrawingArea, ToolButton, Image};
|
2016-05-05 08:44:21 +00:00
|
|
|
use gdk::{ModifierType, Event, EventKey, EventConfigure, EventButton, EventMotion, EventType};
|
2016-05-05 07:23:04 +00:00
|
|
|
use gdk_sys;
|
2016-04-06 14:53:16 +00:00
|
|
|
use glib;
|
2017-02-26 19:31:13 +00:00
|
|
|
use neovim_lib::{Neovim, NeovimApi, Value, Integer};
|
2016-03-16 15:25:25 +00:00
|
|
|
|
2016-04-05 22:04:40 +00:00
|
|
|
use ui_model::{UiModel, Attrs, Color, COLOR_BLACK, COLOR_WHITE};
|
2017-03-08 19:22:58 +00:00
|
|
|
use nvim::{RedrawEvents, GuiApi, ErrorReport};
|
2016-03-19 08:47:23 +00:00
|
|
|
|
2016-05-04 14:59:51 +00:00
|
|
|
use input::{convert_key, keyval_to_input_string};
|
2016-04-04 10:14:57 +00:00
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2017-03-05 22:28:07 +00:00
|
|
|
const FONT_NAME: &'static str = "Droid Sans Mono for Powerline 12";
|
2016-04-04 10:14:57 +00:00
|
|
|
#[cfg(target_os = "windows")]
|
2017-03-05 22:28:07 +00:00
|
|
|
const FONT_NAME: &'static str = "DejaVu Sans Mono 12";
|
2016-04-01 21:14:22 +00:00
|
|
|
|
2016-03-31 10:09:34 +00:00
|
|
|
thread_local!(pub static UI: RefCell<Ui> = {
|
|
|
|
let thread = thread::current();
|
|
|
|
let current_thread_name = thread.name();
|
2017-02-26 19:31:13 +00:00
|
|
|
if current_thread_name != Some("main") {
|
2016-03-31 10:09:34 +00:00
|
|
|
panic!("Can create UI only from main thread, {:?}", current_thread_name);
|
|
|
|
}
|
|
|
|
RefCell::new(Ui::new())
|
|
|
|
});
|
|
|
|
|
2016-05-04 06:23:39 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
enum NvimMode {
|
|
|
|
Normal,
|
|
|
|
Insert,
|
|
|
|
Other,
|
|
|
|
}
|
|
|
|
|
2016-03-19 10:27:39 +00:00
|
|
|
pub struct Ui {
|
2016-03-28 15:05:10 +00:00
|
|
|
pub model: UiModel,
|
2016-03-28 10:09:31 +00:00
|
|
|
nvim: Option<Neovim>,
|
2016-03-31 10:09:34 +00:00
|
|
|
drawing_area: DrawingArea,
|
2017-03-06 13:58:10 +00:00
|
|
|
window: Option<ApplicationWindow>,
|
2017-03-07 14:12:22 +00:00
|
|
|
header_bar: HeaderBar,
|
2016-03-31 16:19:08 +00:00
|
|
|
cur_attrs: Option<Attrs>,
|
2016-04-05 22:04:40 +00:00
|
|
|
bg_color: Color,
|
|
|
|
fg_color: Color,
|
2016-04-06 10:16:41 +00:00
|
|
|
line_height: Option<f64>,
|
|
|
|
char_width: Option<f64>,
|
2017-03-05 17:52:46 +00:00
|
|
|
resize_timer: Option<glib::SourceId>,
|
2016-05-04 06:23:39 +00:00
|
|
|
mode: NvimMode,
|
2016-05-04 14:59:51 +00:00
|
|
|
mouse_enabled: bool,
|
2016-05-05 08:44:21 +00:00
|
|
|
mouse_pressed: bool,
|
2017-03-07 11:36:29 +00:00
|
|
|
font_desc: FontDescription,
|
2016-03-19 10:27:39 +00:00
|
|
|
}
|
2016-03-16 15:25:25 +00:00
|
|
|
|
|
|
|
impl Ui {
|
|
|
|
pub fn new() -> Ui {
|
2016-03-19 10:27:39 +00:00
|
|
|
Ui {
|
|
|
|
model: UiModel::empty(),
|
2016-03-31 10:09:34 +00:00
|
|
|
drawing_area: DrawingArea::new(),
|
2017-03-06 13:58:10 +00:00
|
|
|
window: None,
|
2017-03-07 14:12:22 +00:00
|
|
|
header_bar: HeaderBar::new(),
|
2016-03-28 10:09:31 +00:00
|
|
|
nvim: None,
|
2016-03-31 16:19:08 +00:00
|
|
|
cur_attrs: None,
|
2016-04-05 22:04:40 +00:00
|
|
|
bg_color: COLOR_BLACK,
|
|
|
|
fg_color: COLOR_WHITE,
|
2016-04-06 10:16:41 +00:00
|
|
|
line_height: None,
|
|
|
|
char_width: None,
|
2016-04-06 14:53:16 +00:00
|
|
|
resize_timer: None,
|
2017-02-28 08:53:56 +00:00
|
|
|
mode: NvimMode::Normal,
|
2016-05-04 14:59:51 +00:00
|
|
|
mouse_enabled: false,
|
2016-05-05 08:44:21 +00:00
|
|
|
mouse_pressed: false,
|
2017-03-07 11:36:29 +00:00
|
|
|
font_desc: FontDescription::from_string(FONT_NAME),
|
2016-03-19 10:27:39 +00:00
|
|
|
}
|
2016-03-16 15:25:25 +00:00
|
|
|
}
|
|
|
|
|
2016-03-28 10:09:31 +00:00
|
|
|
pub fn set_nvim(&mut self, nvim: Neovim) {
|
|
|
|
self.nvim = Some(nvim);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nvim(&mut self) -> &mut Neovim {
|
|
|
|
self.nvim.as_mut().unwrap()
|
|
|
|
}
|
|
|
|
|
2017-03-06 13:58:10 +00:00
|
|
|
pub fn destroy(&self) {
|
|
|
|
self.window.as_ref().unwrap().destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn init(&mut self, app: >k::Application) {
|
2017-03-07 14:12:22 +00:00
|
|
|
self.header_bar.set_show_close_button(true);
|
2016-03-17 13:58:21 +00:00
|
|
|
|
|
|
|
let save_image = Image::new_from_icon_name("document-save", 50);
|
|
|
|
let save_btn = ToolButton::new(Some(&save_image), None);
|
2017-03-07 14:12:22 +00:00
|
|
|
save_btn.connect_clicked(|_| edit_save_all());
|
|
|
|
self.header_bar.pack_start(&save_btn);
|
2016-03-17 13:58:21 +00:00
|
|
|
|
2017-03-07 14:12:22 +00:00
|
|
|
let paste_image = Image::new_from_icon_name("edit-paste", 50);
|
|
|
|
let paste_btn = ToolButton::new(Some(&paste_image), None);
|
|
|
|
paste_btn.connect_clicked(|_| edit_paste());
|
|
|
|
self.header_bar.pack_start(&paste_btn);
|
2016-03-17 13:58:21 +00:00
|
|
|
|
2016-03-16 15:25:25 +00:00
|
|
|
|
2016-04-03 22:34:44 +00:00
|
|
|
self.drawing_area.set_size_request(500, 300);
|
2016-03-31 10:09:34 +00:00
|
|
|
self.drawing_area.set_hexpand(true);
|
|
|
|
self.drawing_area.set_vexpand(true);
|
2016-05-04 14:59:51 +00:00
|
|
|
|
2016-05-05 08:44:21 +00:00
|
|
|
self.drawing_area
|
|
|
|
.set_events((gdk_sys::GDK_BUTTON_RELEASE_MASK | gdk_sys::GDK_BUTTON_PRESS_MASK |
|
|
|
|
gdk_sys::GDK_BUTTON_MOTION_MASK)
|
2017-02-26 19:33:44 +00:00
|
|
|
.bits() as i32);
|
2016-05-04 14:59:51 +00:00
|
|
|
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);
|
2016-03-31 10:09:34 +00:00
|
|
|
self.drawing_area.connect_draw(gtk_draw);
|
2016-03-16 15:25:25 +00:00
|
|
|
|
2017-03-06 13:58:10 +00:00
|
|
|
self.window = Some(ApplicationWindow::new(app));
|
|
|
|
let window = self.window.as_ref().unwrap();
|
|
|
|
|
2017-03-07 14:12:22 +00:00
|
|
|
window.set_titlebar(Some(&self.header_bar));
|
|
|
|
window.add(&self.drawing_area);
|
2017-03-06 13:58:10 +00:00
|
|
|
window.show_all();
|
|
|
|
window.connect_key_press_event(gtk_key_press);
|
|
|
|
window.connect_delete_event(gtk_delete);
|
2017-03-06 14:13:32 +00:00
|
|
|
window.set_title("Neovim-gtk");
|
2016-04-06 14:53:16 +00:00
|
|
|
self.drawing_area.connect_configure_event(gtk_configure_event);
|
2016-03-16 15:25:25 +00:00
|
|
|
}
|
2017-03-06 21:05:48 +00:00
|
|
|
|
|
|
|
fn create_pango_font(&self) -> FontDescription {
|
2017-03-07 11:36:29 +00:00
|
|
|
self.font_desc.clone()
|
2017-03-06 21:05:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_font_desc(&mut self, desc: &str) {
|
2017-03-07 11:36:29 +00:00
|
|
|
self.font_desc = FontDescription::from_string(desc);
|
2017-03-06 21:05:48 +00:00
|
|
|
}
|
2016-03-31 10:09:34 +00:00
|
|
|
}
|
2016-03-16 15:25:25 +00:00
|
|
|
|
2016-05-04 14:59:51 +00:00
|
|
|
fn gtk_button_press(_: &DrawingArea, ev: &EventButton) -> Inhibit {
|
|
|
|
if ev.get_event_type() != EventType::ButtonPress {
|
|
|
|
return Inhibit(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
UI.with(|ui_cell| {
|
|
|
|
let mut ui = ui_cell.borrow_mut();
|
|
|
|
if !ui.mouse_enabled {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-05 08:44:21 +00:00
|
|
|
mouse_input(&mut *ui, "LeftMouse", ev.get_state(), ev.get_position());
|
2016-05-04 14:59:51 +00:00
|
|
|
});
|
|
|
|
Inhibit(false)
|
|
|
|
}
|
|
|
|
|
2016-05-05 08:44:21 +00:00
|
|
|
fn mouse_input(ui: &mut Ui, input: &str, state: ModifierType, position: (f64, f64)) {
|
|
|
|
if let Some(line_height) = ui.line_height {
|
|
|
|
if let Some(char_width) = ui.char_width {
|
|
|
|
ui.mouse_pressed = true;
|
|
|
|
|
|
|
|
let nvim = ui.nvim();
|
|
|
|
let (x, y) = position;
|
|
|
|
let col = (x / char_width).trunc() as u64;
|
|
|
|
let row = (y / line_height).trunc() as u64;
|
|
|
|
let input_str = format!("{}<{},{}>", keyval_to_input_string(input, state), col, row);
|
|
|
|
nvim.input(&input_str).expect("Can't send mouse input event");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-04 14:59:51 +00:00
|
|
|
fn gtk_button_release(_: &DrawingArea, _: &EventButton) -> Inhibit {
|
2016-05-05 08:44:21 +00:00
|
|
|
UI.with(|ui_cell| ui_cell.borrow_mut().mouse_pressed = false);
|
2016-05-04 14:59:51 +00:00
|
|
|
Inhibit(false)
|
|
|
|
}
|
|
|
|
|
2016-05-05 08:44:21 +00:00
|
|
|
fn gtk_motion_notify(_: &DrawingArea, ev: &EventMotion) -> Inhibit {
|
2016-05-04 14:59:51 +00:00
|
|
|
UI.with(|ui_cell| {
|
|
|
|
let mut ui = ui_cell.borrow_mut();
|
2016-05-05 08:44:21 +00:00
|
|
|
if !ui.mouse_enabled || !ui.mouse_pressed {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mouse_input(&mut *ui, "LeftDrag", ev.get_state(), ev.get_position());
|
2016-05-04 14:59:51 +00:00
|
|
|
});
|
|
|
|
Inhibit(false)
|
|
|
|
}
|
|
|
|
|
2017-03-07 14:12:22 +00:00
|
|
|
fn edit_paste() {
|
2017-03-08 19:22:58 +00:00
|
|
|
UI.with(|ui_cell| {
|
2017-03-07 14:12:22 +00:00
|
|
|
let mut ui = ui_cell.borrow_mut();
|
|
|
|
|
2017-03-08 19:22:58 +00:00
|
|
|
let paste_command = if ui.mode == NvimMode::Normal {
|
|
|
|
"\"*p"
|
|
|
|
} else {
|
|
|
|
"<Esc>\"*p"
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut nvim = ui.nvim();
|
|
|
|
nvim.input(paste_command).report_err(nvim, "Error paste from clipboard");
|
2017-03-07 14:12:22 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn edit_save_all() {
|
2017-03-07 10:52:01 +00:00
|
|
|
UI.with(|ui_cell| {
|
|
|
|
let mut ui = ui_cell.borrow_mut();
|
|
|
|
|
2017-03-08 19:22:58 +00:00
|
|
|
let mut nvim = ui.nvim();
|
|
|
|
nvim.command(":wa").report_err(nvim, "Error save all files");
|
2017-03-07 10:52:01 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-05-05 13:48:21 +00:00
|
|
|
fn quit() {
|
2016-05-04 08:52:57 +00:00
|
|
|
UI.with(|ui_cell| {
|
|
|
|
let mut ui = ui_cell.borrow_mut();
|
2017-03-06 13:58:10 +00:00
|
|
|
ui.destroy();
|
|
|
|
|
2016-05-04 08:52:57 +00:00
|
|
|
let nvim = ui.nvim();
|
|
|
|
nvim.ui_detach().expect("Error in ui_detach");
|
2016-05-05 13:48:21 +00:00
|
|
|
//nvim.quit_no_save().expect("Can't stop nvim instance");
|
2016-05-04 08:52:57 +00:00
|
|
|
});
|
2016-05-05 13:48:21 +00:00
|
|
|
}
|
|
|
|
|
2017-03-06 13:58:10 +00:00
|
|
|
fn gtk_delete(_: &ApplicationWindow, _: &Event) -> Inhibit {
|
2016-05-05 13:48:21 +00:00
|
|
|
quit();
|
2016-05-04 08:52:57 +00:00
|
|
|
Inhibit(false)
|
|
|
|
}
|
|
|
|
|
2017-03-06 13:58:10 +00:00
|
|
|
fn gtk_key_press(_: &ApplicationWindow, ev: &EventKey) -> Inhibit {
|
2016-04-04 10:14:57 +00:00
|
|
|
if let Some(input) = convert_key(ev) {
|
|
|
|
UI.with(|ui_cell| {
|
|
|
|
let mut ui = ui_cell.borrow_mut();
|
|
|
|
ui.nvim().input(&input).expect("Error run input command to nvim");
|
|
|
|
});
|
2016-05-03 10:36:59 +00:00
|
|
|
Inhibit(true)
|
|
|
|
} else {
|
|
|
|
Inhibit(false)
|
2016-03-31 13:52:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-03 10:30:36 +00:00
|
|
|
fn gtk_draw(_: &DrawingArea, ctx: &cairo::Context) -> Inhibit {
|
2016-03-31 10:09:34 +00:00
|
|
|
UI.with(|ui_cell| {
|
2016-04-06 10:16:41 +00:00
|
|
|
let mut ui = ui_cell.borrow_mut();
|
2016-04-03 22:34:44 +00:00
|
|
|
|
2017-03-06 21:05:48 +00:00
|
|
|
let (width, height) = calc_char_bounds(&*ui, ctx);
|
2017-03-05 22:28:07 +00:00
|
|
|
ui.line_height = Some(height as f64);
|
|
|
|
ui.char_width = Some(width as f64);
|
2016-04-06 10:16:41 +00:00
|
|
|
|
|
|
|
draw(&*ui, ctx);
|
2016-05-03 10:30:36 +00:00
|
|
|
request_width(&*ui);
|
2016-03-31 10:09:34 +00:00
|
|
|
});
|
|
|
|
|
2016-04-06 14:53:16 +00:00
|
|
|
Inhibit(false)
|
|
|
|
}
|
|
|
|
|
2016-06-23 14:32:30 +00:00
|
|
|
fn gtk_configure_event(_: &DrawingArea, ev: &EventConfigure) -> bool {
|
2016-04-06 14:53:16 +00:00
|
|
|
UI.with(|ui_cell| {
|
|
|
|
let mut ui = ui_cell.borrow_mut();
|
|
|
|
let (width, height) = ev.get_size();
|
|
|
|
|
|
|
|
if let Some(timer) = ui.resize_timer {
|
2017-03-05 17:52:46 +00:00
|
|
|
glib::source_remove(timer);
|
2016-04-06 14:53:16 +00:00
|
|
|
}
|
|
|
|
if let Some(line_height) = ui.line_height {
|
|
|
|
if let Some(char_width) = ui.char_width {
|
|
|
|
|
|
|
|
ui.resize_timer = Some(glib::timeout_add(250, move || {
|
|
|
|
UI.with(|ui_cell| {
|
|
|
|
let mut ui = ui_cell.borrow_mut();
|
|
|
|
ui.resize_timer = None;
|
|
|
|
|
|
|
|
let rows = (height as f64 / line_height).trunc() as usize;
|
|
|
|
let columns = (width as f64 / char_width).trunc() as usize;
|
|
|
|
if ui.model.rows != rows || ui.model.columns != columns {
|
|
|
|
if let Err(err) = ui.nvim().ui_try_resize(columns as u64, rows as u64) {
|
|
|
|
println!("Error trying resize nvim {}", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
Continue(false)
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2016-06-23 14:32:30 +00:00
|
|
|
false
|
2016-04-06 10:16:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn draw(ui: &Ui, ctx: &cairo::Context) {
|
|
|
|
ctx.set_source_rgb(ui.bg_color.0, ui.bg_color.1, ui.bg_color.2);
|
|
|
|
ctx.paint();
|
2016-04-03 22:34:44 +00:00
|
|
|
|
2016-04-06 10:16:41 +00:00
|
|
|
let line_height = ui.line_height.unwrap();
|
|
|
|
let char_width = ui.char_width.unwrap();
|
2016-05-03 17:25:52 +00:00
|
|
|
let (row, col) = ui.model.get_cursor();
|
2017-03-06 14:13:32 +00:00
|
|
|
let mut buf = String::with_capacity(4);
|
2016-04-06 10:16:41 +00:00
|
|
|
|
2017-03-05 22:28:07 +00:00
|
|
|
let mut line_y: f64 = 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
let layout = pc::create_layout(ctx);
|
2017-03-07 11:36:29 +00:00
|
|
|
let mut desc = ui.create_pango_font();
|
2017-03-05 22:28:07 +00:00
|
|
|
|
2016-05-03 17:25:52 +00:00
|
|
|
for (line_idx, line) in ui.model.model().iter().enumerate() {
|
2017-03-05 22:28:07 +00:00
|
|
|
ctx.move_to(0.0, line_y);
|
2016-05-03 17:25:52 +00:00
|
|
|
for (col_idx, cell) in line.iter().enumerate() {
|
2016-04-06 10:16:41 +00:00
|
|
|
|
|
|
|
let current_point = ctx.get_current_point();
|
|
|
|
|
|
|
|
if let Some(ref bg) = cell.attrs.background {
|
|
|
|
ctx.set_source_rgb(bg.0, bg.1, bg.2);
|
2017-03-05 22:28:07 +00:00
|
|
|
ctx.rectangle(current_point.0, line_y, char_width, line_height);
|
2016-04-06 10:16:41 +00:00
|
|
|
ctx.fill();
|
|
|
|
|
|
|
|
ctx.move_to(current_point.0, current_point.1);
|
|
|
|
}
|
2016-05-03 17:25:52 +00:00
|
|
|
|
2016-04-06 10:16:41 +00:00
|
|
|
let fg = if let Some(ref fg) = cell.attrs.foreground {
|
|
|
|
fg
|
2016-05-03 10:34:36 +00:00
|
|
|
} else {
|
2016-04-06 10:16:41 +00:00
|
|
|
&ui.fg_color
|
|
|
|
};
|
2016-05-03 17:25:52 +00:00
|
|
|
|
|
|
|
let bg = if let Some(ref bg) = cell.attrs.background {
|
|
|
|
bg
|
|
|
|
} else {
|
|
|
|
&ui.bg_color
|
|
|
|
};
|
|
|
|
|
|
|
|
if row == line_idx && col == col_idx {
|
|
|
|
ctx.set_source_rgba(1.0 - bg.0, 1.0 - bg.1, 1.0 - bg.2, 0.5);
|
2016-05-04 06:23:39 +00:00
|
|
|
|
|
|
|
let cursor_width = if ui.mode == NvimMode::Insert {
|
|
|
|
char_width / 5.0
|
|
|
|
} else {
|
|
|
|
char_width
|
|
|
|
};
|
|
|
|
|
2017-03-05 22:28:07 +00:00
|
|
|
ctx.rectangle(current_point.0, line_y, cursor_width, line_height);
|
2016-05-03 17:25:52 +00:00
|
|
|
ctx.fill();
|
|
|
|
ctx.move_to(current_point.0, current_point.1);
|
|
|
|
}
|
2017-03-05 22:28:07 +00:00
|
|
|
|
2017-03-06 14:13:32 +00:00
|
|
|
if !cell.ch.is_whitespace() {
|
2017-03-07 11:36:29 +00:00
|
|
|
desc.unset_fields(pango::FONT_MASK_STYLE | pango::FONT_MASK_WEIGHT);
|
2017-03-06 14:13:32 +00:00
|
|
|
if cell.attrs.italic {
|
|
|
|
desc.set_style(pango::Style::Italic);
|
|
|
|
}
|
|
|
|
if cell.attrs.bold {
|
|
|
|
desc.set_weight(pango::Weight::Bold);
|
|
|
|
}
|
|
|
|
|
|
|
|
layout.set_font_description(Some(&desc));
|
|
|
|
buf.clear();
|
|
|
|
buf.push(cell.ch);
|
|
|
|
layout.set_text(&buf, -1);
|
|
|
|
|
|
|
|
ctx.set_source_rgb(fg.0, fg.1, fg.2);
|
|
|
|
pc::update_layout(ctx, &layout);
|
|
|
|
pc::show_layout(ctx, &layout);
|
|
|
|
}
|
|
|
|
|
2016-04-06 10:16:41 +00:00
|
|
|
ctx.move_to(current_point.0 + char_width, current_point.1);
|
|
|
|
}
|
2017-03-05 22:28:07 +00:00
|
|
|
|
2016-04-06 10:16:41 +00:00
|
|
|
line_y += line_height;
|
|
|
|
}
|
2016-04-04 10:14:57 +00:00
|
|
|
|
2017-03-05 22:28:07 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-03-06 21:05:48 +00:00
|
|
|
fn calc_char_bounds(ui: &Ui, ctx: &cairo::Context) -> (i32, i32) {
|
2017-03-05 22:28:07 +00:00
|
|
|
let layout = pc::create_layout(ctx);
|
|
|
|
|
2017-03-06 21:05:48 +00:00
|
|
|
let desc = ui.create_pango_font();
|
2017-03-05 22:28:07 +00:00
|
|
|
layout.set_font_description(Some(&desc));
|
|
|
|
layout.set_text("A", -1);
|
|
|
|
|
|
|
|
layout.get_pixel_size()
|
2016-03-16 15:25:25 +00:00
|
|
|
}
|
2016-03-23 11:59:18 +00:00
|
|
|
|
2016-05-03 10:30:36 +00:00
|
|
|
fn request_width(ui: &Ui) {
|
|
|
|
if ui.resize_timer.is_some() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let width = ui.drawing_area.get_allocated_width();
|
|
|
|
let height = ui.drawing_area.get_allocated_height();
|
2016-04-06 10:16:41 +00:00
|
|
|
let request_height = (ui.model.rows as f64 * ui.line_height.unwrap()) as i32;
|
|
|
|
let request_width = (ui.model.columns as f64 * ui.char_width.unwrap()) as i32;
|
2016-04-03 22:34:44 +00:00
|
|
|
|
|
|
|
if width != request_width || height != request_height {
|
2017-03-06 13:58:10 +00:00
|
|
|
let window = ui.window.as_ref().unwrap();
|
|
|
|
let (win_width, win_height) = window.get_size();
|
2017-03-06 10:03:13 +00:00
|
|
|
let h_border = win_width - width;
|
|
|
|
let v_border = win_height - height;
|
2017-03-06 13:58:10 +00:00
|
|
|
window.resize(request_width + h_border, request_height + v_border);
|
2016-04-03 22:34:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-06 21:05:48 +00:00
|
|
|
impl GuiApi for Ui {
|
2017-03-08 19:22:58 +00:00
|
|
|
fn set_font(&mut self, font_desc: &str) {
|
|
|
|
self.set_font_desc(font_desc);
|
|
|
|
}
|
2017-03-06 21:05:48 +00:00
|
|
|
}
|
|
|
|
|
2016-03-23 11:59:18 +00:00
|
|
|
impl RedrawEvents for Ui {
|
2016-03-28 14:03:21 +00:00
|
|
|
fn on_cursor_goto(&mut self, row: u64, col: u64) {
|
|
|
|
self.model.set_cursor(row, col);
|
|
|
|
}
|
2016-03-28 15:05:10 +00:00
|
|
|
|
|
|
|
fn on_put(&mut self, text: &str) {
|
2016-03-31 16:19:08 +00:00
|
|
|
self.model.put(text, &self.cur_attrs);
|
2016-03-28 15:05:10 +00:00
|
|
|
}
|
2016-03-29 09:22:16 +00:00
|
|
|
|
|
|
|
fn on_clear(&mut self) {
|
|
|
|
self.model.clear();
|
|
|
|
}
|
2016-03-29 09:43:01 +00:00
|
|
|
|
2016-04-03 13:04:52 +00:00
|
|
|
fn on_eol_clear(&mut self) {
|
|
|
|
self.model.eol_clear();
|
|
|
|
}
|
|
|
|
|
2016-03-29 09:43:01 +00:00
|
|
|
fn on_resize(&mut self, columns: u64, rows: u64) {
|
|
|
|
self.model = UiModel::new(rows, columns);
|
|
|
|
}
|
2016-03-31 13:52:22 +00:00
|
|
|
|
|
|
|
fn on_redraw(&self) {
|
|
|
|
self.drawing_area.queue_draw();
|
|
|
|
}
|
2016-03-31 16:19:08 +00:00
|
|
|
|
2016-04-03 15:13:18 +00:00
|
|
|
fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) {
|
|
|
|
self.model.set_scroll_region(top, bot, left, right);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn on_scroll(&mut self, count: i64) {
|
|
|
|
self.model.scroll(count);
|
|
|
|
}
|
|
|
|
|
2016-03-31 16:19:08 +00:00
|
|
|
fn on_highlight_set(&mut self, attrs: &HashMap<String, Value>) {
|
|
|
|
let mut model_attrs = Attrs::new();
|
|
|
|
if let Some(&Value::Integer(Integer::U64(fg))) = attrs.get("foreground") {
|
2016-04-05 22:04:40 +00:00
|
|
|
model_attrs.foreground = Some(split_color(fg));
|
2016-03-31 16:19:08 +00:00
|
|
|
}
|
2016-04-05 22:04:40 +00:00
|
|
|
if let Some(&Value::Integer(Integer::U64(bg))) = attrs.get("background") {
|
|
|
|
model_attrs.background = Some(split_color(bg));
|
2016-03-31 16:19:08 +00:00
|
|
|
}
|
|
|
|
if attrs.contains_key("reverse") {
|
2016-04-05 22:04:40 +00:00
|
|
|
let fg = if let Some(ref fg) = model_attrs.foreground {
|
|
|
|
fg.clone()
|
|
|
|
} else {
|
|
|
|
self.fg_color.clone()
|
|
|
|
};
|
|
|
|
let bg = if let Some(ref bg) = model_attrs.background {
|
|
|
|
bg.clone()
|
|
|
|
} else {
|
|
|
|
self.bg_color.clone()
|
|
|
|
};
|
|
|
|
model_attrs.foreground = Some(bg);
|
|
|
|
model_attrs.background = Some(fg);
|
2016-03-31 16:19:08 +00:00
|
|
|
}
|
2016-04-01 09:34:55 +00:00
|
|
|
model_attrs.bold = attrs.contains_key("bold");
|
|
|
|
model_attrs.italic = attrs.contains_key("italic");
|
2016-03-31 16:19:08 +00:00
|
|
|
self.cur_attrs = Some(model_attrs);
|
|
|
|
}
|
2016-04-05 22:04:40 +00:00
|
|
|
|
|
|
|
fn on_update_bg(&mut self, bg: i64) {
|
|
|
|
if bg >= 0 {
|
|
|
|
self.bg_color = split_color(bg as u64);
|
2016-05-03 10:34:36 +00:00
|
|
|
} else {
|
2016-04-05 22:04:40 +00:00
|
|
|
self.bg_color = COLOR_BLACK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn on_update_fg(&mut self, fg: i64) {
|
|
|
|
if fg >= 0 {
|
|
|
|
self.fg_color = split_color(fg as u64);
|
2016-05-03 10:34:36 +00:00
|
|
|
} else {
|
2016-04-05 22:04:40 +00:00
|
|
|
self.fg_color = COLOR_WHITE;
|
|
|
|
}
|
|
|
|
}
|
2016-05-04 06:23:39 +00:00
|
|
|
|
|
|
|
fn on_mode_change(&mut self, mode: &str) {
|
|
|
|
match mode {
|
|
|
|
"normal" => self.mode = NvimMode::Normal,
|
|
|
|
"insert" => self.mode = NvimMode::Insert,
|
|
|
|
_ => self.mode = NvimMode::Other,
|
|
|
|
}
|
|
|
|
}
|
2016-05-04 14:59:51 +00:00
|
|
|
|
|
|
|
fn on_mouse_on(&mut self) {
|
|
|
|
self.mouse_enabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn on_mouse_off(&mut self) {
|
|
|
|
self.mouse_enabled = false;
|
|
|
|
}
|
2016-03-31 16:19:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn split_color(indexed_color: u64) -> Color {
|
|
|
|
let r = ((indexed_color >> 16) & 0xff) as f64;
|
|
|
|
let g = ((indexed_color >> 8) & 0xff) as f64;
|
|
|
|
let b = (indexed_color & 0xff) as f64;
|
2016-04-03 13:04:52 +00:00
|
|
|
Color(r / 255.0, g / 255.0, b / 255.0)
|
2016-03-23 11:59:18 +00:00
|
|
|
}
|