use std::sync::LazyLock;
use crate::prelude::*;
pub use self::builder::ButtonBuilder as Builder;
pub type Button <'element> =
Widget <'element, Switch, model::Component, view::Component>;
pub static CONTROLS : LazyLock <Controls> = LazyLock::new (||
controls::Builder::new()
.buttons (vec![
controls::button::Builtin::ButtonPush,
controls::button::Builtin::ButtonRelease
].into_iter().map (Into::into).collect::<Vec <_>>().into())
.build()
);
pub fn push (
release : &controls::button::Release,
elements : &Tree <Element>,
frame_id : &NodeId,
action_buffer : &mut Vec <(NodeId, Action)>
) {
log::trace!("push...");
let frame = elements.get_element (frame_id);
let mut frame_children = elements.children_ids (frame_id).unwrap();
let button_id = frame_children.next().unwrap();
let label_id = frame_children
.find (|node_id| Textbox::try_get (elements, node_id).is_ok());
let Widget (switch, _, _) = Button::try_get (elements, button_id).unwrap();
let toggle = switch.toggle;
if toggle && switch.state == switch::State::On {
return self::release (&None, elements, frame_id, action_buffer)
}
let mut switch = switch.clone();
let (exit, (enter, appearances, label)) = switch.on();
let update_switch = Box::new (
|controller : &mut Controller| controller.component = switch.into());
action_buffer
.push ((button_id.clone(), Action::ModifyController (update_switch)));
let appearance = Appearance {
sound: None, .. appearances.get (frame.controller.state.clone()).clone()
};
let update_controller = Box::new (
|controller : &mut Controller| controller.appearances = appearances);
let update_view = Box::new (
|view : &mut View| view.appearance = appearance);
action_buffer
.push ((frame_id.clone(), Action::ModifyController (update_controller)));
action_buffer
.push ((frame_id.clone(), Action::ModifyView (update_view)));
if let Some (trigger) = exit {
let target = trigger.target.as_ref().unwrap_or (button_id);
trigger.control_fun.0 (release, elements, target, action_buffer)
}
if let Some (textbox_id) = label_id {
action_buffer.push ((textbox_id.clone(), Action::Destroy))
}
if let Some (label) = label {
let textbox =
textbox::WithFrameBuilder::<application::Default>::new (elements, frame_id)
.text (label)
.build_element();
action_buffer.push ((frame_id.clone(),
Action::create_singleton (textbox, CreateOrder::Append)))
}
if let Some (trigger) = enter {
let target = trigger.target.as_ref().unwrap_or (button_id);
trigger.control_fun.0 (release, elements, target, action_buffer)
}
if !toggle {
if let Some (release) = release {
release.borrow_mut().push (
(controls::button::Builtin::ButtonRelease.into(), frame_id.clone()));
}
}
log::trace!("...push");
}
pub fn release (
_ : &controls::button::Release,
elements : &Tree <Element>,
frame_id : &NodeId,
action_buffer : &mut Vec <(NodeId, Action)>
) {
log::trace!("release...");
let frame = elements.get_element (frame_id);
let mut frame_children = elements.children_ids (frame_id).unwrap();
let button_id = frame_children.next().unwrap();
let label_id = frame_children
.find (|node_id| Textbox::try_get (elements, node_id).is_ok());
let Widget (switch, _, _) = Button::try_get (elements, button_id).unwrap();
let mut switch = switch.clone();
let (exit, (enter, appearances, label)) = switch.off();
if let Some (trigger) = exit {
let target = trigger.target.as_ref().unwrap_or (button_id);
trigger.control_fun.0 (&None, elements, target, action_buffer)
}
if let Some (textbox_id) = label_id {
action_buffer.push ((textbox_id.clone(), Action::Destroy))
}
if let Some (label) = label {
let textbox =
textbox::WithFrameBuilder::<application::Default>::new (elements, frame_id)
.text (label)
.build_element();
action_buffer.push ((frame_id.clone(),
Action::create_singleton (textbox, CreateOrder::Append)))
}
if let Some (trigger) = enter {
let target = trigger.target.as_ref().unwrap_or (button_id);
trigger.control_fun.0 (&None, elements, target, action_buffer)
}
let update_switch = Box::new (
|controller : &mut Controller| controller.component = switch.into());
action_buffer
.push ((button_id.clone(), Action::ModifyController (update_switch)));
let appearance = Appearance {
sound: None,
.. appearances.get (frame.controller.state.clone()).clone()
};
let update_controller = Box::new (
|controller : &mut Controller| controller.appearances = appearances);
let update_view = Box::new (
|view : &mut View| view.appearance = appearance);
action_buffer
.push ((frame_id.clone(), Action::ModifyController (update_controller)));
action_buffer
.push ((frame_id.clone(), Action::ModifyView (update_view)));
log::trace!("...release");
}
mod builder {
use derive_builder::Builder;
use crate::prelude::*;
#[derive(Builder)]
#[builder(public, pattern="owned", build_fn(private), setter(strip_option))]
struct Button <'a, A : Application> {
elements : &'a Tree <Element>,
parent_id : &'a NodeId,
#[builder(default)]
bindings : Option <&'a Bindings <A>>,
#[builder(default)]
callback_id : Option <application::CallbackId>,
#[builder(default)]
controls : Option <Controls>,
#[builder(default)]
frame_layout : Layout,
#[builder(default)]
frame_border : Option <Border>,
#[builder(default)]
model_data : Option <model::Component>,
#[builder(default)]
name : Option <String>,
#[builder(default)]
switch : Switch
}
impl <'a, A : Application> ButtonBuilder <'a, A> {
pub const fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
ButtonBuilder {
elements: Some (elements),
parent_id: Some (parent_id),
bindings: None,
callback_id: None,
controls: None,
frame_border: None,
frame_layout: None,
model_data: None,
name: None,
switch: None
}
}
}
impl <A : Application> BuildActions for ButtonBuilder <'_, A> {
fn build_actions (self) -> Vec<(NodeId, Action)> {
use std::convert::TryInto;
use crate::tree::InsertBehavior;
log::trace!("build actions...");
let Button {
elements, parent_id, bindings, callback_id, controls, frame_border,
frame_layout, model_data, name, switch
} = self.build()
.map_err(|err| log::error!("button builder error: {err:?}")).unwrap();
let bindings_empty = Bindings::empty();
let bindings = bindings.unwrap_or (&bindings_empty);
let mut out = vec![];
let (mut subtree, order) = {
let mut actions = {
let mut frame = frame::Builder::new (elements, parent_id)
.appearances (switch.appearances().clone())
.bindings (bindings)
.layout (frame_layout);
set_option!(frame, border, frame_border);
frame.build_actions()
};
out.extend (actions.drain (1..));
debug_assert_eq!(actions.len(), 1);
actions.pop().unwrap().1.try_into().unwrap()
};
let frame_id = subtree.root_node_id().unwrap().clone();
subtree.get_mut (&frame_id).unwrap().data_mut().controller.add_bindings (
&bindings.get_bindings (controls.as_ref().unwrap_or (&super::CONTROLS))
);
let label = switch.label().clone();
let button = {
let controller = Controller {
component: switch.into(),
focus_top: false,
.. Controller::default()
};
let model = {
let component = model_data.unwrap_or_else (Default::default);
Model { callback_id, component }
};
let name = name.unwrap_or ("Button".to_string());
Element::new (name, controller, model, View::default())
};
let _ = subtree
.insert (Node::new (button), InsertBehavior::UnderNode (&frame_id))
.unwrap();
if let Some (label) = label {
let textbox = textbox::WithFrameBuilder::<A>::new (&subtree, &frame_id)
.text (label)
.build_element();
let _ = subtree
.insert (Node::new (textbox), InsertBehavior::UnderNode (&frame_id))
.unwrap();
}
out.push ((parent_id.clone(), Action::Create (subtree, order)));
log::trace!("...build actions");
out
}
}
}