zng_wgt_window/
fallback_chrome.rs1use zng_ext_window::{cmd::*, *};
2use zng_wgt::{prelude::*, *};
3use zng_wgt_button::Button;
4use zng_wgt_container::*;
5use zng_wgt_fill::*;
6use zng_wgt_input::{mouse::*, *};
7use zng_wgt_stack::{Stack, StackDirection};
8use zng_wgt_text::Text;
9
10pub fn fallback_chrome() -> UiNode {
14 let vars = WINDOW.vars();
15 let can_move = vars.state().map(|s| matches!(s, WindowState::Normal | WindowState::Maximized));
16 let win_id = WINDOW.id();
17 let title = Text! {
18 txt = vars.title();
19 align = Align::FILL_TOP;
20 background_color = light_dark(colors::WHITE, colors::BLACK);
21 zng_wgt_size_offset::height = 28;
22 txt_align = Align::CENTER;
23
24 child_right = Stack! {
25 direction = StackDirection::left_to_right();
26 zng_wgt_button::style_fn = zng_wgt_button::LightStyle! {
27 corner_radius = 0;
28 zng_wgt_button::cmd_child_fn = wgt_fn!(|cmd: Command| {
29 presenter(
30 (),
31 cmd.icon().map(move |ico| {
32 wgt_fn!(ico, |_| {
33 let ico = ico(());
34 if ico.is_nil() {
35 let cmd = cmd.scoped(zng_app::event::CommandScope::App);
37 let (symbol, size, padding_top) = if cmd == RESTORE_CMD {
38 ("🗗", 9, 0)
39 } else if cmd == MINIMIZE_CMD {
40 ("🗕", 9, 0)
41 } else if cmd == MAXIMIZE_CMD {
42 ("🗖", 9, 0)
43 } else if cmd == CLOSE_CMD {
44 ("🗙", 12, -5)
45 } else {
46 unreachable!("{cmd:?} what")
47 };
48 Text! {
49 font_family = "Noto Sans Symbols 2";
50 font_size = size.pt();
51 padding = (padding_top, 0, 0, 0);
52 txt = symbol;
53 }
54 } else {
55 ico
56 }
57 })
58 }),
59 )
60 });
61 };
62 children = ui_vec![
63 Button! {
64 cmd = MINIMIZE_CMD.scoped(win_id);
65 },
66 Button! {
67 cmd = MAXIMIZE_CMD.scoped(win_id);
68 when #is_disabled {
69 visibility = false;
70 }
71 },
72 Button! {
73 cmd = RESTORE_CMD.scoped(win_id);
74 when #is_disabled {
75 visibility = false;
76 }
77 },
78 Button! {
79 cmd = CLOSE_CMD.scoped(win_id);
80 },
81 ];
82 };
83
84 when *#{can_move.clone()} {
85 cursor = CursorIcon::Move;
86 }
87 mouse::on_mouse_down = hn!(|args| {
88 if args.is_primary() && can_move.get() && args.target.widget_id() == WIDGET.id() {
89 DRAG_MOVE_RESIZE_CMD.scoped(WINDOW.id()).notify();
90 }
91 });
92
93 gesture::on_context_click = hn!(|args| {
94 if matches!(WINDOW.vars().state().get(), WindowState::Normal | WindowState::Maximized)
95 && args.target.widget_id() == WIDGET.id()
96 && let Some(p) = args.position()
97 {
98 OPEN_TITLE_BAR_CONTEXT_MENU_CMD.scoped(WINDOW.id()).notify_param(p);
99 }
100 });
101 };
102
103 use zng_ext_window::cmd::ResizeDirection as RD;
104
105 fn resize_direction(wgt_pos: PxPoint) -> Option<RD> {
106 let p = wgt_pos;
107 let s = WIDGET.bounds().inner_size();
108 let b = WIDGET.border().offsets();
109 let corner_b = b * FactorSideOffsets::from(3.fct());
110
111 if p.x <= b.left {
112 if p.y <= corner_b.top {
113 Some(RD::NorthWest)
114 } else if p.y >= s.height - corner_b.bottom {
115 Some(RD::SouthWest)
116 } else {
117 Some(RD::West)
118 }
119 } else if p.x >= s.width - b.right {
120 if p.y <= corner_b.top {
121 Some(RD::NorthEast)
122 } else if p.y >= s.height - corner_b.bottom {
123 Some(RD::SouthEast)
124 } else {
125 Some(RD::East)
126 }
127 } else if p.y <= b.top {
128 if p.x <= corner_b.left {
129 Some(RD::NorthWest)
130 } else if p.x >= s.width - corner_b.right {
131 Some(RD::NorthEast)
132 } else {
133 Some(RD::North)
134 }
135 } else if p.y >= s.height - b.bottom {
136 if p.x <= corner_b.left {
137 Some(RD::SouthWest)
138 } else if p.x >= s.width - corner_b.right {
139 Some(RD::SouthEast)
140 } else {
141 Some(RD::South)
142 }
143 } else {
144 None
145 }
146 }
147
148 let cursor = var(CursorSource::Hidden);
149
150 Container! {
151 exclude_text_context = true;
152
153 hit_test_mode = HitTestMode::Detailed;
154
155 child = title;
156
157 when matches!(#{vars.state()}, WindowState::Normal) {
158 border = 5, light_dark(colors::WHITE, colors::BLACK).rgba().map_into();
159 cursor = cursor.clone();
160 on_mouse_move = hn!(|args| {
161 cursor.set(match args.position_wgt().and_then(resize_direction) {
162 Some(d) => CursorIcon::from(d).into(),
163 None => CursorSource::Hidden,
164 });
165 });
166 on_mouse_down = hn!(|args| {
167 if args.is_primary()
168 && let Some(d) = args.position_wgt().and_then(resize_direction)
169 {
170 DRAG_MOVE_RESIZE_CMD.scoped(WINDOW.id()).notify_param(d);
171 }
172 });
173 }
174 }
175}
176
177#[property(WIDGET)]
178fn exclude_text_context(child: impl IntoUiNode, exclude: impl IntoValue<bool>) -> UiNode {
179 assert!(exclude.into());
180
181 let excluded_set = {
183 let mut c = ContextValueSet::new();
184 Text::context_vars_set(&mut c);
185 c
186 };
187 let child = match_node(child, move |c, op| {
188 let mut filtered = LocalContext::capture_filtered(CaptureFilter::Exclude(excluded_set.clone()));
189 filtered.with_context(|| {
190 c.op(op);
191 });
192 });
193
194 zng_wgt_text::font_size(child, 16)
196}