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