Move out resize/init code from draw handler

This commit is contained in:
daa84 2017-09-13 17:40:43 +03:00
parent dc8d6d5a70
commit 94747615af
8 changed files with 330 additions and 272 deletions

View File

@ -47,26 +47,29 @@ pub trait RedrawEvents {
fn on_busy(&mut self, busy: bool) -> RepaintMode;
fn popupmenu_show(&mut self,
fn popupmenu_show(
&mut self,
menu: &[Vec<&str>],
selected: i64,
row: u64,
col: u64)
-> RepaintMode;
col: u64,
) -> RepaintMode;
fn popupmenu_hide(&mut self) -> RepaintMode;
fn popupmenu_select(&mut self, selected: i64) -> RepaintMode;
fn tabline_update(&mut self,
fn tabline_update(
&mut self,
selected: Tabpage,
tabs: Vec<(Tabpage, Option<String>)>)
-> RepaintMode;
tabs: Vec<(Tabpage, Option<String>)>,
) -> RepaintMode;
fn mode_info_set(&mut self,
fn mode_info_set(
&mut self,
cursor_style_enabled: bool,
mode_info: Vec<ModeInfo>)
-> RepaintMode;
mode_info: Vec<ModeInfo>,
) -> RepaintMode;
}
pub trait GuiApi {
@ -116,9 +119,9 @@ pub enum CursorShape {
impl CursorShape {
fn new(shape_code: &Value) -> Result<CursorShape, String> {
let str_code = shape_code
.as_str()
.ok_or_else(|| "Can't convert cursor shape to string".to_owned())?;
let str_code = shape_code.as_str().ok_or_else(|| {
"Can't convert cursor shape to string".to_owned()
})?;
Ok(match str_code {
"block" => CursorShape::Block,
@ -177,7 +180,8 @@ pub struct NvimInitError {
impl NvimInitError {
pub fn new_post_init<E>(error: E) -> NvimInitError
where E: Into<Box<error::Error>>
where
E: Into<Box<error::Error>>,
{
NvimInitError {
cmd: None,
@ -186,7 +190,8 @@ impl NvimInitError {
}
pub fn new<E>(cmd: &Command, error: E) -> NvimInitError
where E: Into<Box<error::Error>>
where
E: Into<Box<error::Error>>,
{
NvimInitError {
cmd: Some(format!("{:?}", cmd)),
@ -219,9 +224,10 @@ impl error::Error for NvimInitError {
}
}
pub fn start(shell: Arc<UiMutex<shell::State>>,
nvim_bin_path: Option<&String>)
-> result::Result<Neovim, NvimInitError> {
pub fn start(
shell: Arc<UiMutex<shell::State>>,
nvim_bin_path: Option<&String>,
) -> result::Result<Neovim, NvimInitError> {
let mut cmd = if let Some(path) = nvim_bin_path {
Command::new(path)
} else {
@ -237,11 +243,14 @@ pub fn start(shell: Arc<UiMutex<shell::State>>,
.stderr(Stdio::inherit());
if let Ok(runtime_path) = env::var("NVIM_GTK_RUNTIME_PATH") {
cmd.arg("--cmd")
.arg(format!("let &rtp.=',{}'", runtime_path));
cmd.arg("--cmd").arg(
format!("let &rtp.=',{}'", runtime_path),
);
} else if let Some(prefix) = option_env!("PREFIX") {
cmd.arg("--cmd")
.arg(format!("let &rtp.=',{}/share/nvim-gtk/runtime'", prefix));
cmd.arg("--cmd").arg(format!(
"let &rtp.=',{}/share/nvim-gtk/runtime'",
prefix
));
} else {
cmd.arg("--cmd").arg("let &rtp.=',runtime'");
}
@ -255,28 +264,33 @@ pub fn start(shell: Arc<UiMutex<shell::State>>,
let mut nvim = Neovim::new(session);
nvim.session
.start_event_loop_handler(NvimHandler::new(shell));
nvim.session.start_event_loop_handler(
NvimHandler::new(shell),
);
Ok(nvim)
}
pub fn post_start_init(nvim: &mut Neovim,
pub fn post_start_init(
nvim: &mut Neovim,
open_path: Option<&String>,
cols: u64,
rows: u64)
-> result::Result<(), NvimInitError> {
rows: u64,
) -> result::Result<(), NvimInitError> {
let mut opts = UiAttachOptions::new();
opts.set_popupmenu_external(false);
opts.set_tabline_external(true);
nvim.ui_attach(cols, rows, opts)
.map_err(NvimInitError::new_post_init)?;
nvim.command("runtime! ginit.vim")
.map_err(NvimInitError::new_post_init)?;
nvim.ui_attach(cols, rows, opts).map_err(
NvimInitError::new_post_init,
)?;
nvim.command("runtime! ginit.vim").map_err(
NvimInitError::new_post_init,
)?;
if let Some(path) = open_path {
nvim.command(&format!("e {}", path))
.map_err(NvimInitError::new_post_init)?;
nvim.command(&format!("e {}", path)).map_err(
NvimInitError::new_post_init,
)?;
}
Ok(())
@ -343,7 +357,8 @@ impl NvimHandler {
}
fn safe_call<F>(&self, cb: F)
where F: Fn(&mut shell::State) -> result::Result<(), String> + 'static + Send
where
F: Fn(&mut shell::State) -> result::Result<(), String> + 'static + Send,
{
let shell = self.shell.clone();
glib::idle_add(move || {
@ -362,21 +377,24 @@ impl Handler for NvimHandler {
}
fn call_gui_event(ui: &mut shell::State,
fn call_gui_event(
ui: &mut shell::State,
method: &str,
args: &Vec<Value>)
-> result::Result<(), String> {
args: &Vec<Value>,
) -> result::Result<(), String> {
match method {
"Font" => ui.set_font(try_str!(args[0])),
"Option" => {
match try_str!(args[0]) {
"Popupmenu" => {
ui.nvim()
.unwrap()
.set_option(UiOption::ExtPopupmenu(try_uint!(args[1]) == 1))
.map_err(|e| e.to_string())?
}
"Tabline" => {
ui.nvim()
.unwrap()
.set_option(UiOption::ExtTabline(try_uint!(args[1]) == 1))
.map_err(|e| e.to_string())?
}
@ -388,10 +406,11 @@ fn call_gui_event(ui: &mut shell::State,
Ok(())
}
fn call(ui: &mut shell::State,
fn call(
ui: &mut shell::State,
method: &str,
args: &[Value])
-> result::Result<RepaintMode, String> {
args: &[Value],
) -> result::Result<RepaintMode, String> {
let repaint_mode = match method {
"cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])),
"put" => ui.on_put(try_str!(args[0])),
@ -407,10 +426,12 @@ fn call(ui: &mut shell::State,
}
"eol_clear" => ui.on_eol_clear(),
"set_scroll_region" => {
ui.on_set_scroll_region(try_uint!(args[0]),
ui.on_set_scroll_region(
try_uint!(args[0]),
try_uint!(args[1]),
try_uint!(args[2]),
try_uint!(args[3]));
try_uint!(args[3]),
);
RepaintMode::Nothing
}
"scroll" => ui.on_scroll(try_int!(args[0])),
@ -424,15 +445,17 @@ fn call(ui: &mut shell::State,
"busy_stop" => ui.on_busy(false),
"popupmenu_show" => {
let menu_items = map_array!(args[0], "Error get menu list array", |item| {
map_array!(item,
"Error get menu item array",
|col| col.as_str().ok_or("Error get menu column"))
map_array!(item, "Error get menu item array", |col| {
col.as_str().ok_or("Error get menu column")
})
})?;
ui.popupmenu_show(&menu_items,
ui.popupmenu_show(
&menu_items,
try_int!(args[1]),
try_uint!(args[2]),
try_uint!(args[3]))
try_uint!(args[3]),
)
}
"popupmenu_hide" => ui.popupmenu_hide(),
"popupmenu_select" => ui.popupmenu_select(try_int!(args[0])),
@ -442,9 +465,9 @@ fn call(ui: &mut shell::State,
.ok_or_else(|| "Error get map for tab".to_owned())
.and_then(|tab_map| tab_map.to_attrs_map())
.map(|tab_attrs| {
let name_attr = tab_attrs
.get("name")
.and_then(|n| n.as_str().map(|s| s.to_owned()));
let name_attr = tab_attrs.get("name").and_then(
|n| n.as_str().map(|s| s.to_owned()),
);
let tab_attr = tab_attrs
.get("tab")
.map(|tab_id| Tabpage::new(tab_id.clone()))
@ -456,13 +479,15 @@ fn call(ui: &mut shell::State,
ui.tabline_update(Tabpage::new(args[0].clone()), tabs_out)
}
"mode_info_set" => {
let mode_info = map_array!(args[1],
let mode_info = map_array!(
args[1],
"Error get array key value for mode_info".to_owned(),
|mi| {
mi.as_map()
.ok_or_else(|| "Erro get map for mode_info".to_owned())
.and_then(|mi_map| ModeInfo::new(mi_map))
})?;
}
)?;
ui.mode_info_set(try_bool!(args[0]), mode_info)
}
_ => {

View File

@ -245,15 +245,17 @@ impl Projects {
fn load_oldfiles(&mut self) {
let shell_borrow = self.shell.borrow();
let shell_state = shell_borrow.state.borrow_mut();
let mut nvim = shell_state.nvim();
let nvim = shell_state.nvim();
if let Some(mut nvim) = nvim {
let store = EntryStore::load(&mut nvim);
store.populate(&self.get_list_store(), None);
self.store = Some(store);
}
}
pub fn clear(&mut self) {
self.store.take().unwrap().save();
self.store.take().map(|s| s.save());
self.get_list_store().clear();
}

View File

@ -96,6 +96,5 @@ fn monospace_font_changed(mut shell: &mut Shell, state: &mut State) {
// rpc is priority for font
if state.font_source != FontSource::Rpc {
state.update_font(&mut shell);
shell.redraw(&RepaintMode::All);
}
}

View File

@ -48,6 +48,12 @@ macro_rules! idle_cb_call {
)
}
enum ResizeState {
RequestNvimResize(glib::SourceId),
RequestWindowResize,
Wait,
}
pub struct State {
pub model: UiModel,
color_model: ColorModel,
@ -67,9 +73,7 @@ pub struct State {
im_context: gtk::IMMulticontext,
error_area: error::ErrorArea,
request_resize: bool,
request_nvim_resize: bool,
resize_timer: Option<glib::SourceId>,
resize_state: ResizeState,
options: ShellOptions,
@ -102,9 +106,7 @@ impl State {
im_context: gtk::IMMulticontext::new(),
error_area: error::ErrorArea::new(),
resize_timer: None,
request_resize: false,
request_nvim_resize: false,
resize_state: ResizeState::Wait,
options,
@ -120,8 +122,12 @@ impl State {
&self.color_model.bg_color
}
pub fn nvim(&self) -> RefMut<Neovim> {
RefMut::map(self.nvim.borrow_mut(), |n| n.nvim_mut())
pub fn nvim(&self) -> Option<RefMut<Neovim>> {
if self.nvim.borrow().is_initialized() {
Some(RefMut::map(self.nvim.borrow_mut(), |n| n.nvim_mut()))
} else {
None
}
}
pub fn nvim_clone(&self) -> Rc<RefCell<NeovimClient>> {
@ -151,37 +157,36 @@ impl State {
}
pub fn open_file(&self, path: &str) {
let mut nvim = self.nvim();
if let Some(mut nvim) = self.nvim() {
nvim.command(&format!("e {}", path)).report_err(&mut *nvim);
}
}
pub fn cd(&self, path: &str) {
let mut nvim = self.nvim();
if let Some(mut nvim) = self.nvim() {
nvim.command(&format!("cd {}", path)).report_err(&mut *nvim);
}
fn request_resize(&mut self) {
self.request_resize = true;
}
fn request_nvim_resize(&mut self) {
self.request_nvim_resize = true;
}
fn close_popup_menu(&self) {
if self.popup_menu.borrow().is_open() {
let mut nvim = self.nvim();
if let Some(mut nvim) = self.nvim() {
nvim.input("<Esc>").report_err(&mut *nvim);
}
}
}
fn queue_draw_area<M: AsRef<ModelRect>>(&mut self, rect_list: &[M]) {
// extends by items before, then after changes
let rects: Vec<_> = rect_list.iter().map(|rect| rect.as_ref().clone()).map(|mut rect| {
let rects: Vec<_> = rect_list
.iter()
.map(|rect| rect.as_ref().clone())
.map(|mut rect| {
rect.extend_by_items(&self.model);
rect
}).collect();
})
.collect();
self.update_dirty_glyphs();
@ -239,6 +244,38 @@ impl State {
self.im_context.reset();
}
fn resize_main_window(&mut self) {
match self.resize_state {
ResizeState::RequestNvimResize(_) => return,
_ => (),
}
let &CellMetrics {
line_height,
char_width,
..
} = self.font_ctx.cell_metrics();
let width = self.drawing_area.get_allocated_width();
let height = self.drawing_area.get_allocated_height();
let request_height = (self.model.rows as f64 * line_height) as i32;
let request_width = (self.model.columns as f64 * char_width) as i32;
if width != request_width || height != request_height {
self.resize_state = ResizeState::RequestWindowResize;
let window: gtk::Window = self.drawing_area
.get_toplevel()
.unwrap()
.downcast()
.unwrap();
let (win_width, win_height) = window.get_size();
let h_border = win_width - width;
let v_border = win_height - height;
window.resize(request_width + h_border, request_height + v_border);
}
}
}
pub struct UiState {
@ -419,11 +456,12 @@ impl Shell {
try_nvim_resize(&ref_state);
false
});
}
#[cfg(unix)]
pub fn redraw(&self, mode: &RepaintMode) {
self.state.borrow_mut().on_redraw(mode);
let ref_state = self.state.clone();
state.drawing_area.connect_size_allocate(
move |_, _| init_nvim(&ref_state),
);
}
#[cfg(unix)]
@ -445,7 +483,11 @@ impl Shell {
pub fn detach_ui(&mut self) {
let state = self.state.borrow();
state.nvim().ui_detach().expect("Error in ui_detach");
let nvim = state.nvim();
if let Some(mut nvim) = nvim {
nvim.ui_detach().expect("Error in ui_detach");
}
}
pub fn edit_paste(&self) {
@ -456,14 +498,19 @@ impl Shell {
"<Esc>\"*pa"
};
let mut nvim = state.nvim();
let nvim = state.nvim();
if let Some(mut nvim) = nvim {
nvim.input(paste_command).report_err(&mut *nvim);
}
}
pub fn edit_save_all(&self) {
let state = self.state.borrow();
let nvim = &mut *state.nvim();
nvim.command(":wa").report_err(nvim);
let nvim = state.nvim();
if let Some(mut nvim) = nvim {
nvim.command(":wa").report_err(&mut *nvim);
}
}
pub fn set_detach_cb<F>(&self, cb: Option<F>)
@ -544,15 +591,18 @@ fn mouse_input(shell: &mut State, input: &str, state: ModifierType, position: (f
char_width,
..
} = shell.font_ctx.cell_metrics();
let mut nvim = shell.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);
let nvim = shell.nvim();
if let Some(mut nvim) = nvim {
nvim.input(&input_str).expect(
"Can't send mouse input event",
);
}
}
fn gtk_button_release(ui_state: &mut UiState) -> Inhibit {
ui_state.mouse_pressed = false;
@ -567,15 +617,9 @@ fn gtk_motion_notify(shell: &mut State, ui_state: &mut UiState, ev: &EventMotion
}
fn gtk_draw(state_arc: &Arc<UiMutex<State>>, ctx: &cairo::Context) -> Inhibit {
if state_arc.borrow_mut().request_nvim_resize {
try_nvim_resize(state_arc);
}
init_nvim(state_arc);
let mut state = state_arc.borrow_mut();
let state = state_arc.borrow();
if state.nvim.borrow().is_initialized() {
request_window_resize(&mut *state);
render::render(
ctx,
state.cursor.as_ref().unwrap(),
@ -664,21 +708,6 @@ fn init_nvim_async(
});
}
fn init_nvim(state_arc: &Arc<UiMutex<State>>) {
let state = state_arc.borrow();
let mut nvim = state.nvim.borrow_mut();
if nvim.is_uninitialized() {
nvim.set_in_progress();
let (cols, rows) = state.calc_nvim_size();
let state_arc = state_arc.clone();
let options = state.options.clone();
thread::spawn(move || init_nvim_async(state_arc, options, cols, rows));
}
}
fn draw_initializing(state: &State, ctx: &cairo::Context) {
let layout = ctx.create_pango_layout();
let desc = state.get_font_desc();
@ -719,48 +748,33 @@ fn draw_initializing(state: &State, ctx: &cairo::Context) {
);
}
fn request_window_resize(state: &mut State) {
if !state.request_resize {
return;
}
if state.resize_timer.is_some() {
return;
}
fn init_nvim(state_ref: &Arc<UiMutex<State>>) {
let state = state_ref.borrow();
let mut nvim = state.nvim.borrow_mut();
if nvim.is_uninitialized() {
nvim.set_in_progress();
let &CellMetrics {
line_height,
char_width,
..
} = state.font_ctx.cell_metrics();
state.request_resize = false;
let (cols, rows) = state.calc_nvim_size();
let width = state.drawing_area.get_allocated_width();
let height = state.drawing_area.get_allocated_height();
let request_height = (state.model.rows as f64 * line_height) as i32;
let request_width = (state.model.columns as f64 * char_width) as i32;
if width != request_width || height != request_height {
let window: gtk::Window = state
.drawing_area
.get_toplevel()
.unwrap()
.downcast()
.unwrap();
let (win_width, win_height) = window.get_size();
let h_border = win_width - width;
let v_border = win_height - height;
window.resize(request_width + h_border, request_height + v_border);
let state_arc = state_ref.clone();
let options = state.options.clone();
thread::spawn(move || init_nvim_async(state_arc, options, cols, rows));
}
}
fn try_nvim_resize(state: &Arc<UiMutex<State>>) {
let mut state_ref = state.borrow_mut();
state_ref.request_nvim_resize = false;
if let Some(timer) = state_ref.resize_timer {
match state_ref.resize_state {
ResizeState::RequestWindowResize => {
state_ref.resize_state = ResizeState::Wait;
return;
}
ResizeState::RequestNvimResize(timer) => {
glib::source_remove(timer);
}
ResizeState::Wait => (),
}
if !state_ref.nvim.borrow().is_initialized() {
return;
@ -768,16 +782,19 @@ fn try_nvim_resize(state: &Arc<UiMutex<State>>) {
let (columns, rows) = state_ref.calc_nvim_size();
let state = state.clone();
state_ref.resize_timer = Some(glib::timeout_add(250, move || {
state_ref.resize_state = ResizeState::RequestNvimResize(gtk::timeout_add(250, move || {
let mut state_ref = state.borrow_mut();
state_ref.resize_timer = None;
state_ref.resize_state = ResizeState::Wait;
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) {
let nvim = state_ref.nvim();
if let Some(mut nvim) = nvim {
if let Err(err) = nvim.ui_try_resize(columns as u64, rows as u64) {
error!("Error trying resize nvim {}", err);
}
}
}
Continue(false)
}));
}
@ -804,7 +821,8 @@ impl RedrawEvents for State {
fn on_resize(&mut self, columns: u64, rows: u64) -> RepaintMode {
self.model = UiModel::new(rows, columns);
self.request_resize();
self.resize_main_window();
RepaintMode::Nothing
}
@ -813,7 +831,7 @@ impl RedrawEvents for State {
RepaintMode::All => {
self.update_dirty_glyphs();
self.drawing_area.queue_draw();
},
}
RepaintMode::Area(ref rect) => self.queue_draw_area(&[rect]),
RepaintMode::AreaList(ref list) => self.queue_draw_area(&list.list),
RepaintMode::Nothing => (),
@ -968,10 +986,12 @@ impl RedrawEvents for State {
impl GuiApi for State {
fn set_font(&mut self, font_desc: &str) {
self.set_font_desc(font_desc);
self.request_nvim_resize();
{
let mut settings = self.settings.borrow_mut();
settings.set_font_source(FontSource::Rpc);
}
self.set_font_desc(font_desc);
self.resize_main_window();
}
}

View File

@ -24,10 +24,7 @@ pub fn can_close_window(comps: &UiMutex<Components>, shell: &RefCell<Shell>) ->
}
}
fn show_not_saved_dlg(comps: &UiMutex<Components>,
shell: &Shell,
changed_bufs: &[String])
-> bool {
fn show_not_saved_dlg(comps: &UiMutex<Components>, shell: &Shell, changed_bufs: &[String]) -> bool {
let mut changed_files = changed_bufs
.iter()
.map(|n| if n.is_empty() { "<No name>" } else { n })
@ -35,24 +32,30 @@ fn show_not_saved_dlg(comps: &UiMutex<Components>,
changed_files.pop();
let flags = gtk::DIALOG_MODAL | gtk::DIALOG_DESTROY_WITH_PARENT;
let dlg = MessageDialog::new(Some(comps.borrow().window()),
let dlg = MessageDialog::new(
Some(comps.borrow().window()),
flags,
MessageType::Question,
ButtonsType::None,
&format!("Save changes to '{}'?", changed_files));
&format!("Save changes to '{}'?", changed_files),
);
const SAVE_ID: i32 = 0;
const CLOSE_WITHOUT_SAVE: i32 = 1;
const CANCEL_ID: i32 = 2;
dlg.add_buttons(&[("_Yes", SAVE_ID),
dlg.add_buttons(
&[
("_Yes", SAVE_ID),
("_No", CLOSE_WITHOUT_SAVE),
("_Cancel", CANCEL_ID)]);
("_Cancel", CANCEL_ID),
],
);
let res = match dlg.run() {
SAVE_ID => {
let state = shell.state.borrow();
let mut nvim = state.nvim();
let mut nvim = state.nvim().unwrap();
match nvim.command("wa") {
Err(ref err) => {
println!("Error: {}", err);
@ -72,32 +75,46 @@ fn show_not_saved_dlg(comps: &UiMutex<Components>,
fn get_changed_buffers(shell: &Shell) -> Result<Vec<String>, CallError> {
let state = shell.state.borrow();
let mut nvim = state.nvim();
let nvim = state.nvim();
if let Some(mut nvim) = nvim {
let buffers = nvim.list_bufs().unwrap();
Ok(buffers
Ok(
buffers
.iter()
.map(|buf| {
(match buf.get_option(&mut nvim, "modified") {
(
match buf.get_option(&mut nvim, "modified") {
Ok(Value::Boolean(val)) => val,
Ok(_) => {
println!("Value must be boolean");
false
}
Err(ref err) => {
println!("Something going wrong while getting buffer option: {}", err);
println!(
"Something going wrong while getting buffer option: {}",
err
);
false
}
},
match buf.get_name(&mut nvim) {
Ok(name) => name,
Err(ref err) => {
println!("Something going wrong while getting buffer name: {}", err);
println!(
"Something going wrong while getting buffer name: {}",
err
);
"<Error>".to_owned()
}
})
},
)
})
.filter(|e| e.0)
.map(|e| e.1)
.collect())
.collect(),
)
} else {
Ok(vec![])
}
}

View File

@ -27,13 +27,6 @@ impl Item {
}
}
#[cfg(test)]
pub fn set_offset(&mut self, offset: i32, length: i32, num_chars: i32) {
self.0.offset = offset;
self.0.length = length;
self.0.num_chars = num_chars;
}
pub fn analysis(&self) -> analysis::Analysis {
analysis::Analysis::from(&self.0.analysis)
}

View File

@ -231,32 +231,6 @@ mod tests {
assert_eq!(2, list.list.len());
}
#[test]
fn test_from_area() {
let rect = ModelRect::from_area(10.0, 5.0, 3.0, 3.0, 9.0, 17.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(10.0, 5.0, 0.0, 0.0, 10.0, 20.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(10.0, 5.0, 0.0, 0.0, 11.0, 21.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(2, rect.bot);
assert_eq!(2, rect.right);
}
#[test]
fn test_cursor_area() {
let mut model = UiModel::new(10, 20);

View File

@ -301,4 +301,32 @@ mod tests {
assert_eq!(5, width);
assert_eq!(10, height);
}
#[test]
fn test_from_area() {
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 3.0, 3.0, 9.0, 17.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 10.0, 20.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 11.0, 21.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(2, rect.bot);
assert_eq!(2, rect.right);
}
}