gooey/presentation/
mod.rs

1//! Presentation layer.
2//!
3//! The `Presentation` trait defines required methods for getting input and
4//! displaying `View` data.
5//!
6//! A concrete `Presentation` type instance is a member of the main `Interface`
7//! structure.
8//!
9//! Calling `Interface::update()` will run `Presentation::get_input()` and
10//! pass the `Input` to the focused `Controller` component for handling.
11//!
12//! Any changes to `View` component data will result in `Display` events being
13//! generated and calling `Interface::display()` will run
14//! `Presentation::display_view()` with those `Display` values collected in the
15//! last update.
16
17use crate::{Application, Interface, Tree};
18use crate::tree::NodeId;
19use crate::interface::{view, Element, View};
20
21pub mod headless;
22pub use headless::Headless;
23
24// graphics
25// TODO: crossterm backend
26#[cfg(feature="curses")]
27#[cfg_attr(docsrs, doc(cfg(feature="curses")))]
28pub mod curses;
29#[cfg(feature="curses")]
30#[cfg_attr(docsrs, doc(cfg(feature="curses")))]
31pub use self::curses::Curses;
32#[cfg(feature="opengl")]
33#[cfg_attr(docsrs, doc(cfg(feature="opengl")))]
34pub mod opengl;
35#[cfg(feature="opengl")]
36#[cfg_attr(docsrs, doc(cfg(feature="opengl")))]
37pub use self::opengl::Opengl;
38// audio
39#[cfg(feature="fmod")]
40#[cfg_attr(docsrs, doc(cfg(feature="fmod")))]
41pub mod fmod;
42#[cfg(feature="fmod")]
43#[cfg_attr(docsrs, doc(cfg(feature="fmod")))]
44pub use self::fmod::Fmod;
45
46/// Implements a means of getting input and displaying view data
47pub trait Presentation {
48  fn with_root (root : View, root_id : NodeId) -> Self;
49  /// Overridable constructor allowing the presentation backend to do custom
50  /// initialization of the interface, e.g. initializing the root screen element of a
51  /// graphical interface.
52  fn make_interface <A : Application> () -> Interface <A, Self> where Self : Sized {
53    Interface::with_root (Element::default())
54  }
55  fn get_input (&mut self, input_buffer : &mut Vec <view::Input>);
56  fn display_view <V : AsRef <View>> (&mut self,
57    view_tree      : &Tree <V>,
58    display_values : std::vec::Drain <(NodeId, view::Display)>);
59}
60
61/// Marker trait for backends with graphics capabilities
62pub trait Graphics : Presentation { }
63/// Marker trait for backends with audio capabilities
64pub trait Audio    : Presentation { }
65/// Get the graphics component from a capable backend
66pub trait HasGraphics <G : Graphics> {
67  fn graphics (&mut self) -> &mut G;
68}
69/// A presentation backend with both graphics and audio components
70// TODO: HasAudio trait ?
71#[derive(Debug)]
72#[expect(clippy::type_complexity)]
73pub struct Composite <G : Graphics, A : Audio> {
74  pub graphics    : G,
75  pub audio       : A,
76  display_buffers : (Vec <(NodeId, view::Display)>, Vec <(NodeId, view::Display)>)
77}
78impl <G, A> Presentation for Composite <G, A> where
79  G : Graphics,
80  A : Audio
81{
82  fn with_root (root : View, root_id : NodeId) -> Self {
83    let graphics        = G::with_root (root.clone(), root_id.clone());
84    let audio           = A::with_root (root, root_id);
85    let display_buffers = (vec![], vec![]);
86    Composite { graphics, audio, display_buffers }
87  }
88  /// Uses the graphical presentation backend to create an initialized interface
89  fn make_interface <APP : Application> () -> Interface <APP, Self> where Self : Sized {
90    let graphical = G::make_interface();
91    let root      = graphical.root_node().data().view.clone();
92    let root_id   = graphical.root_id().clone();
93    graphical.swap_presentation (|graphics| {
94      let audio           = A::with_root (root, root_id);
95      let display_buffers = (vec![], vec![]);
96      Composite { graphics, audio, display_buffers }
97    })
98  }
99  fn get_input (&mut self, input_buffer : &mut Vec <view::Input>) {
100    self.graphics.get_input (input_buffer);
101    self.audio.get_input (input_buffer);
102  }
103  fn display_view <V : AsRef <View>> (&mut self,
104    view_tree      : &Tree <V>,
105    display_values : std::vec::Drain <(NodeId, view::Display)>
106  ) {
107    self.display_buffers.0 = display_values.collect();
108    self.display_buffers.1 = self.display_buffers.0.clone();
109    self.graphics.display_view (view_tree, self.display_buffers.0.drain(..));
110    self.audio.display_view    (view_tree, self.display_buffers.1.drain(..));
111  }
112}
113
114impl <G, A> HasGraphics <G> for Composite <G, A> where
115  G : Graphics,
116  A : Audio
117{
118  fn graphics (&mut self) -> &mut G {
119    &mut self.graphics
120  }
121}
122
123impl <G : Graphics> HasGraphics <G> for G {
124  fn graphics (&mut self) -> &mut G {
125    self
126  }
127}