Add getters & other utility methods to Dialog (#541)

* Allow taking the content of a dialog without destroying it by replacing it with another view.

* Add getters for all three ways of mutating padding (`Margins` struct, LRTB tuple, and individual fields)

* Allow setting focus

* Add a getter for the title of the dialog

* Add getter for title position

* Add immutable button iterator for `Dialog`

* Rename `buttons_mut` to fit with `iter_buttons_mut`.

* Add getter for horizontal alignment property

* Remove `replace_content` and replace it with just having `set_content` return the previous view.

* Actually clamp dialog focus rather than forcibly unclamping it

* Use the existing convention for button iterators rather than the `iter`/`iter_mut` convention

* Remove extraneous padding getters

* Remove import of `std::mem::replace`
This commit is contained in:
kmeisthax 2021-02-05 10:44:53 -07:00 committed by GitHub
parent aedfc9e0c1
commit 06d64be0a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -10,7 +10,7 @@ use crate::{
Cursive, Printer, Vec2, With, Cursive, Printer, Vec2, With,
}; };
use std::cell::Cell; use std::cell::Cell;
use std::cmp::max; use std::cmp::{max, min};
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
/// Identifies currently focused element in [`Dialog`]. /// Identifies currently focused element in [`Dialog`].
@ -117,7 +117,9 @@ impl Dialog {
/// .button("Quit", |s| s.quit()); /// .button("Quit", |s| s.quit());
/// ``` /// ```
pub fn content<V: IntoBoxedView>(self, view: V) -> Self { pub fn content<V: IntoBoxedView>(self, view: V) -> Self {
self.with(|s| s.set_content(view)) self.with(|s| {
s.set_content(view);
})
} }
/// Gets the content of this dialog. /// Gets the content of this dialog.
@ -161,10 +163,15 @@ impl Dialog {
/// Sets the content for this dialog. /// Sets the content for this dialog.
/// ///
/// Previous content will be dropped. /// Previous content will be returned.
pub fn set_content<V: IntoBoxedView>(&mut self, view: V) { pub fn set_content<V: IntoBoxedView>(&mut self, view: V) -> Box<dyn View> {
self.content = LastSizeView::new(BoxedView::boxed(view));
self.invalidate(); self.invalidate();
std::mem::replace(
&mut self.content,
LastSizeView::new(BoxedView::boxed(view)),
)
.view
.unwrap()
} }
/// Convenient method to create a dialog with a simple text content. /// Convenient method to create a dialog with a simple text content.
@ -244,6 +251,11 @@ impl Dialog {
self self
} }
/// Gets the horizontal alignment for the buttons.
pub fn get_h_align(&self) -> HAlign {
self.align.h
}
/* /*
* Commented out because currently un-implemented. * Commented out because currently un-implemented.
* *
@ -293,6 +305,11 @@ impl Dialog {
self.invalidate(); self.invalidate();
} }
/// Get the title of the dialog.
pub fn get_title(&self) -> &str {
&self.title
}
/// Sets the horizontal position of the title in the dialog. /// Sets the horizontal position of the title in the dialog.
/// The default position is `HAlign::Center` /// The default position is `HAlign::Center`
pub fn title_position(self, align: HAlign) -> Self { pub fn title_position(self, align: HAlign) -> Self {
@ -305,6 +322,11 @@ impl Dialog {
self.title_position = align; self.title_position = align;
} }
/// Gets the alignment of the title
pub fn get_title_position(&self) -> HAlign {
self.title_position
}
/// Sets the padding in the dialog (around content and buttons). /// Sets the padding in the dialog (around content and buttons).
/// ///
/// # Examples /// # Examples
@ -319,6 +341,11 @@ impl Dialog {
self.with(|s| s.set_padding(padding)) self.with(|s| s.set_padding(padding))
} }
/// Gets the padding in the dialog (around content and buttons).
pub fn get_padding(&self) -> Margins {
self.padding
}
/// Sets the padding in the dialog. /// Sets the padding in the dialog.
/// ///
/// Takes Left, Right, Top, Bottom fields. /// Takes Left, Right, Top, Bottom fields.
@ -379,7 +406,12 @@ impl Dialog {
self.padding.right = padding; self.padding.right = padding;
} }
/// Returns an iterator on this buttons for this dialog. /// Iterate the buttons of this dialog.
pub fn buttons(&self) -> impl Iterator<Item = &Button> {
self.buttons.iter().map(|b| &b.button.view)
}
/// Mutably iterate the buttons of this dialog.
pub fn buttons_mut(&mut self) -> impl Iterator<Item = &mut Button> { pub fn buttons_mut(&mut self) -> impl Iterator<Item = &mut Button> {
self.invalidate(); self.invalidate();
self.buttons.iter_mut().map(|b| &mut b.button.view) self.buttons.iter_mut().map(|b| &mut b.button.view)
@ -390,6 +422,28 @@ impl Dialog {
self.focus self.focus
} }
/// Change the current focus of the dialog.
///
/// Please be considerate of the context from which focus is being stolen
/// when programmatically moving focus. For example, moving focus to a
/// button when a user is typing something into an `EditView` would cause
/// them to accidentally activate the button.
///
/// The given dialog focus will be clamped to a valid range. For example,
/// attempting to focus a button that no longer exists will instead focus
/// one that does (or the content, if no buttons exist).
pub fn set_focus(&mut self, new_focus: DialogFocus) {
self.focus = match new_focus {
DialogFocus::Content => DialogFocus::Content,
DialogFocus::Button(_) if self.buttons.is_empty() => {
DialogFocus::Content
}
DialogFocus::Button(c) => {
DialogFocus::Button(min(c, self.buttons.len()))
}
}
}
// Private methods // Private methods
// An event is received while the content is in focus // An event is received while the content is in focus