use crate::core::{Handle, Pixels};
use crate::view::any_element::AnyElement;
use crate::view::div::{Div, div};
use crate::view::element::{IntoElement, ParentElement};
use crate::view::media::Svg;
use crate::view::recipes::Recipes;
use crate::view::state::State;
use crate::view::styled::Styled;
use crate::view::text_element::Text;
use crate::view::ui::Ui;
use crate::view::uniform_list::uniform_list;
use crate::widgets::{
Button, IconName, InputChanged, InputSubmitted, TextInput, empty_state, field, icon, page_header, section,
setting_row, switch,
};
struct BoundInput {
state: State<String>,
}
struct SubmitBinding {
action: Box<dyn Fn(String)>,
}
impl<'a> Ui<'a> {
pub fn text(&self, content: impl Into<String>) -> Text {
crate::view::text_element::text(content)
}
pub fn title(&self, content: impl Into<String>) -> Div {
let content: String = content.into();
div().heading().child(content)
}
pub fn caption(&self, content: impl Into<String>) -> Div {
let content: String = content.into();
div().caption().child(content)
}
pub fn button(&self, label: impl Into<String>) -> Button {
Button::new(label)
}
pub fn icon(&self, name: IconName) -> Svg {
icon(name)
}
pub fn page(&self) -> Div {
div().page()
}
pub fn card(&self) -> Div {
div().card()
}
pub fn row(&self) -> Div {
div().flex_row().items_center()
}
pub fn column(&self) -> Div {
div().flex_col()
}
pub fn spacer(&self) -> Div {
div().flex_1()
}
pub fn list<R: IntoElement>(
&mut self,
key: &'static str,
count: usize,
row_height: Pixels,
mut row: impl FnMut(&mut Ui, usize) -> R,
) -> AnyElement {
let list = self.widgets.uniform_list(key);
let mut ui = Ui {
theme: self.theme,
viewport: self.viewport,
entities: &mut *self.entities,
state: &mut *self.state,
widgets: &mut *self.widgets,
root_id: self.root_id,
theme_request: self.theme_request,
};
uniform_list(&list, count, row_height, |range| range.map(|index| row(&mut ui, index).into_element()).collect())
.into_element()
}
pub fn section(&self, title: impl Into<String>, hint: impl Into<String>) -> Div {
section(title, hint)
}
pub fn setting_row(&self, title: impl Into<String>, hint: impl Into<String>, control: impl IntoElement) -> Div {
setting_row(title, hint, control)
}
pub fn page_header(&self, title: impl Into<String>, subtitle: impl Into<String>) -> Div {
page_header(title, subtitle)
}
pub fn field(&self, label: impl Into<String>, control: impl IntoElement) -> Div {
field(label, control)
}
pub fn empty_state(&self, title: impl Into<String>, hint: impl Into<String>) -> Div {
empty_state(title, hint)
}
fn ensure_text_input(&mut self, placeholder: &str, state: &State<String>) -> Handle<TextInput> {
let key = state.key();
let input = match self.widgets.text_input(key) {
Some(input) => input,
None => {
let focus = self.entities.focus.new_handle();
let input = self.entities.insert(TextInput::new(focus).placeholder(placeholder.to_owned()));
let binding = self.entities.insert(BoundInput { state: state.clone() });
self.entities.subscribe(input, binding, |binding, event: &InputChanged, _| {
binding.state.write(|text| *text = event.0.clone());
});
self.widgets.insert_text_input(key, input);
input
}
};
state.read(|text| {
self.entities.update(input, |input, _| {
if input.text() != text {
input.set_text(text.clone());
}
});
});
input
}
pub fn text_field(&mut self, label: impl Into<String>, state: &State<String>) -> Div {
let label: String = label.into();
let input = self.ensure_text_input(&label, state);
let element = self.child(input);
field(label, element)
}
pub fn text_field_submit(
&mut self,
label: impl Into<String>,
state: &State<String>,
on_submit: impl Fn(String) + 'static,
) -> Div {
let label: String = label.into();
let key = state.key();
let input = self.ensure_text_input(&label, state);
if !self.widgets.has_text_submit(key) {
let state_clone = state.clone();
let root_id = self.root_id;
let submit = self.entities.insert(SubmitBinding { action: Box::new(on_submit) });
self.entities.subscribe(input, submit, move |submit, _: &InputSubmitted, cx| {
if let Some(trimmed) = state_clone.take_trimmed() {
cx.update(input, |input, _| input.set_text(String::new()));
(submit.action)(trimmed);
cx.mark_dirty(root_id);
}
});
self.widgets.mark_text_submit(key);
}
let element = self.child(input);
field(label, element)
}
pub fn switch(&self, state: &State<bool>) -> AnyElement {
switch(state.get(), state.key(), state.toggle())
}
}