gooey/interface/
mod.rs

1//! Interface layer.
2//!
3//! The `Interface` is the primary structure representing the user interface and
4//! contains all the data for the interface including the `Presentation`
5//! instance.
6//!
7//! The internal representation of the interface is a `Tree` of `Element` nodes.
8//! An `Element` is a combination of a `Model` component, a `View` component,
9//! and a `Controller` component. The kinds of components in `Elements` and
10//! their relations with parent/child nodes are contextualized in various
11//! `Widget` definitions.
12//!
13//! `Action` events define the internal language of the `Interface` layer and
14//! result from user `Input` events, or directly submitted from application
15//! code. Each `Action` is directed at a target `Element` node. `Action` events
16//! include creating/destroying/modifying `Element` nodes and their components,
17//! changing focus, or submitting callbacks.
18
19use std::convert::TryFrom;
20use std::sync::{Arc, LazyLock, RwLock};
21use log;
22use derive_more::{From, TryInto};
23
24use crate::prelude::*;
25
26pub mod controller;
27pub mod model;
28pub mod view;
29pub use self::controller::Controller;
30pub use self::model::Model;
31pub use self::view::View;
32
33/// Pointer position
34pub static POINTER : LazyLock <Arc <RwLock <input::Pointer>>> = LazyLock::new (||
35  Arc::new (RwLock::new (input::Pointer::default())));
36
37/// Parameterized interface represented by a tree of `Element`s
38#[derive(Debug)]
39pub struct Interface <A=application::Default, P=presentation::Headless> where
40  A : Application,
41  P : Presentation
42{
43  pub presentation : P,
44  elements         : Tree <Element>,
45  focused_id       : NodeId,
46  input_buffer     : Option <Vec <Input>>,
47  action_buffer    : Option <Vec <(NodeId, Action)>>,
48  display_buffer   : Vec <(NodeId, Display)>,
49  event_buffer     : Vec <(NodeId, Event)>,
50  _phantom         : std::marker::PhantomData <A>
51}
52
53/// An interface node consisting of one each of `Model`, `View`, and
54/// `Controller` components.
55///
56/// See `Widget`s for construction of contextualzed combinations of different
57/// components.
58#[derive(Clone, Debug)]
59pub struct Element {
60  pub name       : String,
61  pub controller : Controller,
62  pub model      : Model,
63  pub view       : View
64}
65
66/// An interface-level event
67#[derive(From, TryInto)]
68pub enum Action {
69  Create           (Tree <Element>, CreateOrder),
70  ModifyController (Box <dyn FnOnce (&mut Controller)>),
71  ModifyModel      (Box <dyn FnOnce (&mut Model)>),
72  ModifyView       (Box <dyn FnOnce (&mut View)>),
73  /// This will submit produce an event with the Model containing this callback
74  /// ID, but will *not* modify the current Model callback ID.
75  ///
76  /// See the Form widget control `FormSubmitCallback` for a control function
77  /// that submits a model with the currently set callback ID.
78  SubmitCallback   (application::CallbackId),
79  /// Change the view state from Enabled to Focused; it is a debug error if the
80  /// view state is not Enabled.
81  ///
82  /// If `top` is true, node will be moved to the last sibling position
83  /// ("top"), otherwise position relative to siblings will remain unchanged
84  Focus,
85  /// Change `view.state` from Disabled to Enabled; it is a debug error if the
86  /// view state is not Disabled
87  Enable,
88  /// Change the `view.state` from Enabled to Disabled; it is a debug error if
89  /// the view state is not Enabled
90  Disable,
91  /// Destroy the target element and children.
92  ///
93  /// If the node was focused, then focus is shifted to the parent. If it was
94  /// the root node that was focused, then this is always an error since the
95  /// root node is always focused as the common ancestor of all nodes.
96  Destroy,
97  /// Trigger any release buttons that exist in the current input map of the
98  /// controller of the target node.
99  ///
100  /// This can be used when focus is changing and input state should not be
101  /// orphaned.
102  ReleaseButtons
103}
104
105/// Either append or prepend newly created element
106#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
107pub enum CreateOrder {
108  #[default]
109  Append,
110  Prepend,
111  NthSibling (u32)
112}
113
114impl <A, P> Interface <A, P> where
115  A : Application,
116  P : Presentation
117{
118  pub fn with_root (mut root : Element) -> Self {
119    log::trace!("with_root...");
120    root.focus();
121    let elements       = TreeBuilder::new().with_root (Node::new (root.clone()))
122      .build();
123    let focused_id     = elements.root_node_id().unwrap().clone();
124    let presentation   = P::with_root (root.view, focused_id.clone());
125    let input_buffer   = Some (vec![]);
126    let action_buffer  = Some (vec![]);
127    let display_buffer = vec![];
128    let event_buffer   = vec![];
129    log::trace!("...with_root");
130    Interface {
131      elements, focused_id, presentation,
132      input_buffer, display_buffer, action_buffer, event_buffer,
133      _phantom: std::marker::PhantomData
134    }
135  }
136
137  /// Handle an application request.
138  ///
139  /// Does not update presentation, must call `display()` to refresh display.
140  #[inline]
141  #[must_use]
142  #[expect(mismatched_lifetime_syntaxes)]
143  pub fn action (&mut self, node_id : &NodeId, action : Action)
144    -> std::vec::Drain <(NodeId, Event)>
145  {
146    self.handle_action (action, node_id);
147    self.event_buffer.drain(..)
148  }
149
150  /// Handles a batch of an application requests.
151  ///
152  /// Does not update presentation, must call `display()` to refresh display.
153  #[inline]
154  #[must_use]
155  #[expect(mismatched_lifetime_syntaxes)]
156  pub fn actions (&mut self, actions : Vec <(NodeId, Action)>)
157    -> std::vec::Drain <(NodeId, Event)>
158  {
159    for (node_id, action) in actions.into_iter() {
160      self.handle_action (action, &node_id);
161    }
162    self.event_buffer.drain(..)
163  }
164
165  /// Get and handle user input
166  #[must_use]
167  #[expect(mismatched_lifetime_syntaxes)]
168  pub fn update (&mut self) -> std::vec::Drain <(NodeId, Event)> {
169    log::trace!("update...");
170    // handle input
171    let mut action_buffer = self.action_buffer.take().unwrap();
172    let mut input_buffer  = self.input_buffer.take().unwrap();
173    debug_assert!(action_buffer.is_empty());
174    debug_assert!(input_buffer.is_empty());
175    self.presentation.get_input (&mut input_buffer);
176    #[expect(clippy::iter_with_drain)]
177    for input in input_buffer.drain(..) {
178      log::trace!("input: {input:?}");
179      // update global POINTER
180      if let Input::Pointer (pointer) = &input {
181        *POINTER.write().unwrap() = pointer.clone()
182      }
183      let focused_id = self.focused_element_id().clone();
184      let focused = self.focused_element();
185      // TODO: possibly allow a node to bubble even if input was handled ?
186      let button_release = match focused.controller.handle_input::<A> (
187        input, &self.elements, &focused_id, &mut action_buffer
188      ) {
189        Ok  (result) => result,
190        Err (mut input) => {
191          // bubble up to ancestors
192          debug_assert!(action_buffer.is_empty());
193          let mut button_release = None;
194          let input_mask = (&input).into();
195          if !focused.controller.bubble_trap.intersects (input_mask) {
196            for ancestor_id in self.elements.ancestor_ids (&focused_id).unwrap() {
197              let ancestor = self.get_element (ancestor_id);
198              input = match ancestor.controller.handle_input::<A> (
199                input, &self.elements, ancestor_id, &mut action_buffer
200              ) {
201                Err (input) =>
202                  if ancestor.controller.bubble_trap.intersects (input_mask) {
203                    break
204                  } else {
205                    input
206                  }
207                Ok (result) => {
208                  button_release = result;
209                  break
210                }
211              };
212            }
213          }
214          button_release
215        }
216      };
217      // handle actions
218      for (node_id, action) in action_buffer.drain(..) {
219        self.handle_action (action, &node_id);
220      }
221      // TODO: this was originally before handling the actions so that if focus
222      // changes, the release button is inserted into the newly focused node;
223      // however if the button release payload is a remove, we may want that to
224      // be processed by the original node before focus changes
225      if let Some (button_release) = button_release {
226        match button_release {
227          ButtonRelease::Insert (input, controls) =>
228            for (control, node_id) in controls {
229              let element = self.get_element_mut (&node_id);
230              element.controller.release_button_insert (input, control);
231            }
232          ButtonRelease::Remove (input, node_id) => {
233            let element = self.get_element_mut (&node_id);
234            element.controller.release_button_remove (input);
235          }
236        }
237      }
238    }
239    debug_assert!(action_buffer.is_empty());
240    debug_assert!(input_buffer.is_empty());
241    self.action_buffer = Some (action_buffer);
242    self.input_buffer  = Some (input_buffer);
243
244    log::trace!("...update");
245    // return application events
246    self.event_buffer.drain(..)
247  }
248
249  /// Presentation update
250  #[inline]
251  pub fn display (&mut self) {
252    log::trace!("display...");
253    self.presentation
254      .display_view (&self.elements, self.display_buffer.drain(..));
255    log::trace!("...display");
256  }
257
258  #[inline]
259  pub const fn elements (&self) -> &Tree <Element> {
260    &self.elements
261  }
262
263  #[inline]
264  pub fn root (&self) -> &Element {
265    self.root_node().data()
266  }
267
268  pub fn root_node (&self) -> &Node <Element> {
269    self.elements.get (self.root_id()).unwrap()
270  }
271
272  #[inline]
273  pub fn root_id (&self) -> &NodeId {
274    self.elements.root_node_id().unwrap()
275  }
276
277  #[inline]
278  pub fn get_element (&self, node_id : &NodeId) -> &Element {
279    self.elements.get_element (node_id)
280  }
281
282  #[inline]
283  pub fn get_element_mut (&mut self, node_id : &NodeId) -> &mut Element {
284    self.elements.get_element_mut (node_id)
285  }
286
287  #[inline]
288  pub const fn focused_element_id (&self) -> &NodeId {
289    &self.focused_id
290  }
291
292  #[inline]
293  pub fn focused_element (&self) -> &Element {
294    self.get_element (&self.focused_id)
295  }
296
297  #[inline]
298  pub fn focused_element_mut (&mut self) -> &mut Element {
299    let focused_id = self.focused_id.clone();
300    self.get_element_mut (&focused_id)
301  }
302
303  #[inline]
304  pub fn print_elements_tree (&self) {
305    let mut s = String::new();
306    self.elements.write_formatted (&mut s).unwrap();
307    println!("elements:\n{s}");
308  }
309
310  #[inline]
311  pub fn log_elements_tree (&self) {
312    let mut s = String::new();
313    self.elements.write_formatted (&mut s).unwrap();
314    log::info!("elements:\n{s}");
315  }
316
317  #[inline]
318  pub fn print_elements_tree_names (&self) {
319    let mut s = String::new();
320    self.elements.write_formatted_names (&mut s).unwrap();
321    println!("elements:\n{s}");
322  }
323
324  #[inline]
325  pub fn log_elements_tree_names (&self) {
326    let mut s = String::new();
327    self.elements.write_formatted_names (&mut s).unwrap();
328    log::info!("elements:\n{s}");
329  }
330
331  /// Create a new element and return the node ID
332  pub fn create_singleton (&mut self,
333    parent_id : &NodeId,
334    element   : Element,
335    order     : CreateOrder
336  ) -> NodeId {
337    match self.action (parent_id, Action::create_singleton (element, order))
338      .next().unwrap()
339    {
340      (_, Event::Create (_, new_id, _)) => new_id,
341      _ => unreachable!()
342    }
343  }
344
345  fn handle_action (&mut self, action : Action, node_id : &NodeId) {
346    use controller::component::{Kind, Selection};
347    log::trace!("handle_action...");
348    log::trace!("action: {action:?}");
349    match action {
350      Action::Create (elements, order) => {
351        #[cfg(debug_assertions)]
352        for element in
353          elements.traverse_level_order (elements.root_node_id().unwrap())
354            .unwrap()
355        {
356          // check that appearances match the controller state
357          debug_assert_eq!(&element.data().view.appearance,
358            element.data().controller.get_appearance());
359        }
360        self.splice_subtree (
361          &elements, elements.root_node_id().unwrap(), node_id, order);
362      }
363      Action::ModifyController (f) => {
364        let controller = &mut self.get_element_mut (node_id).controller;
365        f (controller);
366      }
367      Action::ModifyModel (f) => {
368        let model = {
369          let model = &mut self.get_element_mut (node_id).model;
370          f (model);
371          model.clone()
372        };
373        self.event_buffer.push ((node_id.clone(), Event::Update (model)));
374      }
375      Action::ModifyView (f) => {
376        let view = {
377          let view = &mut self.get_element_mut (node_id).view;
378          f (view);
379          // TODO: reset ephemeral fields (sound triggers)
380          view.clone()
381        };
382        self.display_buffer.push (
383          (node_id.clone(), Display::Update (view.into())));
384      }
385      Action::SubmitCallback (callback_id) => {
386        let callback_id = Some (callback_id);
387        let model = Model {
388          callback_id, .. self.get_element (node_id).model.clone()
389        };
390        self.event_buffer.push ((node_id.clone(), Event::Submit (model)));
391      }
392      Action::Focus => {
393        let mut focus_id = Some (node_id.clone());
394        while let Some (id) = focus_id {
395          focus_id = self.change_focus (&id);
396          // handle re-ordering
397          if self.get_element (&id).controller.focus_top {
398            self.elements.make_last_sibling (&id).unwrap();
399            self.display_buffer.push (
400              (id.clone(), Display::Update (Update::FocusTop)));
401          }
402          let ancestor_ids = self.elements.ancestor_ids (&id).unwrap().cloned()
403            .collect::<Vec <_>>();
404          for ancestor_id in ancestor_ids {
405            if self.get_element (&ancestor_id).controller.focus_top {
406              self.elements.make_last_sibling (&ancestor_id).unwrap();
407              self.display_buffer.push (
408                ( ancestor_id.clone(),
409                  Display::Update (Update::FocusTop)
410                )
411              );
412            }
413          }
414        }
415      }
416      Action::Enable => {
417        let view = {
418          let element = self.get_element_mut (node_id);
419          element.controller.state.enable();
420          element.view.appearance = element.controller.get_appearance().clone();
421          element.view.clone()
422        };
423        self.display_buffer.push (
424          (node_id.clone(), Display::Update (view.into())));
425      }
426      Action::Disable => {
427        let view = {
428          let element = self.get_element_mut (node_id);
429          element.controller.state.disable();
430          element.view.appearance = element.controller.get_appearance().clone();
431          element.view.clone()
432        };
433        self.display_buffer.push (
434          (node_id.clone(), Display::Update (view.into())));
435      }
436      Action::Destroy => {
437        let parent_id = self.elements.get_parent_id (node_id).clone();
438        let focused = self.elements.get_element (node_id).controller.state ==
439          State::Focused;
440        { // widget-specific destroy logic
441          let mut children_ids = self.elements.children_ids (&parent_id).unwrap();
442          // menu: we want to update the selection here so that the destroyed
443          // node is not refocused below
444          let first_sibling_id = children_ids.next().unwrap().clone();
445          let first_sibling    = self.elements.get_element (&first_sibling_id);
446          if let Ok (Widget (selection, _, _)) = Menu::try_from (first_sibling)
447            && selection.current.as_ref() == Some (node_id)
448          {
449            let mut select = None;
450            for sibling_id in children_ids {
451              if sibling_id == node_id {
452                continue
453              }
454              let sibling = self.elements.get_element (sibling_id);
455              if sibling.controller.state == State::Enabled
456                && Frame::try_from (sibling).is_ok()
457              {
458                select = Some (sibling_id.clone());
459                break
460              }
461            }
462            let deselect = Box::new (move |controller : &mut Controller|{
463              let selection = Selection::try_ref_mut (&mut controller.component)
464                .unwrap();
465              selection.current = select;
466            });
467            self.handle_action (Action::ModifyController (deselect), &first_sibling_id);
468          }
469        }
470        if focused {
471          let mut focus_id = Some (parent_id);
472          while let Some (id) = focus_id {
473            focus_id = self.change_focus (&id);
474          }
475        }
476        for node_id in self.elements.traverse_post_order_ids (node_id).unwrap() {
477          self.event_buffer.push   ((node_id.clone(), Event::Destroy));
478          self.display_buffer.push ((node_id,         Display::Destroy));
479        }
480        let _ = self.elements
481          .remove_node (node_id.clone(), tree::RemoveBehavior::DropChildren).unwrap();
482      }
483      Action::ReleaseButtons => {
484        use controller::controls::Control;
485        let release_buttons =
486          self.elements.get_element_mut (node_id).controller.release_buttons();
487        for control in release_buttons {
488          control.fun::<A::ButtonControls>().0 (
489            &None, &self.elements, node_id, self.action_buffer.as_mut().unwrap());
490        }
491        let mut action_buffer = self.action_buffer.take().unwrap();
492        #[expect(clippy::iter_with_drain)]
493        for (node_id, action) in action_buffer.drain(..) {
494          self.handle_action (action, &node_id);
495        }
496        self.action_buffer = Some (action_buffer);
497      }
498    }
499    log::trace!("...handle_action");
500  }
501
502  /// Insert node as child of the given node ID
503  fn insert_child (&mut self,
504    parent_id : &NodeId,
505    child     : Node <Element>,
506    order     : CreateOrder
507  ) -> NodeId {
508    let child_model = child.data().model.clone();
509    let child_view  = child.data().view.clone();
510    let child_id    = self.elements.insert (
511      child, tree::InsertBehavior::UnderNode (parent_id)).unwrap();
512    match order {
513      CreateOrder::Append  => {}
514      CreateOrder::Prepend => {
515        let _ = self.elements.make_first_sibling (&child_id).unwrap();
516      }
517      CreateOrder::NthSibling (n) =>
518        self.elements.make_nth_sibling (&child_id, n as usize).unwrap()
519    }
520    self.event_buffer.push ((parent_id.clone(),
521      Event::Create (child_model, child_id.clone(), order)));
522    self.display_buffer.push ((parent_id.clone(),
523      Display::Create (child_view, child_id.clone(), order)));
524    child_id
525  }
526
527  /// Defocus the currently focused node and focuses the target.
528  ///
529  /// Returns a new focus ID if focus should be redirected.
530  fn change_focus (&mut self, target_id : &NodeId) -> Option <NodeId> {
531    use controller::component::{Kind, Selection};
532    log::trace!("change_focus...");
533    let focused_id = self.focused_element_id().clone();
534    let focused_ancestors = self.elements.ancestor_ids (&focused_id).unwrap()
535      .cloned().collect::<Vec <NodeId>>();
536    let target_ancestors = self.elements.ancestor_ids (target_id).unwrap()
537      .cloned().collect::<Vec <NodeId>>();
538    let maybe_common_ancestor_id = {
539      focused_ancestors.iter().rev().zip (target_ancestors.iter().rev())
540        .filter_map (|(a, b)|
541          if a == b {
542            Some (a)
543          } else {
544            None
545          })
546        .cloned().enumerate().last()
547    };
548    let focused_ancestor_of_target = target_ancestors.contains (&focused_id);
549    let target_ancestor_of_focused = focused_ancestors.contains (target_id);
550    { // defocus currently focused node and ancestors up to common ancestor
551      let mut defocus = |defocus_id| {
552        let view = {
553          // widget-specific defocus logic here
554          let mut actions  = vec![];
555          let focused_node = self.elements.get (&defocus_id).unwrap();
556          // release button if the focused node is a button widget and it was pressed
557          // ('on')
558          if let Some (sub_child_id) = focused_node.children().first() &&
559            let Ok (Widget (switch, _, _)) =
560              Button::try_get (&self.elements, sub_child_id)
561            && switch.state == switch::State::On && !switch.toggle
562          {
563            button::release (&None, &self.elements, &defocus_id, &mut actions);
564          }
565          for (node_id, action) in actions.into_iter() {
566            self.handle_action (action, &node_id);
567          }
568          let focused = self.elements.get_mut (&defocus_id).unwrap().data_mut();
569          focused.defocus();
570          let view = focused.view.clone();
571          focused.view.appearance.sound = None;  // sounds are ephemeral events
572          view
573        };
574        self.display_buffer .push ((defocus_id, Display::Update (view.into())));
575      };
576      // do not defocus if focused node is an ancestor of the target
577      if !focused_ancestor_of_target {
578        defocus (focused_id);
579      }
580      if let Some ((_, common_ancestor_id)) = maybe_common_ancestor_id.as_ref() {
581        for ancestor_id in focused_ancestors.into_iter()
582          .take_while (|id| id != common_ancestor_id && id != target_id)
583        {
584          defocus (ancestor_id);
585        }
586      }
587    }
588    let refocus_id = {
589      // focus from common ancestor to target node
590      let mut focus = |focus_id| {
591        // widget-specific focus logic
592        if Frame::try_from (self.get_element (&focus_id)).is_ok() {
593          // update selection if frame is a menu item
594          let parent_id = self.elements.get_parent_id (&focus_id);
595          let first_sibling_id =
596            self.elements.children_ids (parent_id).unwrap().next().unwrap().clone();
597          if first_sibling_id != focus_id {
598            let first_sibling = self.elements.get_element (&first_sibling_id);
599            if let Ok (Widget (selection, _, _)) = Menu::try_from (first_sibling)
600              && selection.current.as_ref() != Some (&focus_id)
601            {
602              let select_id = focus_id.clone();
603              let select = Box::new (move |controller : &mut Controller|{
604                let selection = Selection::try_ref_mut (&mut controller.component)
605                  .unwrap();
606                selection.current = Some (select_id.clone());
607              });
608              self.handle_action (Action::ModifyController (select), &first_sibling_id);
609            }
610          }
611        }
612        let focus = self.get_element_mut (&focus_id);
613        focus.focus();
614        let view = focus.view.clone();
615        focus.view.appearance.sound = None;  // sounds are ephemeral events
616        self.display_buffer
617          .push ((focus_id.clone(), Display::Update (view.into())));
618      };
619      let depth = if let Some ((depth, _)) = maybe_common_ancestor_id {
620        depth + 1 + usize::from (focused_ancestor_of_target)
621      } else {
622        1
623      };
624      for ancestor_id in target_ancestors.into_iter().rev().skip (depth) {
625        focus (ancestor_id);
626      }
627      // do not focus if target is ancestor of the currently focused node
628      // (the node should already be focused)
629      if !target_ancestor_of_focused {
630        focus (target_id.clone());
631      }
632      // only call refocus on the last node: intermediate nodes are not
633      // redirected
634      refocus (target_id, self.elements())
635    };
636    self.focused_id = target_id.clone();
637    log::trace!("...change_focus");
638    refocus_id
639  }
640
641  /// See also public `crate::utils::splice_subtree` for operating on subtrees
642  /// before insertion into the interface
643  fn splice_subtree (&mut self,
644    other     : &Tree <Element>,
645    other_id  : &NodeId,
646    parent_id : &NodeId,
647    order     : CreateOrder
648  ) -> NodeId {
649    // TODO: avoid clone here?
650    let subtree_root = Node::new (other.get (other_id).unwrap().data().clone());
651    let subtree_id   = self.insert_child (parent_id, subtree_root, order);
652    for child_id in other.children_ids (other_id).unwrap() {
653      self.splice_subtree (other, child_id, &subtree_id, CreateOrder::Append);
654    }
655    subtree_id
656  }
657
658  /// This is method is provided to allow initialization of composite presentations by
659  /// first initializing an interface with `G::make_interface()`--the graphical backend
660  /// creates the interface with a default initial interface, usually containing a root
661  /// screen element--and then adding a default initialized audio backend.
662  pub (crate) fn swap_presentation <P2 : Presentation> (self, f : impl FnOnce (P) -> P2)
663    -> Interface <A, P2>
664  {
665    let Interface {
666      elements, focused_id, presentation, input_buffer, display_buffer, action_buffer,
667      event_buffer, _phantom
668    } = self;
669    #[expect(clippy::used_underscore_binding)]
670    Interface {
671      presentation: f (presentation),
672      elements, focused_id, input_buffer, display_buffer, action_buffer, event_buffer,
673      _phantom
674    }
675  }
676}
677
678impl Element {
679  /// Create a new element. Note that the view appearance will always be set to
680  /// the current appearance defined by the controller state.
681  pub fn new (
682    name : String, controller : Controller, model : Model, mut view : View
683  ) -> Self {
684    view.appearance = controller.get_appearance().clone();
685    Element { name, controller, view, model }
686  }
687  pub fn focus (&mut self) {
688    self.controller.state.focus();
689    self.controller.update_view_focus (&mut self.view);
690  }
691  pub fn defocus (&mut self) {
692    self.controller.state.defocus();
693    self.controller.update_view_focus (&mut self.view);
694  }
695  pub fn disable (&mut self) {
696    self.controller.state.disable();
697    self.controller.update_view_focus (&mut self.view);
698  }
699}
700
701impl Default for Element {
702  fn default() -> Self {
703    Element::new (
704      "".to_string(), Controller::default(), Model::default(), View::default())
705  }
706}
707
708impl AsRef <Controller> for Element {
709  fn as_ref (&self) -> &Controller {
710    &self.controller
711  }
712}
713
714impl AsRef <Model> for Element {
715  fn as_ref (&self) -> &Model {
716    &self.model
717  }
718}
719
720impl AsRef <View> for Element {
721  fn as_ref (&self) -> &View {
722    &self.view
723  }
724}
725
726impl Action {
727  /// Produces a `Create` action that creates a singleton subtree containing the given
728  /// `Element`
729  #[inline]
730  pub fn create_singleton (element : Element, order : CreateOrder) -> Self {
731    let subtree = TreeBuilder::new().with_root (Node::new (element)).build();
732    Action::Create (subtree, order)
733  }
734
735  /// Produces a `ModifyView` action that sets the given `View` data
736  #[inline]
737  pub fn set_view (view : View) -> Self {
738    Action::ModifyView (Box::new (|v| *v = view))
739  }
740
741  /// Produces a `ModifyController` action that sets the given `Controller` data
742  #[inline]
743  pub fn set_controller (controller : Controller) -> Self {
744    Action::ModifyController (Box::new (|c| *c = controller))
745  }
746
747  /// Produces a `ModifyModel` action that sets the given `Model` data.
748  #[inline]
749  pub fn set_model (model : Model) -> Self {
750    Action::ModifyModel (Box::new (|m| *m = model))
751  }
752
753  /// Produces a `ModifyView` action that sets the given component `Kind`
754  #[inline]
755  pub fn set_view_component <V> (component : V) -> Self where
756    V : view::component::Kind + 'static
757  {
758    Action::ModifyView (Box::new (|v| v.component = component.into()))
759  }
760
761  /// Produces a `ModifyView` action that updates the current component with the
762  /// given value and panics if the current component is not the same `Kind`
763  #[inline]
764  pub fn update_view_component <V> (component : V) -> Self where
765    V : view::component::Kind + 'static
766  {
767    Action::ModifyView (Box::new (|v| {
768      let v = V::try_ref_mut (&mut v.component).unwrap();
769      *v = component;
770    }))
771  }
772
773  /// Produces a `ModifyController` action that sets the given component `Kind`
774  #[inline]
775  pub fn set_controller_component <C> (component : C) -> Self where
776    C : ControllerKind + 'static
777  {
778    Action::ModifyController (Box::new (|c| c.component = component.into()))
779  }
780
781  /// Produces a `ModifyController` action that updates the current component with the
782  /// given value and panics if the current component is not the same `Kind`
783  #[inline]
784  pub fn update_controller_component <C> (component : C) -> Self where
785    C : ControllerKind + 'static
786  {
787    Action::ModifyController (Box::new (|c| {
788      let c = C::try_ref_mut (&mut c.component).unwrap();
789      *c = component;
790    }))
791  }
792
793  /// Produces a `ModifyModel` action that sets the given component `Kind`
794  #[inline]
795  pub fn set_model_component <M> (component : M) -> Self where
796    M : model::component::Kind + 'static
797  {
798    Action::ModifyModel (Box::new (|m| m.component = component.into()))
799  }
800
801  /// Produces a `ModifyModel` action that updates the current component with the given
802  /// value and panics if the current component is not the same `Kind`
803  #[inline]
804  pub fn update_model_component <M> (component : M) -> Self where
805    M : model::component::Kind + 'static
806  {
807    Action::ModifyModel (Box::new (|m| {
808      let m = M::try_ref_mut (&mut m.component).unwrap();
809      *m = component;
810    }))
811  }
812}
813
814impl std::fmt::Debug for Action {
815  fn fmt (&self, f : &mut std::fmt::Formatter) -> Result <(), std::fmt::Error> {
816    match self {
817      Action::Create (subtree, order)        =>
818        write!(f, "Create({subtree:?}, {order:?})"),
819      Action::ModifyController (closure)     =>
820        write!(f, "ModifyController({:p})", &closure),
821      Action::ModifyModel      (closure)     =>
822        write!(f, "ModifyModel({:p})", &closure),
823      Action::ModifyView       (closure)     =>
824        write!(f, "ModifyView({:p})", &closure),
825      Action::SubmitCallback   (callback_id) =>
826        write!(f, "SubmitCallback({callback_id:?})"),
827      Action::Focus   => write!(f, "Focus"),
828      Action::Enable  => write!(f, "Enable"),
829      Action::Disable => write!(f, "Disable"),
830      Action::Destroy => write!(f, "Destroy"),
831      Action::ReleaseButtons => write!(f, "ReleaseButtons")
832    }
833  }
834}
835