raui_material/component/containers/
window_paper.rs1use crate::{
2 component::containers::wrap_paper::wrap_paper,
3 theme::{ThemeColor, ThemedWidgetProps},
4};
5use raui_core::{
6 PropsData, Scalar, make_widget, unpack_named_slots,
7 widget::{
8 component::containers::{
9 horizontal_box::horizontal_box, vertical_box::vertical_box, wrap_box::WrapBoxProps,
10 },
11 context::WidgetContext,
12 node::WidgetNode,
13 unit::flex::FlexBoxItemLayout,
14 utils::Rect,
15 },
16};
17use serde::{Deserialize, Serialize};
18
19#[derive(PropsData, Debug, Clone, Serialize, Deserialize)]
20#[props_data(raui_core::props::PropsData)]
21#[prefab(raui_core::Prefab)]
22pub struct WindowPaperProps {
23 #[serde(default)]
24 pub bar_color: ThemeColor,
25 #[serde(default = "WindowPaperProps::default_bar_margin")]
26 pub bar_margin: Rect,
27 #[serde(default = "WindowPaperProps::default_bar_height")]
28 pub bar_height: Option<Scalar>,
29 #[serde(default = "WindowPaperProps::default_content_margin")]
30 pub content_margin: Rect,
31}
32
33impl Default for WindowPaperProps {
34 fn default() -> Self {
35 Self {
36 bar_color: ThemeColor::Primary,
37 bar_margin: Self::default_bar_margin(),
38 bar_height: Self::default_bar_height(),
39 content_margin: Self::default_content_margin(),
40 }
41 }
42}
43
44impl WindowPaperProps {
45 fn default_bar_margin() -> Rect {
46 Rect {
47 left: 10.0,
48 right: 10.0,
49 top: 4.0,
50 bottom: 4.0,
51 }
52 }
53
54 fn default_bar_height() -> Option<Scalar> {
55 Some(32.0)
56 }
57
58 fn default_content_margin() -> Rect {
59 10.0.into()
60 }
61}
62
63pub fn window_paper(context: WidgetContext) -> WidgetNode {
64 let WidgetContext {
65 idref,
66 key,
67 props,
68 named_slots,
69 ..
70 } = context;
71 unpack_named_slots!(named_slots => {content, bar});
72
73 let window_props = props.read_cloned_or_default::<WindowPaperProps>();
74
75 make_widget!(vertical_box)
76 .key(key)
77 .maybe_idref(idref.cloned())
78 .merge_props(props.clone())
79 .listed_slot(
80 make_widget!(wrap_paper)
81 .key("bar")
82 .with_props(ThemedWidgetProps {
83 color: window_props.bar_color,
84 ..Default::default()
85 })
86 .with_props(WrapBoxProps {
87 margin: window_props.bar_margin,
88 ..Default::default()
89 })
90 .with_props(FlexBoxItemLayout {
91 basis: window_props.bar_height,
92 grow: 0.0,
93 shrink: 0.0,
94 ..Default::default()
95 })
96 .named_slot("content", bar),
97 )
98 .listed_slot(
99 make_widget!(wrap_paper)
100 .key("content")
101 .with_props(WrapBoxProps {
102 margin: window_props.content_margin,
103 ..Default::default()
104 })
105 .named_slot("content", content),
106 )
107 .into()
108}
109
110pub fn window_title_controls_paper(context: WidgetContext) -> WidgetNode {
111 let WidgetContext {
112 key, named_slots, ..
113 } = context;
114 unpack_named_slots!(named_slots => {content, title, controls});
115
116 let mut controls = if let WidgetNode::Tuple(nodes) = controls {
117 make_widget!(horizontal_box).listed_slots(nodes).into()
118 } else {
119 controls
120 };
121 controls.remap_props(|p| {
122 if p.has::<FlexBoxItemLayout>() {
123 p
124 } else {
125 p.with(FlexBoxItemLayout {
126 grow: 0.0,
127 shrink: 0.0,
128 ..Default::default()
129 })
130 }
131 });
132
133 make_widget!(window_paper)
134 .key(key)
135 .named_slot(
136 "bar",
137 make_widget!(horizontal_box)
138 .key("bar")
139 .listed_slot(title)
140 .listed_slot(controls),
141 )
142 .named_slot("content", content)
143 .into()
144}