use std::convert::TryFrom;
use std::sync::{Arc, LazyLock, RwLock};
use key_vec::KeyVec;
use log;
use derive_more::{From, TryInto};
use crate::prelude::*;
pub mod controller;
pub mod model;
pub mod view;
pub use self::controller::Controller;
pub use self::model::Model;
pub use self::view::View;
pub static POINTER : LazyLock <Arc <RwLock <input::Pointer>>> = LazyLock::new (||
Arc::new (RwLock::new (input::Pointer::default())));
#[derive(Debug)]
pub struct Interface <A=application::Default, P=presentation::Headless> where
A : Application,
P : Presentation
{
pub presentation : P,
elements : Tree <Element>,
focused_id : NodeId,
input_buffer : Option <Vec <Input>>,
action_buffer : Option <Vec <(NodeId, Action)>>,
display_buffer : Vec <(NodeId, Display)>,
event_buffer : Vec <(NodeId, Event)>,
_phantom : std::marker::PhantomData <A>
}
#[derive(Clone, Debug)]
pub struct Element {
pub name : String,
pub controller : Controller,
pub model : Model,
pub view : View
}
#[derive(From, TryInto)]
pub enum Action {
Create (Tree <Element>, CreateOrder),
ModifyController (Box <dyn FnOnce (&mut Controller)>),
ModifyModel (Box <dyn FnOnce (&mut Model)>),
ModifyView (Box <dyn FnOnce (&mut View)>),
SubmitCallback (application::CallbackId),
Focus,
Enable,
Disable,
Destroy,
ReleaseButtons
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum CreateOrder {
#[default]
Append,
Prepend,
NthSibling (u32)
}
impl <A, P> Interface <A, P> where
A : Application,
P : Presentation
{
pub fn with_root (mut root : Element) -> Self {
log::trace!("with_root...");
root.focus();
let elements = TreeBuilder::new().with_root (Node::new (root.clone())).build();
let focused_id = elements.root_node_id().unwrap().clone();
let presentation = P::with_root (root.view, focused_id.clone());
let input_buffer = Some (vec![]);
let action_buffer = Some (vec![]);
let display_buffer = vec![];
let event_buffer = vec![];
log::trace!("...with_root");
Interface {
elements, focused_id, presentation, input_buffer, display_buffer, action_buffer,
event_buffer, _phantom: std::marker::PhantomData
}
}
#[inline]
#[must_use]
#[expect(mismatched_lifetime_syntaxes)]
pub fn action (&mut self, node_id : &NodeId, action : Action)
-> std::vec::Drain <(NodeId, Event)>
{
self.handle_action (action, node_id);
self.event_buffer.drain(..)
}
#[inline]
#[must_use]
#[expect(mismatched_lifetime_syntaxes)]
pub fn actions (&mut self, actions : Vec <(NodeId, Action)>)
-> std::vec::Drain <(NodeId, Event)>
{
for (node_id, action) in actions.into_iter() {
self.handle_action (action, &node_id);
}
self.event_buffer.drain(..)
}
#[must_use]
#[expect(mismatched_lifetime_syntaxes)]
pub fn update (&mut self) -> std::vec::Drain <(NodeId, Event)> {
log::trace!("update...");
let mut action_buffer = self.action_buffer.take().unwrap();
let mut input_buffer = self.input_buffer.take().unwrap();
debug_assert!(action_buffer.is_empty());
debug_assert!(input_buffer.is_empty());
self.presentation.get_input (&mut input_buffer);
#[expect(clippy::iter_with_drain)]
for input in input_buffer.drain(..) {
log::trace!("input: {input:?}");
if let Input::Pointer (pointer) = &input {
*POINTER.write().unwrap() = pointer.clone()
}
let focused_id = self.focused_element_id().clone();
let focused = self.focused_element();
let button_release = match focused.controller.handle_input::<A> (
input, &self.elements, &focused_id, &mut action_buffer
) {
Ok (result) => result,
Err (mut input) => {
debug_assert!(action_buffer.is_empty());
let mut button_release = None;
let input_mask = (&input).into();
if !focused.controller.bubble_trap.intersects (input_mask) {
for ancestor_id in self.elements.ancestor_ids (&focused_id).unwrap() {
let ancestor = self.get_element (ancestor_id);
input = match ancestor.controller.handle_input::<A> (
input, &self.elements, ancestor_id, &mut action_buffer
) {
Err (input) =>
if ancestor.controller.bubble_trap.intersects (input_mask) {
break
} else {
input
}
Ok (result) => {
button_release = result;
break
}
};
}
}
button_release
}
};
for (node_id, action) in action_buffer.drain(..) {
self.handle_action (action, &node_id);
}
if let Some (button_release) = button_release {
match button_release {
ButtonRelease::Insert (input, controls) =>
for (control, node_id) in controls {
let element = self.get_element_mut (&node_id);
element.controller.release_button_insert (input, control);
}
ButtonRelease::Remove (input, node_id) => {
let element = self.get_element_mut (&node_id);
element.controller.release_button_remove (input);
}
}
}
}
debug_assert!(action_buffer.is_empty());
debug_assert!(input_buffer.is_empty());
self.action_buffer = Some (action_buffer);
self.input_buffer = Some (input_buffer);
log::trace!("...update");
self.event_buffer.drain(..)
}
#[inline]
pub fn display (&mut self) {
log::trace!("display...");
self.presentation.display_view (&self.elements, self.display_buffer.drain(..));
log::trace!("...display");
}
#[inline]
pub const fn elements (&self) -> &Tree <Element> {
&self.elements
}
#[inline]
pub fn root (&self) -> &Element {
self.root_node().data()
}
pub fn root_node (&self) -> &Node <Element> {
self.elements.get (self.root_id()).unwrap()
}
#[inline]
pub fn root_id (&self) -> &NodeId {
self.elements.root_node_id().unwrap()
}
#[inline]
pub fn get_element (&self, node_id : &NodeId) -> &Element {
self.elements.get_element (node_id)
}
#[inline]
pub fn get_element_mut (&mut self, node_id : &NodeId) -> &mut Element {
self.elements.get_element_mut (node_id)
}
#[inline]
pub const fn focused_element_id (&self) -> &NodeId {
&self.focused_id
}
#[inline]
pub fn focused_element (&self) -> &Element {
self.get_element (&self.focused_id)
}
#[inline]
pub fn focused_element_mut (&mut self) -> &mut Element {
let focused_id = self.focused_id.clone();
self.get_element_mut (&focused_id)
}
#[inline]
pub fn print_elements_tree (&self) {
let mut s = String::new();
self.elements.write_formatted (&mut s).unwrap();
println!("elements:\n{s}");
}
#[inline]
pub fn print_elements_tree_names (&self) {
let mut s = String::new();
self.elements.write_formatted_names (&mut s).unwrap();
println!("elements:\n{s}");
}
pub fn keyboard_map (&self)
-> KeyVec <input::Button, Option <controls::button::Control <A::ButtonControls>>>
{
use strum::IntoEnumIterator;
let mut out = KeyVec::new();
let focused = self.focused_element();
let focused_id = self.focused_element_id();
for modifier_bits in 0..16u8 {
let modifiers = input::Modifiers::from_bits (modifier_bits).unwrap();
'keycodes: for keycode in input::button::Keycode::iter() {
let input = input::Button::from (keycode).with_modifiers (modifiers);
if let Ok (index) = focused.controller.input_map.buttons
.binary_search_by_key (&&input, |(b, _)| b)
{
let (b, control) = &focused.controller.input_map.buttons[index];
if b.modifiers.contains (input::Modifiers::ANY) {
}
out.insert (input, Some ((*control).into()));
} else {
let input_mask = (&Input::Button (input, input::button::State::Pressed)).into();
if !focused.controller.bubble_trap.intersects (input_mask) {
for ancestor_id in self.elements.ancestor_ids (focused_id).unwrap() {
let ancestor = self.get_element (ancestor_id);
if let Ok(index) = ancestor.controller.input_map.buttons
.binary_search_by_key (&&input, |(b, _)| b)
{
let (b, control) = &ancestor.controller.input_map.buttons[index];
if b.modifiers.contains (input::Modifiers::ANY) {
}
out.insert (input, Some ((*control).into()));
continue 'keycodes
}
}
}
out.insert (input, None);
}
}
}
out
}
pub fn create_singleton (&mut self,
parent_id : &NodeId,
element : Element,
order : CreateOrder
) -> NodeId {
match self.action (parent_id, Action::create_singleton (element, order))
.next().unwrap()
{
(_, Event::Create (_, new_id, _)) => new_id,
_ => unreachable!()
}
}
fn handle_action (&mut self, action : Action, node_id : &NodeId) {
use controller::component::{Kind, Selection};
log::trace!("handle_action...");
log::trace!("action: {action:?}");
match action {
Action::Create (elements, order) => {
#[cfg(debug_assertions)]
for element in elements.traverse_level_order (elements.root_node_id().unwrap())
.unwrap()
{
debug_assert_eq!(&element.data().view.appearance,
element.data().controller.get_appearance());
}
self.splice_subtree (
&elements, elements.root_node_id().unwrap(), node_id, order);
}
Action::ModifyController (f) => {
let controller = &mut self.get_element_mut (node_id).controller;
f (controller);
}
Action::ModifyModel (f) => {
let model = {
let model = &mut self.get_element_mut (node_id).model;
f (model);
model.clone()
};
self.event_buffer.push ((node_id.clone(), Event::Update (model)));
}
Action::ModifyView (f) => {
let view = {
let view = &mut self.get_element_mut (node_id).view;
f (view);
view.clone()
};
self.display_buffer.push ((node_id.clone(), Display::Update (view.into())));
}
Action::SubmitCallback (callback_id) => {
let callback_id = Some (callback_id);
let model = Model {
callback_id, .. self.get_element (node_id).model.clone()
};
self.event_buffer.push ((node_id.clone(), Event::Submit (model)));
}
Action::Focus => {
let mut focus_id = Some (node_id.clone());
while let Some (id) = focus_id {
focus_id = self.change_focus (&id);
if self.get_element (&id).controller.focus_top {
self.elements.make_last_sibling (&id).unwrap();
self.display_buffer.push ((id.clone(), Display::Update (Update::FocusTop)));
}
let ancestor_ids = self.elements.ancestor_ids (&id).unwrap().cloned()
.collect::<Vec <_>>();
for ancestor_id in ancestor_ids {
if self.get_element (&ancestor_id).controller.focus_top {
self.elements.make_last_sibling (&ancestor_id).unwrap();
self.display_buffer
.push ((ancestor_id.clone(), Display::Update (Update::FocusTop)));
}
}
}
}
Action::Enable => {
let view = {
let element = self.get_element_mut (node_id);
element.controller.state.enable();
element.view.appearance = element.controller.get_appearance().clone();
element.view.clone()
};
self.display_buffer.push ((node_id.clone(), Display::Update (view.into())));
}
Action::Disable => {
let view = {
let element = self.get_element_mut (node_id);
element.controller.state.disable();
element.view.appearance = element.controller.get_appearance().clone();
element.view.clone()
};
self.display_buffer.push ((node_id.clone(), Display::Update (view.into())));
}
Action::Destroy => {
let parent_id = self.elements.get_parent_id (node_id).clone();
let focused = self.elements.get_element (node_id).controller.state
== State::Focused;
{ let mut children_ids = self.elements.children_ids (&parent_id).unwrap();
let first_sibling_id = children_ids.next().unwrap().clone();
let first_sibling = self.elements.get_element (&first_sibling_id);
if let Ok (Widget (selection, _, _)) = Menu::try_from (first_sibling)
&& selection.current.as_ref() == Some (node_id)
{
let mut select = None;
for sibling_id in children_ids {
if sibling_id == node_id {
continue
}
let sibling = self.elements.get_element (sibling_id);
if sibling.controller.state == State::Enabled
&& Frame::try_from (sibling).is_ok()
{
select = Some (sibling_id.clone());
break
}
}
let deselect = Box::new (move |controller : &mut Controller|{
let selection = Selection::try_ref_mut (&mut controller.component)
.unwrap();
selection.current = select;
});
self.handle_action (Action::ModifyController (deselect), &first_sibling_id);
}
}
if focused {
let mut focus_id = Some (parent_id);
while let Some (id) = focus_id {
focus_id = self.change_focus (&id);
}
}
for node_id in self.elements.traverse_post_order_ids (node_id).unwrap() {
self.event_buffer.push ((node_id.clone(), Event::Destroy));
self.display_buffer.push ((node_id, Display::Destroy));
}
let _ = self.elements
.remove_node (node_id.clone(), tree::RemoveBehavior::DropChildren).unwrap();
}
Action::ReleaseButtons => {
use controller::controls::Control;
let release_buttons =
self.elements.get_element_mut (node_id).controller.release_buttons();
for control in release_buttons {
control.fun::<A::ButtonControls>().0 (
&None, &self.elements, node_id, self.action_buffer.as_mut().unwrap());
}
let mut action_buffer = self.action_buffer.take().unwrap();
#[expect(clippy::iter_with_drain)]
for (node_id, action) in action_buffer.drain(..) {
self.handle_action (action, &node_id);
}
self.action_buffer = Some (action_buffer);
}
}
log::trace!("...handle_action");
}
fn insert_child (&mut self,
parent_id : &NodeId,
child : Node <Element>,
order : CreateOrder
) -> NodeId {
let child_model = child.data().model.clone();
let child_view = child.data().view.clone();
let child_id = self.elements.insert (
child, tree::InsertBehavior::UnderNode (parent_id)).unwrap();
match order {
CreateOrder::Append => {}
CreateOrder::Prepend => {
let _ = self.elements.make_first_sibling (&child_id).unwrap();
}
CreateOrder::NthSibling (n) =>
self.elements.make_nth_sibling (&child_id, n as usize).unwrap()
}
self.event_buffer.push ((parent_id.clone(),
Event::Create (child_model, child_id.clone(), order)));
self.display_buffer.push ((parent_id.clone(),
Display::Create (child_view, child_id.clone(), order)));
child_id
}
fn change_focus (&mut self, target_id : &NodeId) -> Option <NodeId> {
use controller::component::{Kind, Selection};
log::trace!("change_focus...");
let focused_id = self.focused_element_id().clone();
let focused_ancestors = self.elements.ancestor_ids (&focused_id).unwrap().cloned()
.collect::<Vec <NodeId>>();
let target_ancestors = self.elements.ancestor_ids (target_id).unwrap().cloned()
.collect::<Vec <NodeId>>();
let maybe_common_ancestor_id = focused_ancestors.iter().rev()
.zip (target_ancestors.iter().rev())
.filter_map (|(a, b)|
if a == b {
Some (a)
} else {
None
})
.cloned().enumerate().last();
let focused_ancestor_of_target = target_ancestors.contains (&focused_id);
let target_ancestor_of_focused = focused_ancestors.contains (target_id);
{ let mut defocus = |defocus_id| {
let view = {
let mut actions = vec![];
let focused_node = self.elements.get (&defocus_id).unwrap();
if let Some (sub_child_id) = focused_node.children().first()
&& let Ok (Widget (switch, _, _)) =
Button::try_get (&self.elements, sub_child_id)
&& switch.state == switch::State::On && !switch.toggle
{
button::release (&None, &self.elements, &defocus_id, &mut actions);
}
for (node_id, action) in actions.into_iter() {
self.handle_action (action, &node_id);
}
let focused = self.elements.get_mut (&defocus_id).unwrap().data_mut();
focused.defocus();
let view = focused.view.clone();
focused.view.appearance.sound = None; view
};
self.display_buffer .push ((defocus_id, Display::Update (view.into())));
};
if !focused_ancestor_of_target {
defocus (focused_id);
}
if let Some ((_, common_ancestor_id)) = maybe_common_ancestor_id.as_ref() {
for ancestor_id in focused_ancestors.into_iter()
.take_while (|id| id != common_ancestor_id && id != target_id)
{
defocus (ancestor_id);
}
}
}
let refocus_id = {
let mut focus = |focus_id| {
if Frame::try_from (self.get_element (&focus_id)).is_ok() {
let parent_id = self.elements.get_parent_id (&focus_id);
let first_sibling_id =
self.elements.children_ids (parent_id).unwrap().next().unwrap().clone();
if first_sibling_id != focus_id {
let first_sibling = self.elements.get_element (&first_sibling_id);
if let Ok (Widget (selection, _, _)) = Menu::try_from (first_sibling)
&& selection.current.as_ref() != Some (&focus_id)
{
let select_id = focus_id.clone();
let select = Box::new (move |controller : &mut Controller|{
let selection = Selection::try_ref_mut (&mut controller.component)
.unwrap();
selection.current = Some (select_id.clone());
});
self.handle_action (Action::ModifyController (select), &first_sibling_id);
}
}
}
let focus = self.get_element_mut (&focus_id);
focus.focus();
let view = focus.view.clone();
focus.view.appearance.sound = None; self.display_buffer.push ((focus_id.clone(), Display::Update (view.into())));
};
let depth = if let Some ((depth, _)) = maybe_common_ancestor_id {
depth + 1 + usize::from (focused_ancestor_of_target)
} else {
1
};
for ancestor_id in target_ancestors.into_iter().rev().skip (depth) {
focus (ancestor_id);
}
if !target_ancestor_of_focused {
focus (target_id.clone());
}
refocus (target_id, self.elements())
};
self.focused_id = target_id.clone();
log::trace!("...change_focus");
refocus_id
}
fn splice_subtree (&mut self,
other : &Tree <Element>,
other_id : &NodeId,
parent_id : &NodeId,
order : CreateOrder
) -> NodeId {
let subtree_root = Node::new (other.get (other_id).unwrap().data().clone());
let subtree_id = self.insert_child (parent_id, subtree_root, order);
for child_id in other.children_ids (other_id).unwrap() {
self.splice_subtree (other, child_id, &subtree_id, CreateOrder::Append);
}
subtree_id
}
pub (crate) fn swap_presentation <P2 : Presentation> (self, f : impl FnOnce (P) -> P2)
-> Interface <A, P2>
{
let Interface {
elements, focused_id, presentation, input_buffer, display_buffer, action_buffer,
event_buffer, _phantom
} = self;
#[expect(clippy::used_underscore_binding)]
Interface {
presentation: f (presentation),
elements, focused_id, input_buffer, display_buffer, action_buffer, event_buffer,
_phantom
}
}
}
pub macro log_elements_tree ($interface:expr$(, $level:expr)?) {
let mut s = String::new();
$interface.elements.write_formatted (&mut s).unwrap();
$crate::interface::log_elements_string!(s$(, $level)?);
}
pub macro log_elements_tree_names ($interface:expr$(, $level:expr)?) {
let mut s = String::new();
$interface.elements.write_formatted_names (&mut s).unwrap();
$crate::interface::log_elements_string!(s$(, $level)?);
}
#[expect(unused_macros)]
macro log_elements_string {
($string:expr) => {
$crate::interface::log_elements_string!($string, $crate::log::Level::Debug);
},
($string:expr, $level:expr) => {
$crate::log::log!($level, "elements:\n{}", $string);
}
}
impl Element {
pub fn new (name : String, controller : Controller, model : Model, mut view : View)
-> Self
{
view.appearance = controller.get_appearance().clone();
Element { name, controller, view, model }
}
pub fn focus (&mut self) {
self.controller.state.focus();
self.controller.update_view_focus (&mut self.view);
}
pub fn defocus (&mut self) {
self.controller.state.defocus();
self.controller.update_view_focus (&mut self.view);
}
pub fn disable (&mut self) {
self.controller.state.disable();
self.controller.update_view_focus (&mut self.view);
}
}
impl Default for Element {
fn default() -> Self {
Element::new (
"".to_string(), Controller::default(), Model::default(), View::default())
}
}
impl AsRef <Controller> for Element {
fn as_ref (&self) -> &Controller {
&self.controller
}
}
impl AsRef <Model> for Element {
fn as_ref (&self) -> &Model {
&self.model
}
}
impl AsRef <View> for Element {
fn as_ref (&self) -> &View {
&self.view
}
}
impl Action {
#[inline]
pub fn create_singleton (element : Element, order : CreateOrder) -> Self {
let subtree = TreeBuilder::new().with_root (Node::new (element)).build();
Action::Create (subtree, order)
}
#[inline]
pub fn set_view (view : View) -> Self {
Action::ModifyView (Box::new (|v| *v = view))
}
#[inline]
pub fn set_controller (controller : Controller) -> Self {
Action::ModifyController (Box::new (|c| *c = controller))
}
#[inline]
pub fn set_model (model : Model) -> Self {
Action::ModifyModel (Box::new (|m| *m = model))
}
#[inline]
pub fn set_view_component <V> (component : V) -> Self where
V : view::component::Kind + 'static
{
Action::ModifyView (Box::new (|v| v.component = component.into()))
}
#[inline]
pub fn update_view_component <V> (component : V) -> Self where
V : view::component::Kind + 'static
{
Action::ModifyView (Box::new (|v| {
let v = V::try_ref_mut (&mut v.component).unwrap();
*v = component;
}))
}
#[inline]
pub fn set_controller_component <C> (component : C) -> Self where
C : ControllerKind + 'static
{
Action::ModifyController (Box::new (|c| c.component = component.into()))
}
#[inline]
pub fn update_controller_component <C> (component : C) -> Self where
C : ControllerKind + 'static
{
Action::ModifyController (Box::new (|c| {
let c = C::try_ref_mut (&mut c.component).unwrap();
*c = component;
}))
}
#[inline]
pub fn set_model_component <M> (component : M) -> Self where
M : model::component::Kind + 'static
{
Action::ModifyModel (Box::new (|m| m.component = component.into()))
}
#[inline]
pub fn update_model_component <M> (component : M) -> Self where
M : model::component::Kind + 'static
{
Action::ModifyModel (Box::new (|m| {
let m = M::try_ref_mut (&mut m.component).unwrap();
*m = component;
}))
}
}
impl std::fmt::Debug for Action {
fn fmt (&self, f : &mut std::fmt::Formatter) -> Result <(), std::fmt::Error> {
match self {
Action::Create (subtree, order) =>
write!(f, "Create({subtree:?}, {order:?})"),
Action::ModifyController (closure) =>
write!(f, "ModifyController({:p})", &closure),
Action::ModifyModel (closure) =>
write!(f, "ModifyModel({:p})", &closure),
Action::ModifyView (closure) =>
write!(f, "ModifyView({:p})", &closure),
Action::SubmitCallback (callback_id) =>
write!(f, "SubmitCallback({callback_id:?})"),
Action::Focus => write!(f, "Focus"),
Action::Enable => write!(f, "Enable"),
Action::Disable => write!(f, "Disable"),
Action::Destroy => write!(f, "Destroy"),
Action::ReleaseButtons => write!(f, "ReleaseButtons")
}
}
}