use super::ButtonContent;
use cursive_core::{
Cursive, impl_enabled,
Printer, Vec2, View, Rect,
direction::Direction,
view::CannotFocus,
event::{
Callback,
Event,
EventResult,
Key,
MouseButton,
MouseEvent
},
utils::markup::StyledString
};
use rust_utils::encapsulated;
#[derive(Clone)]
#[encapsulated]
pub struct AdvancedButton<D: Send + Sync + 'static = ()> {
title: ButtonContent,
callback: Callback,
enabled: bool,
has_brackets: bool,
width: usize,
#[getter(mutable, doc = "Return a reference to the data")]
#[setter(doc = "Set the data")]
data: D,
size_cache: Option<Vec2>
}
impl AdvancedButton {
#[must_use]
pub fn new<T: Into<StyledString>, F: Fn(&mut Cursive) + Send + Sync + 'static>(title: T, callback: F) -> AdvancedButton {
Self::new_with_data(title, (), callback)
}
}
impl<D: Send + Sync + 'static> AdvancedButton<D> {
impl_enabled!(self.enabled);
#[must_use]
pub fn new_with_data<T: Into<StyledString>, F: Fn(&mut Cursive) + Send + Sync + 'static>(title: T, data: D, callback: F) -> AdvancedButton<D> {
AdvancedButton {
title: ButtonContent::new(title),
width: 0,
callback: Callback::from_fn(callback),
has_brackets: false,
enabled: true,
data,
size_cache: None
}
}
pub fn show_brackets(&mut self, show: bool) {
self.size_cache = None;
self.has_brackets = show;
}
#[must_use]
pub fn brackets(mut self) -> Self {
self.has_brackets = true;
self
}
pub fn title(&self) -> &StyledString { self.title.get_content() }
pub fn set_title<T: Into<StyledString>>(&mut self, title: T) {
self.size_cache = None;
self.title.set_content(title);
}
pub fn set_callback<F: Fn(&mut Cursive) + Send + Sync + 'static>(&mut self, callback: F) { self.callback = Callback::from_fn(callback); }
}
impl<D: Send + Sync + 'static> View for AdvancedButton<D> {
fn draw(&self, printer: &Printer) {
self.title.draw(printer, (0, 0).into(), self.enabled, printer.focused, self.has_brackets);
}
fn required_size(&mut self, bound: Vec2) -> Vec2 {
if let Some(size) = self.size_cache {
if self.width > 0 { return size; }
}
self.title.fit_to_width(bound.x);
let size = self.title.size(self.has_brackets);
self.width = size.x;
size
}
fn layout(&mut self, size: Vec2) {
self.size_cache = Some(size);
self.title.fit_to_width(size.x);
}
fn on_event(&mut self, event: Event) -> EventResult {
if !self.enabled {
return EventResult::Ignored;
}
match event {
Event::Mouse {
event: MouseEvent::Release(MouseButton::Left),
position,
offset
} => {
let b_rect = Rect::from_size((0, 0),self.title.size(self.has_brackets));
if let Some(new_pos) = position.checked_sub(offset) {
if b_rect.contains(new_pos) {
EventResult::Consumed(Some(self.callback.clone()))
}
else { EventResult::Ignored }
}
else { EventResult::Ignored }
}
Event::Key(Key::Enter) => EventResult::Consumed(Some(self.callback.clone())),
Event::WindowResize => {
self.size_cache = None;
self.width = 0;
EventResult::Ignored
}
_ => EventResult::Ignored,
}
}
fn take_focus(&mut self, _: Direction) -> Result<EventResult, CannotFocus> { self.enabled.then(EventResult::consumed).ok_or(CannotFocus) }
}