mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
EditVIew: Add mutable and non-mutable callback methods
mutable callbacks disable recursive calls
This commit is contained in:
parent
9850e93125
commit
0bbc10706e
@ -3,6 +3,7 @@
|
|||||||
use {Cursive, Printer, With};
|
use {Cursive, Printer, With};
|
||||||
use direction::Direction;
|
use direction::Direction;
|
||||||
use event::{Callback, Event, EventResult, Key};
|
use event::{Callback, Event, EventResult, Key};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use theme::{ColorStyle, Effect};
|
use theme::{ColorStyle, Effect};
|
||||||
@ -74,7 +75,7 @@ pub struct EditView {
|
|||||||
|
|
||||||
/// Callback when the content is modified.
|
/// Callback when the content is modified.
|
||||||
///
|
///
|
||||||
/// Will be called with the current content and the cursor position
|
/// Will be called with the current content and the cursor position.
|
||||||
on_edit: Option<Rc<Fn(&mut Cursive, &str, usize)>>,
|
on_edit: Option<Rc<Fn(&mut Cursive, &str, usize)>>,
|
||||||
|
|
||||||
/// Callback when <Enter> is pressed.
|
/// Callback when <Enter> is pressed.
|
||||||
@ -136,25 +137,118 @@ impl EditView {
|
|||||||
self.enabled = true;
|
self.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a mutable callback to be called whenever the content is modified.
|
||||||
|
///
|
||||||
|
/// `callback` will be called with the view
|
||||||
|
/// content and the current cursor position.
|
||||||
|
///
|
||||||
|
/// *Warning*: this callback cannot be called recursively. If you somehow
|
||||||
|
/// trigger this callback again in the given closure, it will be ignored.
|
||||||
|
///
|
||||||
|
/// If you don't need a mutable closure but want the possibility of
|
||||||
|
/// recursive calls, see [`set_on_edit`](#method.set_on_edit).
|
||||||
|
pub fn set_on_edit_mut<F>(&mut self, callback: F)
|
||||||
|
where F: FnMut(&mut Cursive, &str, usize) + 'static
|
||||||
|
{
|
||||||
|
let callback = RefCell::new(callback);
|
||||||
|
// Here's the weird trick: if we're already borrowed,
|
||||||
|
// just ignored the callback.
|
||||||
|
self.set_on_edit(move |s, text, cursor| {
|
||||||
|
if let Ok(mut f) = callback.try_borrow_mut() {
|
||||||
|
// Beeeaaah that's ugly.
|
||||||
|
// Why do we need to manually dereference here?
|
||||||
|
(&mut *f)(s, text, cursor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets a callback to be called whenever the content is modified.
|
/// Sets a callback to be called whenever the content is modified.
|
||||||
///
|
///
|
||||||
/// `callback` will be called with the view
|
/// `callback` will be called with the view
|
||||||
/// content and the current cursor position.
|
/// content and the current cursor position.
|
||||||
pub fn on_edit<F>(mut self, callback: F) -> Self
|
///
|
||||||
|
/// This callback can safely trigger itself recursively if needed
|
||||||
|
/// (for instance if you call `on_event` on this view from the callback).
|
||||||
|
///
|
||||||
|
/// If you need a mutable closure and don't care about the recursive
|
||||||
|
/// aspect, see [`set_on_edit_mut`](#method.set_on_edit_mut).
|
||||||
|
pub fn set_on_edit<F>(&mut self, callback: F)
|
||||||
where F: Fn(&mut Cursive, &str, usize) + 'static
|
where F: Fn(&mut Cursive, &str, usize) + 'static
|
||||||
{
|
{
|
||||||
self.on_edit = Some(Rc::new(callback));
|
self.on_edit = Some(Rc::new(callback));
|
||||||
self
|
}
|
||||||
|
|
||||||
|
/// Sets a mutable callback to be called whenever the content is modified.
|
||||||
|
///
|
||||||
|
/// Chainable variant. See [`set_on_edit_mut`](#method.set_on_edit_mut).
|
||||||
|
pub fn on_edit_mut<F>(self, callback: F) -> Self
|
||||||
|
where F: FnMut(&mut Cursive, &str, usize) + 'static
|
||||||
|
{
|
||||||
|
self.with(|v| v.set_on_edit_mut(callback))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets a callback to be called whenever the content is modified.
|
||||||
|
///
|
||||||
|
/// Chainable variant. See [`set_on_edit`](#method.set_on_edit).
|
||||||
|
pub fn on_edit<F>(self, callback: F) -> Self
|
||||||
|
where F: Fn(&mut Cursive, &str, usize) + 'static
|
||||||
|
{
|
||||||
|
self.with(|v| v.set_on_edit(callback))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets a mutable callback to be called when `<Enter>` is pressed.
|
||||||
|
///
|
||||||
|
/// `callback` will be given the content of the view.
|
||||||
|
///
|
||||||
|
/// *Warning*: this callback cannot be called recursively. If you somehow
|
||||||
|
/// trigger this callback again in the given closure, it will be ignored.
|
||||||
|
///
|
||||||
|
/// If you don't need a mutable closure but want the possibility of
|
||||||
|
/// recursive calls, see [`set_on_submit`](#method.set_on_submit).
|
||||||
|
pub fn set_on_submit_mut<F>(&mut self, callback: F)
|
||||||
|
where F: FnMut(&mut Cursive, &str) + 'static
|
||||||
|
{
|
||||||
|
// TODO: don't duplicate all those methods.
|
||||||
|
// Instead, have some generic function immutify()
|
||||||
|
// or something that wraps a FnMut closure.
|
||||||
|
let callback = RefCell::new(callback);
|
||||||
|
self.set_on_submit(move |s, text| if let Ok(mut f) =
|
||||||
|
callback.try_borrow_mut() {
|
||||||
|
(&mut *f)(s, text);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a callback to be called when `<Enter>` is pressed.
|
/// Sets a callback to be called when `<Enter>` is pressed.
|
||||||
///
|
///
|
||||||
/// `callback` will be given the content of the view.
|
/// `callback` will be given the content of the view.
|
||||||
pub fn on_submit<F>(mut self, callback: F) -> Self
|
///
|
||||||
|
/// This callback can safely trigger itself recursively if needed
|
||||||
|
/// (for instance if you call `on_event` on this view from the callback).
|
||||||
|
///
|
||||||
|
/// If you need a mutable closure and don't care about the recursive
|
||||||
|
/// aspect, see [`set_on_submit_mut`](#method.set_on_submit_mut).
|
||||||
|
pub fn set_on_submit<F>(&mut self, callback: F)
|
||||||
where F: Fn(&mut Cursive, &str) + 'static
|
where F: Fn(&mut Cursive, &str) + 'static
|
||||||
{
|
{
|
||||||
self.on_submit = Some(Rc::new(callback));
|
self.on_submit = Some(Rc::new(callback));
|
||||||
self
|
}
|
||||||
|
|
||||||
|
/// Sets a mutable callback to be called when `<Enter>` is pressed.
|
||||||
|
///
|
||||||
|
/// Chainable variant.
|
||||||
|
pub fn on_submit_mut<F>(self, callback: F) -> Self
|
||||||
|
where F: FnMut(&mut Cursive, &str) + 'static
|
||||||
|
{
|
||||||
|
self.with(|v| v.set_on_submit_mut(callback))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets a callback to be called when `<Enter>` is pressed.
|
||||||
|
///
|
||||||
|
/// Chainable variant.
|
||||||
|
pub fn on_submit<F>(self, callback: F) -> Self
|
||||||
|
where F: Fn(&mut Cursive, &str) + 'static
|
||||||
|
{
|
||||||
|
self.with(|v| v.set_on_submit(callback))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable or disable this view.
|
/// Enable or disable this view.
|
||||||
@ -239,9 +333,10 @@ impl EditView {
|
|||||||
// Look at the content before the cursor (we will print its tail).
|
// Look at the content before the cursor (we will print its tail).
|
||||||
// From the end, count the length until we reach `available`.
|
// From the end, count the length until we reach `available`.
|
||||||
// Then sum the byte lengths.
|
// Then sum the byte lengths.
|
||||||
let suffix_length =
|
let suffix_length = simple_suffix(&self.content[self.offset..
|
||||||
simple_suffix(&self.content[self.offset..self.cursor],
|
self.cursor],
|
||||||
available).length;
|
available)
|
||||||
|
.length;
|
||||||
self.offset = self.cursor - suffix_length;
|
self.offset = self.cursor - suffix_length;
|
||||||
// Make sure the cursor is in view
|
// Make sure the cursor is in view
|
||||||
assert!(self.cursor >= self.offset);
|
assert!(self.cursor >= self.offset);
|
||||||
@ -250,8 +345,8 @@ impl EditView {
|
|||||||
|
|
||||||
// If we have too much space
|
// If we have too much space
|
||||||
if self.content[self.offset..].width() < self.last_length {
|
if self.content[self.offset..].width() < self.last_length {
|
||||||
let suffix_length = simple_suffix(&self.content,
|
let suffix_length =
|
||||||
self.last_length - 1).length;
|
simple_suffix(&self.content, self.last_length - 1).length;
|
||||||
self.offset = self.content.len() - suffix_length;
|
self.offset = self.content.len() - suffix_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,9 +488,7 @@ impl View for EditView {
|
|||||||
Event::Key(Key::Enter) if self.on_submit.is_some() => {
|
Event::Key(Key::Enter) if self.on_submit.is_some() => {
|
||||||
let cb = self.on_submit.clone().unwrap();
|
let cb = self.on_submit.clone().unwrap();
|
||||||
let content = self.content.clone();
|
let content = self.content.clone();
|
||||||
return EventResult::with_cb(move |s| {
|
return EventResult::with_cb(move |s| { cb(s, &content); });
|
||||||
cb(s, &content);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => return EventResult::Ignored,
|
_ => return EventResult::Ignored,
|
||||||
}
|
}
|
||||||
@ -404,13 +497,11 @@ impl View for EditView {
|
|||||||
|
|
||||||
let cb = self.on_edit.clone().map(|cb| {
|
let cb = self.on_edit.clone().map(|cb| {
|
||||||
|
|
||||||
// Get a new Rc on it
|
// Get a new Rc on the content
|
||||||
let content = self.content.clone();
|
let content = self.content.clone();
|
||||||
let cursor = self.cursor;
|
let cursor = self.cursor;
|
||||||
|
|
||||||
Callback::from_fn(move |s| {
|
Callback::from_fn(move |s| { cb(s, &content, cursor); })
|
||||||
cb(s, &content, cursor);
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
EventResult::Consumed(cb)
|
EventResult::Consumed(cb)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user