narui_core/eval/
fragment.rs

1use crate::{
2    util::geom::{Rect, Vec2},
3    vulkano_render::{lyon::ColoredBuffersBuilder, subpass_stack::AbstractImageView},
4    CallbackContext,
5    Color,
6    Dimension,
7    Key,
8    WidgetContext,
9};
10use derivative::Derivative;
11use freelist::Idx;
12use rutter_layout::Layout;
13use smallvec::{smallvec, SmallVec};
14use std::{rc::Rc, sync::Arc};
15use vulkano::{
16    command_buffer::SecondaryAutoCommandBuffer,
17    pipeline::graphics::viewport::Viewport,
18    render_pass::RenderPass,
19};
20
21/*
22The general flow of a frame in narui:
23Evaluation -> Layout -> Rendering
24
251. Evaluation
26the output of this Stage is a tree of LayoutObjects
27
282. Layout
29the outputs of this stage are PositionedRenderObjects
30
313. Rendering
32the output of this stage is the visual output :). profit!
33
34 */
35
36/// Fragment is merely a reference (for performance reasons)
37#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
38pub struct Fragment(pub(crate) u32);
39impl From<Key> for Fragment {
40    fn from(key: Key) -> Self { Fragment(key.0) }
41}
42impl From<Fragment> for Idx {
43    fn from(fragment: Fragment) -> Self { unsafe { Idx::new_unchecked(fragment.0 as _) } }
44}
45impl From<Fragment> for Key {
46    fn from(fragment: Fragment) -> Self { Key(fragment.0) }
47}
48impl From<Fragment> for FragmentChildren {
49    fn from(fragment: Fragment) -> Self { smallvec![fragment] }
50}
51impl From<Idx> for Fragment {
52    fn from(idx: Idx) -> Self { Fragment(idx.get() as _) }
53}
54pub type FragmentChildren = SmallVec<[Fragment; 8]>;
55
56
57#[derive(Derivative)]
58#[derivative(Debug)]
59pub struct UnevaluatedFragment {
60    pub key: Key,
61    #[derivative(Debug = "ignore")]
62    pub gen: Option<Box<dyn Fn(&mut WidgetContext) -> FragmentInner>>,
63}
64impl PartialEq for UnevaluatedFragment {
65    fn eq(&self, other: &Self) -> bool { self.key == other.key }
66}
67
68pub type SubPassRenderFunction = Rc<
69    dyn Fn(
70        &CallbackContext,
71        AbstractImageView, // color
72        AbstractImageView, // depth
73        Arc<RenderPass>,
74        Viewport, // viewport of target
75        [u32; 2], // dimensions of target
76        Rect,     // absolute layout rect of self
77        Rect,     // layout rect of self relative to next higher subpass
78        f32,      // z_index
79    ) -> SecondaryAutoCommandBuffer,
80>;
81
82#[derive(Clone)]
83pub struct SubPassSetup {
84    pub resolve: SubPassRenderFunction,
85    // finish function, + (optional) subpass key, before whose parent subpass pop we want to
86    // execute the finish function by default executes the finish function before the next
87    // higher subpass pop
88    pub finish: Option<(SubPassRenderFunction, Option<usize>)>,
89}
90
91#[derive(Derivative)]
92#[derivative(Debug)]
93pub enum FragmentInner {
94    Leaf {
95        render_object: RenderObject,
96        layout: Box<dyn Layout>,
97    },
98    Node {
99        children: FragmentChildren,
100        layout: Box<dyn Layout>,
101        is_clipper: bool,
102        #[derivative(Debug = "ignore")]
103        subpass: Option<SubPassSetup>,
104    },
105}
106impl FragmentInner {
107    pub fn unpack(
108        self,
109    ) -> (Box<dyn Layout>, Option<RenderObject>, FragmentChildren, bool, Option<SubPassSetup>) {
110        match self {
111            Self::Leaf { render_object, layout } => {
112                (layout, Some(render_object), SmallVec::new(), false, None)
113            }
114            Self::Node { children, layout, is_clipper, subpass } => {
115                (layout, None, children, is_clipper, subpass)
116            }
117        }
118    }
119
120    pub fn from_fragment(fragment: Fragment) -> Self {
121        FragmentInner::Node {
122            children: smallvec![fragment],
123            layout: Box::new(rutter_layout::layouts::Transparent),
124            is_clipper: false,
125            subpass: None,
126        }
127    }
128}
129
130pub type PathGenInner = dyn Fn(
131    Vec2, // size
132    &mut lyon::tessellation::FillTessellator,
133    &mut lyon::tessellation::StrokeTessellator,
134    ColoredBuffersBuilder,
135);
136pub type RenderFnInner = dyn Fn(
137    &Viewport,
138    f32,  // z_index
139    Rect, // target rect
140    Vec2, // window dimensions
141) -> SecondaryAutoCommandBuffer;
142/// RenderObject is the data structure that really defines _what_ is rendered
143#[derive(Derivative, Clone)]
144#[derivative(Debug)]
145pub enum RenderObject {
146    DebugRect,
147    RoundedRect {
148        inverted: bool,
149        stroke_color: Option<Color>,
150        fill_color: Option<Color>,
151        stroke_width: f32,
152        border_radius: Dimension,
153        for_clipping: bool,
154    },
155    Path {
156        #[derivative(Debug = "ignore")]
157        path_gen: Arc<PathGenInner>,
158    },
159    Text {
160        key: Key,
161        text: Rc<String>,
162        size: f32,
163        color: Color,
164    },
165    Input {
166        key: Key,
167        // this is nothing that gets rendered but instead it gets interpreted by the input handling
168        // logic
169        #[derivative(Debug = "ignore")]
170        on_click: Arc<dyn Fn(&CallbackContext, bool, Vec2, Vec2)>,
171        #[derivative(Debug = "ignore")]
172        on_hover: Arc<dyn Fn(&CallbackContext, bool, Vec2, Vec2)>,
173        #[derivative(Debug = "ignore")]
174        on_move: Arc<dyn Fn(&CallbackContext, Vec2, Vec2)>,
175    },
176    Raw {
177        #[derivative(Debug = "ignore")]
178        render_fn: Arc<RenderFnInner>,
179    },
180    None,
181}