Implemented widget access from UiNode and UiNodeList.
This commit is contained in:
parent
21b4000828
commit
37848fc178
|
@ -4,4 +4,5 @@
|
||||||
|
|
||||||
* Review layout double-pass of stacks.
|
* Review layout double-pass of stacks.
|
||||||
* Fix text final size, either clip or return accurate size.
|
* Fix text final size, either clip or return accurate size.
|
||||||
* Get Widget from UiNode (at least to avoid having to do custom reference frames in fill_node).
|
|
||||||
|
* Test scroll to end when the height changes by scrolling.
|
|
@ -13,7 +13,7 @@ pub fn first_and_last_window_events() {
|
||||||
|
|
||||||
let root_id = WidgetId::new_unique();
|
let root_id = WidgetId::new_unique();
|
||||||
let stack_id = WidgetId::new_unique();
|
let stack_id = WidgetId::new_unique();
|
||||||
let button_0_id = buttons.widget_id(0);
|
let button_0_id = buttons.item_id(0);
|
||||||
|
|
||||||
let mut app = TestApp::new_w(window! {
|
let mut app = TestApp::new_w(window! {
|
||||||
content = v_stack!(id = stack_id; items = buttons);
|
content = v_stack!(id = stack_id; items = buttons);
|
||||||
|
@ -87,7 +87,7 @@ pub fn window_tab_cycle_index_auto() {
|
||||||
button! { content = text("Button 2"); tab_index = tab_ids[2] },
|
button! { content = text("Button 2"); tab_index = tab_ids[2] },
|
||||||
];
|
];
|
||||||
// we collect the widget_id values in the TAB navigation order.
|
// we collect the widget_id values in the TAB navigation order.
|
||||||
let mut ids: Vec<_> = (0..3).map(|i| (buttons.widget_id(i), tab_ids[i])).collect();
|
let mut ids: Vec<_> = (0..3).map(|i| (buttons.item_id(i), tab_ids[i])).collect();
|
||||||
ids.sort_by_key(|(_, ti)| *ti);
|
ids.sort_by_key(|(_, ti)| *ti);
|
||||||
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ pub fn window_tab_cycle_and_alt_scope() {
|
||||||
button! { content = text("Button 0"); tab_index = tab_ids[0] },
|
button! { content = text("Button 0"); tab_index = tab_ids[0] },
|
||||||
button! { content = text("Button 1"); tab_index = tab_ids[1] },
|
button! { content = text("Button 1"); tab_index = tab_ids[1] },
|
||||||
];
|
];
|
||||||
let mut ids: Vec<_> = (0..2).map(|i| (buttons.widget_id(i), tab_ids[i])).collect();
|
let mut ids: Vec<_> = (0..2).map(|i| (buttons.item_id(i), tab_ids[i])).collect();
|
||||||
ids.sort_by_key(|(_, ti)| *ti);
|
ids.sort_by_key(|(_, ti)| *ti);
|
||||||
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ pub fn window_tab_cycle_and_alt_scope() {
|
||||||
button! { content = text("Alt 1"); tab_index = tab_ids[3] },
|
button! { content = text("Alt 1"); tab_index = tab_ids[3] },
|
||||||
button! { content = text("Alt 2"); tab_index = tab_ids[4] },
|
button! { content = text("Alt 2"); tab_index = tab_ids[4] },
|
||||||
];
|
];
|
||||||
let mut alt_ids: Vec<_> = (0..3).map(|i| (alt_buttons.widget_id(i), tab_ids[i + 2])).collect();
|
let mut alt_ids: Vec<_> = (0..3).map(|i| (alt_buttons.item_id(i), tab_ids[i + 2])).collect();
|
||||||
alt_ids.sort_by_key(|(_, ti)| *ti);
|
alt_ids.sort_by_key(|(_, ti)| *ti);
|
||||||
let alt_ids: Vec<_> = alt_ids.into_iter().map(|(id, _)| id).collect();
|
let alt_ids: Vec<_> = alt_ids.into_iter().map(|(id, _)| id).collect();
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ fn window_tab_contained_and_continue(tab_nav: TabNav) {
|
||||||
button! { content = text("Button 2"); tab_index = tab_ids[2] },
|
button! { content = text("Button 2"); tab_index = tab_ids[2] },
|
||||||
];
|
];
|
||||||
// we collect the widget_id values in the TAB navigation order.
|
// we collect the widget_id values in the TAB navigation order.
|
||||||
let mut ids: Vec<_> = (0..3).map(|i| (buttons.widget_id(i), tab_ids[i])).collect();
|
let mut ids: Vec<_> = (0..3).map(|i| (buttons.item_id(i), tab_ids[i])).collect();
|
||||||
ids.sort_by_key(|(_, ti)| *ti);
|
ids.sort_by_key(|(_, ti)| *ti);
|
||||||
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ fn window_tab_once_and_none(tab_nav: TabNav) {
|
||||||
button! { content = text("Button 2"); tab_index = tab_ids[2] },
|
button! { content = text("Button 2"); tab_index = tab_ids[2] },
|
||||||
];
|
];
|
||||||
// we collect the widget_id values in the TAB navigation order.
|
// we collect the widget_id values in the TAB navigation order.
|
||||||
let mut ids: Vec<_> = (0..3).map(|i| (buttons.widget_id(i), tab_ids[i])).collect();
|
let mut ids: Vec<_> = (0..3).map(|i| (buttons.item_id(i), tab_ids[i])).collect();
|
||||||
ids.sort_by_key(|(_, ti)| *ti);
|
ids.sort_by_key(|(_, ti)| *ti);
|
||||||
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
let ids: Vec<_> = ids.into_iter().map(|(id, _)| id).collect();
|
||||||
|
|
||||||
|
@ -328,14 +328,14 @@ fn two_continue_scopes_or_containers_in_tab_cycle_window(focus_scope: bool) {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids_a: Vec<_> = (0..3).map(|i| buttons_a.widget_id(i)).collect();
|
let ids_a: Vec<_> = (0..3).map(|i| buttons_a.item_id(i)).collect();
|
||||||
|
|
||||||
let buttons_b = widgets![
|
let buttons_b = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids_b: Vec<_> = (0..3).map(|i| buttons_b.widget_id(i)).collect();
|
let ids_b: Vec<_> = (0..3).map(|i| buttons_b.item_id(i)).collect();
|
||||||
|
|
||||||
let a = v_stack! {
|
let a = v_stack! {
|
||||||
items = buttons_a;
|
items = buttons_a;
|
||||||
|
@ -409,14 +409,14 @@ pub fn two_continue_scopes_with_mixed_indexes() {
|
||||||
button! { content = text("Button 2"); tab_index = 5; },
|
button! { content = text("Button 2"); tab_index = 5; },
|
||||||
button! { content = text("Button 1"); tab_index = 3; },
|
button! { content = text("Button 1"); tab_index = 3; },
|
||||||
];
|
];
|
||||||
let ids_a: Vec<_> = (0..3).map(|i| buttons_a.widget_id(i)).collect();
|
let ids_a: Vec<_> = (0..3).map(|i| buttons_a.item_id(i)).collect();
|
||||||
|
|
||||||
let buttons_b = widgets![
|
let buttons_b = widgets![
|
||||||
button! { content = text("Button 3"); tab_index = 2; },
|
button! { content = text("Button 3"); tab_index = 2; },
|
||||||
button! { content = text("Button 4"); tab_index = 4; },
|
button! { content = text("Button 4"); tab_index = 4; },
|
||||||
button! { content = text("Button 5"); tab_index = 6; },
|
button! { content = text("Button 5"); tab_index = 6; },
|
||||||
];
|
];
|
||||||
let ids_b: Vec<_> = (0..3).map(|i| buttons_b.widget_id(i)).collect();
|
let ids_b: Vec<_> = (0..3).map(|i| buttons_b.item_id(i)).collect();
|
||||||
|
|
||||||
let a = v_stack! {
|
let a = v_stack! {
|
||||||
items = buttons_a;
|
items = buttons_a;
|
||||||
|
@ -481,14 +481,14 @@ pub fn two_containers_with_mixed_indexes() {
|
||||||
button! { content = text("Button 2"); tab_index = 5; },
|
button! { content = text("Button 2"); tab_index = 5; },
|
||||||
button! { content = text("Button 1"); tab_index = 3; },
|
button! { content = text("Button 1"); tab_index = 3; },
|
||||||
];
|
];
|
||||||
let ids_a: Vec<_> = (0..3).map(|i| buttons_a.widget_id(i)).collect();
|
let ids_a: Vec<_> = (0..3).map(|i| buttons_a.item_id(i)).collect();
|
||||||
|
|
||||||
let buttons_b = widgets![
|
let buttons_b = widgets![
|
||||||
button! { content = text("Button 3"); tab_index = 2; },
|
button! { content = text("Button 3"); tab_index = 2; },
|
||||||
button! { content = text("Button 4"); tab_index = 4; },
|
button! { content = text("Button 4"); tab_index = 4; },
|
||||||
button! { content = text("Button 5"); tab_index = 6; },
|
button! { content = text("Button 5"); tab_index = 6; },
|
||||||
];
|
];
|
||||||
let ids_b: Vec<_> = (0..3).map(|i| buttons_b.widget_id(i)).collect();
|
let ids_b: Vec<_> = (0..3).map(|i| buttons_b.item_id(i)).collect();
|
||||||
|
|
||||||
let a = v_stack(buttons_a);
|
let a = v_stack(buttons_a);
|
||||||
let b = v_stack(buttons_b);
|
let b = v_stack(buttons_b);
|
||||||
|
@ -539,7 +539,7 @@ pub fn tab_index_skip() {
|
||||||
button! { content = text("Button 1"); tab_index = TabIndex::SKIP; },
|
button! { content = text("Button 1"); tab_index = TabIndex::SKIP; },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(buttons));
|
let mut app = TestApp::new(v_stack(buttons));
|
||||||
|
|
||||||
|
@ -562,13 +562,13 @@ pub fn tab_inner_container() {
|
||||||
// sanity check for `tab_skip_inner_container`.
|
// sanity check for `tab_skip_inner_container`.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack(inner_buttons),
|
v_stack(inner_buttons),
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -595,7 +595,7 @@ pub fn tab_skip_inner_container() {
|
||||||
// directly.
|
// directly.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack! {
|
v_stack! {
|
||||||
|
@ -604,7 +604,7 @@ pub fn tab_skip_inner_container() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -643,7 +643,7 @@ pub fn tab_inner_scope_continue() {
|
||||||
// sanity check for `tab_skip_inner_scope_continue`.
|
// sanity check for `tab_skip_inner_scope_continue`.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack! {
|
v_stack! {
|
||||||
|
@ -653,7 +653,7 @@ pub fn tab_inner_scope_continue() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -680,7 +680,7 @@ pub fn tab_skip_inner_scope_continue() {
|
||||||
// directly.
|
// directly.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack! {
|
v_stack! {
|
||||||
|
@ -691,7 +691,7 @@ pub fn tab_skip_inner_scope_continue() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -730,7 +730,7 @@ pub fn tab_inner_scope_cycle() {
|
||||||
// we expect tab navigation to enter the inner scope and get trapped in there.
|
// we expect tab navigation to enter the inner scope and get trapped in there.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack! {
|
v_stack! {
|
||||||
|
@ -740,7 +740,7 @@ pub fn tab_inner_scope_cycle() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -772,7 +772,7 @@ pub fn tab_inner_scope_contained() {
|
||||||
// we expect tab navigation to enter the inner scope and get trapped in there.
|
// we expect tab navigation to enter the inner scope and get trapped in there.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack! {
|
v_stack! {
|
||||||
|
@ -782,7 +782,7 @@ pub fn tab_inner_scope_contained() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -814,7 +814,7 @@ pub fn tab_inner_scope_once() {
|
||||||
// we expect tab navigation to enter the inner scope but then leave it.
|
// we expect tab navigation to enter the inner scope but then leave it.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack! {
|
v_stack! {
|
||||||
|
@ -824,7 +824,7 @@ pub fn tab_inner_scope_once() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -850,7 +850,7 @@ pub fn tab_inner_scope_none() {
|
||||||
// we expect tab navigation to enter the inner scope and then not move.
|
// we expect tab navigation to enter the inner scope and then not move.
|
||||||
|
|
||||||
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
let inner_buttons = widgets![button! { content = text("Button 1") }, button! { content = text("Button 2") },];
|
||||||
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.widget_id(i)).collect();
|
let inner_ids: Vec<_> = (0..2).map(|i| inner_buttons.item_id(i)).collect();
|
||||||
let items = widgets![
|
let items = widgets![
|
||||||
button! { content = text("Button 0") },
|
button! { content = text("Button 0") },
|
||||||
v_stack! {
|
v_stack! {
|
||||||
|
@ -860,7 +860,7 @@ pub fn tab_inner_scope_none() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 3") },
|
button! { content = text("Button 3") },
|
||||||
];
|
];
|
||||||
let item_ids: Vec<_> = (0..3).map(|i| items.widget_id(i)).collect();
|
let item_ids: Vec<_> = (0..3).map(|i| items.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(items));
|
let mut app = TestApp::new(v_stack(items));
|
||||||
|
|
||||||
|
@ -996,7 +996,7 @@ fn focused_removed_test(button1: impl Widget, set_var: impl FnOnce(&Vars)) {
|
||||||
button1,
|
button1,
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(buttons));
|
let mut app = TestApp::new(v_stack(buttons));
|
||||||
|
|
||||||
|
@ -1212,7 +1212,7 @@ pub fn directional_focus_up() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(buttons));
|
let mut app = TestApp::new(v_stack(buttons));
|
||||||
|
|
||||||
|
@ -1233,7 +1233,7 @@ pub fn directional_focus_down() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(buttons));
|
let mut app = TestApp::new(v_stack(buttons));
|
||||||
|
|
||||||
|
@ -1253,7 +1253,7 @@ pub fn directional_focus_left() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(h_stack(buttons));
|
let mut app = TestApp::new(h_stack(buttons));
|
||||||
|
|
||||||
|
@ -1274,7 +1274,7 @@ pub fn directional_focus_right() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(h_stack(buttons));
|
let mut app = TestApp::new(h_stack(buttons));
|
||||||
|
|
||||||
|
@ -1294,7 +1294,7 @@ pub fn directional_cycle_vertical() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new_w(window! {
|
let mut app = TestApp::new_w(window! {
|
||||||
directional_nav = DirectionalNav::Cycle;
|
directional_nav = DirectionalNav::Cycle;
|
||||||
|
@ -1316,7 +1316,7 @@ pub fn directional_cycle_horizontal() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new_w(window! {
|
let mut app = TestApp::new_w(window! {
|
||||||
directional_nav = DirectionalNav::Cycle;
|
directional_nav = DirectionalNav::Cycle;
|
||||||
|
@ -1338,7 +1338,7 @@ pub fn directional_contained_vertical() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new_w(window! {
|
let mut app = TestApp::new_w(window! {
|
||||||
directional_nav = DirectionalNav::Contained;
|
directional_nav = DirectionalNav::Contained;
|
||||||
|
@ -1360,7 +1360,7 @@ pub fn directional_contained_horizontal() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new_w(window! {
|
let mut app = TestApp::new_w(window! {
|
||||||
directional_nav = DirectionalNav::Contained;
|
directional_nav = DirectionalNav::Contained;
|
||||||
|
@ -1383,7 +1383,7 @@ pub fn directional_none() {
|
||||||
button! { content = text("Button 1") },
|
button! { content = text("Button 1") },
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new_w(window! {
|
let mut app = TestApp::new_w(window! {
|
||||||
directional_nav = DirectionalNav::None;
|
directional_nav = DirectionalNav::None;
|
||||||
|
@ -1417,7 +1417,7 @@ pub fn directional_continue_up() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(buttons));
|
let mut app = TestApp::new(v_stack(buttons));
|
||||||
|
|
||||||
|
@ -1442,7 +1442,7 @@ pub fn directional_continue_down() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(v_stack(buttons));
|
let mut app = TestApp::new(v_stack(buttons));
|
||||||
|
|
||||||
|
@ -1467,7 +1467,7 @@ pub fn directional_continue_left() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(h_stack(buttons));
|
let mut app = TestApp::new(h_stack(buttons));
|
||||||
|
|
||||||
|
@ -1492,7 +1492,7 @@ pub fn directional_continue_right() {
|
||||||
},
|
},
|
||||||
button! { content = text("Button 2") },
|
button! { content = text("Button 2") },
|
||||||
];
|
];
|
||||||
let ids: Vec<_> = (0..3).map(|i| buttons.widget_id(i)).collect();
|
let ids: Vec<_> = (0..3).map(|i| buttons.item_id(i)).collect();
|
||||||
|
|
||||||
let mut app = TestApp::new(h_stack(buttons));
|
let mut app = TestApp::new(h_stack(buttons));
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,54 @@ pub trait UiNodeList: 'static {
|
||||||
|
|
||||||
/// Calls [`UiNode::render_update`] in only the `index` node or widget.
|
/// Calls [`UiNode::render_update`] in only the `index` node or widget.
|
||||||
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate);
|
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate);
|
||||||
|
|
||||||
|
/// Gets the id of the widget at the `index` if the node is a full widget.
|
||||||
|
///
|
||||||
|
/// The index is zero-based.
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId>;
|
||||||
|
|
||||||
|
/// Reference the state of the widget at the `index`.
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap>;
|
||||||
|
|
||||||
|
/// Exclusive reference the state of the widget at the `index`.
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap>;
|
||||||
|
|
||||||
|
/// Gets the bounds layout info of the node at the `index` if it is a full widget.
|
||||||
|
///
|
||||||
|
/// See [`Widget::bounds_info`] for more details.
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo>;
|
||||||
|
|
||||||
|
/// Gets the border and corners info from the node at the `index` if it is a full widget.
|
||||||
|
///
|
||||||
|
/// See [`Widget::border_info`] for more details.
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo>;
|
||||||
|
|
||||||
|
/// Gets the render info from the node at the `index` if it is a full widget.
|
||||||
|
///
|
||||||
|
/// See [`Widget::render_info`] for more details.
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo>;
|
||||||
|
|
||||||
|
/// Calls [`UiNode::render`] in all nodes allowed by a `filter`, skips rendering the rest.
|
||||||
|
fn render_node_filtered<F>(&self, filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool;
|
||||||
|
|
||||||
|
/// Calls [`WidgetLayout::try_with_outer`] in only the `index` node. The `transform` closure only runs if the node
|
||||||
|
/// is a full widget.
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R;
|
||||||
|
|
||||||
|
/// Calls [`WidgetLayout::try_with_outer`] in all nodes on the list. The `transform` closures only runs for the nodes
|
||||||
|
/// that are full widgets.
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs);
|
||||||
|
|
||||||
|
/// Count nodes that pass the `filter`.
|
||||||
|
fn count_nodes<F>(&self, filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arguments for the closure in [`UiNodeList::layout_all`] that runs before each child is layout.
|
/// Arguments for the closure in [`UiNodeList::layout_all`] that runs before each child is layout.
|
||||||
|
@ -127,7 +175,7 @@ pub struct PreLayoutArgs<'a> {
|
||||||
|
|
||||||
/// Mutable reference to the widget state.
|
/// Mutable reference to the widget state.
|
||||||
///
|
///
|
||||||
/// Is `None` in lists that only implement [`UiNodeList`].
|
/// Can be `None` in [`UiNodeList`] for nodes that are not full widgets.
|
||||||
pub state: Option<&'a mut StateMap>,
|
pub state: Option<&'a mut StateMap>,
|
||||||
|
|
||||||
/// Constrains overwrite just for this child.
|
/// Constrains overwrite just for this child.
|
||||||
|
@ -151,10 +199,10 @@ pub struct PosLayoutArgs<'a> {
|
||||||
|
|
||||||
/// Mutable reference to the widget state.
|
/// Mutable reference to the widget state.
|
||||||
///
|
///
|
||||||
/// Is `None` in lists that only implement [`UiNodeList`].
|
/// Can be `None` in [`UiNodeList`] for nodes that are not full widgets.
|
||||||
pub state: Option<&'a mut StateMap>,
|
pub state: Option<&'a mut StateMap>,
|
||||||
|
|
||||||
/// The widget outer size.
|
/// The updated size.
|
||||||
pub size: PxSize,
|
pub size: PxSize,
|
||||||
}
|
}
|
||||||
impl<'a> PosLayoutArgs<'a> {
|
impl<'a> PosLayoutArgs<'a> {
|
||||||
|
@ -196,18 +244,20 @@ fn default_ui_node_list_layout_all<N, C, D>(
|
||||||
D: FnMut(&mut LayoutContext, &mut WidgetLayout, PosLayoutArgs),
|
D: FnMut(&mut LayoutContext, &mut WidgetLayout, PosLayoutArgs),
|
||||||
{
|
{
|
||||||
let (size, _) = wl.with_child(ctx, |ctx, wl| {
|
let (size, _) = wl.with_child(ctx, |ctx, wl| {
|
||||||
let mut args = PreLayoutArgs::new(index, None);
|
let mut args = PreLayoutArgs::new(index, node.try_state_mut());
|
||||||
pre_layout(ctx, wl, &mut args);
|
pre_layout(ctx, wl, &mut args);
|
||||||
ctx.with_constrains(|c| args.constrains.take().unwrap_or(c), |ctx| node.layout(ctx, wl))
|
ctx.with_constrains(|c| args.constrains.take().unwrap_or(c), |ctx| node.layout(ctx, wl))
|
||||||
});
|
});
|
||||||
pos_layout(ctx, wl, PosLayoutArgs::new(index, None, size));
|
pos_layout(ctx, wl, PosLayoutArgs::new(index, None, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All [`Widget`] accessible *info*.
|
/// All [`Widget`] accessible info.
|
||||||
pub struct WidgetFilterArgs<'a> {
|
pub struct WidgetFilterArgs<'a> {
|
||||||
/// The widget index in the list.
|
/// The widget index in the list.
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
|
|
||||||
|
/// The [`Widget::id`].
|
||||||
|
pub id: WidgetId,
|
||||||
/// The [`Widget::bounds_info`].
|
/// The [`Widget::bounds_info`].
|
||||||
pub bounds_info: &'a WidgetBoundsInfo,
|
pub bounds_info: &'a WidgetBoundsInfo,
|
||||||
/// The [`Widget::border_info`].
|
/// The [`Widget::border_info`].
|
||||||
|
@ -222,10 +272,11 @@ impl<'a> WidgetFilterArgs<'a> {
|
||||||
pub fn get(list: &'a impl WidgetList, index: usize) -> Self {
|
pub fn get(list: &'a impl WidgetList, index: usize) -> Self {
|
||||||
WidgetFilterArgs {
|
WidgetFilterArgs {
|
||||||
index,
|
index,
|
||||||
bounds_info: list.widget_bounds_info(index),
|
id: list.item_id(index),
|
||||||
border_info: list.widget_border_info(index),
|
bounds_info: list.item_bounds_info(index),
|
||||||
render_info: list.widget_render_info(index),
|
border_info: list.item_border_info(index),
|
||||||
state: list.widget_state(index),
|
render_info: list.item_render_info(index),
|
||||||
|
state: list.item_state(index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +284,7 @@ impl<'a> WidgetFilterArgs<'a> {
|
||||||
pub fn new(index: usize, widget: &'a impl Widget) -> Self {
|
pub fn new(index: usize, widget: &'a impl Widget) -> Self {
|
||||||
WidgetFilterArgs {
|
WidgetFilterArgs {
|
||||||
index,
|
index,
|
||||||
|
id: widget.id(),
|
||||||
bounds_info: widget.bounds_info(),
|
bounds_info: widget.bounds_info(),
|
||||||
border_info: widget.border_info(),
|
border_info: widget.border_info(),
|
||||||
render_info: widget.render_info(),
|
render_info: widget.render_info(),
|
||||||
|
@ -241,11 +293,53 @@ impl<'a> WidgetFilterArgs<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All [`UiNode`] accessible widget info.
|
||||||
|
pub struct UiNodeFilterArgs<'a> {
|
||||||
|
/// The node index in the list.
|
||||||
|
pub index: usize,
|
||||||
|
|
||||||
|
/// The [`UiNode::try_id`].
|
||||||
|
pub id: Option<WidgetId>,
|
||||||
|
/// The [`UiNode::try_bounds_info`].
|
||||||
|
pub bounds_info: Option<&'a WidgetBoundsInfo>,
|
||||||
|
/// The [`UiNode::try_border_info`].
|
||||||
|
pub border_info: Option<&'a WidgetBorderInfo>,
|
||||||
|
/// The [`UiNode::try_render_info`].
|
||||||
|
pub render_info: Option<&'a WidgetRenderInfo>,
|
||||||
|
/// The [`UiNode::try_state`].
|
||||||
|
pub state: Option<&'a StateMap>,
|
||||||
|
}
|
||||||
|
impl<'a> UiNodeFilterArgs<'a> {
|
||||||
|
/// Copy or borrow all info from a node list and index.
|
||||||
|
pub fn get(list: &'a impl UiNodeList, index: usize) -> Self {
|
||||||
|
UiNodeFilterArgs {
|
||||||
|
index,
|
||||||
|
id: list.try_item_id(index),
|
||||||
|
bounds_info: list.try_item_bounds_info(index),
|
||||||
|
border_info: list.try_item_border_info(index),
|
||||||
|
render_info: list.try_item_render_info(index),
|
||||||
|
state: list.try_item_state(index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy or borrow all info from a node reference.
|
||||||
|
pub fn new(index: usize, node: &'a impl UiNode) -> Self {
|
||||||
|
UiNodeFilterArgs {
|
||||||
|
index,
|
||||||
|
id: node.try_id(),
|
||||||
|
bounds_info: node.try_bounds_info(),
|
||||||
|
border_info: node.try_border_info(),
|
||||||
|
render_info: node.try_render_info(),
|
||||||
|
state: node.try_state(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A generic view over a list of [`Widget`] UI nodes.
|
/// A generic view over a list of [`Widget`] UI nodes.
|
||||||
///
|
///
|
||||||
/// Layout widgets should use this to abstract the children list type if possible.
|
/// Layout widgets should use this to abstract the children list type if possible.
|
||||||
pub trait WidgetList: UiNodeList {
|
pub trait WidgetList: UiNodeList {
|
||||||
/// Count widgets that pass filter using the widget state.
|
/// Count widgets that pass the `filter`.
|
||||||
fn count<F>(&self, filter: F) -> usize
|
fn count<F>(&self, filter: F) -> usize
|
||||||
where
|
where
|
||||||
F: FnMut(WidgetFilterArgs) -> bool;
|
F: FnMut(WidgetFilterArgs) -> bool;
|
||||||
|
@ -265,28 +359,28 @@ pub trait WidgetList: UiNodeList {
|
||||||
/// Gets the id of the widget at the `index`.
|
/// Gets the id of the widget at the `index`.
|
||||||
///
|
///
|
||||||
/// The index is zero-based.
|
/// The index is zero-based.
|
||||||
fn widget_id(&self, index: usize) -> WidgetId;
|
fn item_id(&self, index: usize) -> WidgetId;
|
||||||
|
|
||||||
/// Reference the state of the widget at the `index`.
|
/// Reference the state of the widget at the `index`.
|
||||||
fn widget_state(&self, index: usize) -> &StateMap;
|
fn item_state(&self, index: usize) -> &StateMap;
|
||||||
|
|
||||||
/// Exclusive reference the state of the widget at the `index`.
|
/// Exclusive reference the state of the widget at the `index`.
|
||||||
fn widget_state_mut(&mut self, index: usize) -> &mut StateMap;
|
fn item_state_mut(&mut self, index: usize) -> &mut StateMap;
|
||||||
|
|
||||||
/// Gets the bounds layout info of the widget at the `index`.
|
/// Gets the bounds layout info of the widget at the `index`.
|
||||||
///
|
///
|
||||||
/// See [`Widget::bounds_info`] for more details.
|
/// See [`Widget::bounds_info`] for more details.
|
||||||
fn widget_bounds_info(&self, index: usize) -> &WidgetBoundsInfo;
|
fn item_bounds_info(&self, index: usize) -> &WidgetBoundsInfo;
|
||||||
|
|
||||||
/// Gets the border and corners info of the widget at the `index`.
|
/// Gets the border and corners info of the widget at the `index`.
|
||||||
///
|
///
|
||||||
/// See [`Widget::border_info`] for more details.
|
/// See [`Widget::border_info`] for more details.
|
||||||
fn widget_border_info(&self, index: usize) -> &WidgetBorderInfo;
|
fn item_border_info(&self, index: usize) -> &WidgetBorderInfo;
|
||||||
|
|
||||||
/// Gets the render info the widget at the `index`.
|
/// Gets the render info the widget at the `index`.
|
||||||
///
|
///
|
||||||
/// See [`Widget::render_info`] for more details.
|
/// See [`Widget::render_info`] for more details.
|
||||||
fn widget_render_info(&self, index: usize) -> &WidgetRenderInfo;
|
fn item_render_info(&self, index: usize) -> &WidgetRenderInfo;
|
||||||
|
|
||||||
/// Calls [`UiNode::render`] in all widgets allowed by a `filter`, skips rendering the rest.
|
/// Calls [`UiNode::render`] in all widgets allowed by a `filter`, skips rendering the rest.
|
||||||
fn render_filtered<F>(&self, filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
fn render_filtered<F>(&self, filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
@ -294,9 +388,9 @@ pub trait WidgetList: UiNodeList {
|
||||||
F: FnMut(WidgetFilterArgs) -> bool;
|
F: FnMut(WidgetFilterArgs) -> bool;
|
||||||
|
|
||||||
/// Calls [`WidgetLayout::with_outer`] in only the `index` widget.
|
/// Calls [`WidgetLayout::with_outer`] in only the `index` widget.
|
||||||
fn widget_outer<F>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs);
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R;
|
||||||
|
|
||||||
/// Calls [`WidgetLayout::with_outer`] in all widgets on the list.
|
/// Calls [`WidgetLayout::with_outer`] in all widgets on the list.
|
||||||
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
||||||
|
|
|
@ -142,6 +142,115 @@ impl<A: WidgetList, B: WidgetList> UiNodeList for WidgetListChain<A, B> {
|
||||||
self.1.item_render_update(index - a_len, ctx, update)
|
self.1.item_render_update(index - a_len, ctx, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_id(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_id(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_state(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_state(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_state_mut(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_state_mut(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_bounds_info(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_bounds_info(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_border_info(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_border_info(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_render_info(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_render_info(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
self.0.render_node_filtered(&mut filter, ctx, frame);
|
||||||
|
let offset = self.0.len();
|
||||||
|
self.1.render_node_filtered(
|
||||||
|
|mut a| {
|
||||||
|
a.index += offset;
|
||||||
|
filter(a)
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
frame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_outer(index, wl, keep_previous, transform)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_outer(index - a_len, wl, keep_previous, transform)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
self.0.try_outer_all(wl, keep_previous, &mut transform);
|
||||||
|
let offset = self.0.len();
|
||||||
|
self.1.try_outer_all(wl, keep_previous, |wlt, mut args| {
|
||||||
|
args.index += offset;
|
||||||
|
transform(wlt, args);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, mut filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
let a_count = self.0.count_nodes(&mut filter);
|
||||||
|
|
||||||
|
let offset = self.0.len();
|
||||||
|
let b_count = self.1.count_nodes(|mut args| {
|
||||||
|
args.index += offset;
|
||||||
|
filter(args)
|
||||||
|
});
|
||||||
|
|
||||||
|
a_count + b_count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: WidgetList, B: WidgetList> WidgetList for WidgetListChain<A, B> {
|
impl<A: WidgetList, B: WidgetList> WidgetList for WidgetListChain<A, B> {
|
||||||
|
@ -183,69 +292,69 @@ impl<A: WidgetList, B: WidgetList> WidgetList for WidgetListChain<A, B> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_id(&self, index: usize) -> WidgetId {
|
fn item_id(&self, index: usize) -> WidgetId {
|
||||||
let a_len = self.0.len();
|
let a_len = self.0.len();
|
||||||
if index < a_len {
|
if index < a_len {
|
||||||
self.0.widget_id(index)
|
self.0.item_id(index)
|
||||||
} else {
|
} else {
|
||||||
self.1.widget_id(index - a_len)
|
self.1.item_id(index - a_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state(&self, index: usize) -> &StateMap {
|
fn item_state(&self, index: usize) -> &StateMap {
|
||||||
let a_len = self.0.len();
|
let a_len = self.0.len();
|
||||||
if index < a_len {
|
if index < a_len {
|
||||||
self.0.widget_state(index)
|
self.0.item_state(index)
|
||||||
} else {
|
} else {
|
||||||
self.1.widget_state(index - a_len)
|
self.1.item_state(index - a_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state_mut(&mut self, index: usize) -> &mut StateMap {
|
fn item_state_mut(&mut self, index: usize) -> &mut StateMap {
|
||||||
let a_len = self.0.len();
|
let a_len = self.0.len();
|
||||||
if index < a_len {
|
if index < a_len {
|
||||||
self.0.widget_state_mut(index)
|
self.0.item_state_mut(index)
|
||||||
} else {
|
} else {
|
||||||
self.1.widget_state_mut(index - a_len)
|
self.1.item_state_mut(index - a_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
fn item_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
||||||
let a_len = self.0.len();
|
let a_len = self.0.len();
|
||||||
if index < a_len {
|
if index < a_len {
|
||||||
self.0.widget_bounds_info(index)
|
self.0.item_bounds_info(index)
|
||||||
} else {
|
} else {
|
||||||
self.1.widget_bounds_info(index - a_len)
|
self.1.item_bounds_info(index - a_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
fn item_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
||||||
let a_len = self.0.len();
|
let a_len = self.0.len();
|
||||||
if index < a_len {
|
if index < a_len {
|
||||||
self.0.widget_border_info(index)
|
self.0.item_border_info(index)
|
||||||
} else {
|
} else {
|
||||||
self.1.widget_border_info(index - a_len)
|
self.1.item_border_info(index - a_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
fn item_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
||||||
let a_len = self.0.len();
|
let a_len = self.0.len();
|
||||||
if index < a_len {
|
if index < a_len {
|
||||||
self.0.widget_render_info(index)
|
self.0.item_render_info(index)
|
||||||
} else {
|
} else {
|
||||||
self.1.widget_render_info(index - a_len)
|
self.1.item_render_info(index - a_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_outer<F>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
{
|
{
|
||||||
let a_len = self.0.len();
|
let a_len = self.0.len();
|
||||||
if index < a_len {
|
if index < a_len {
|
||||||
self.0.widget_outer(index, wl, keep_previous, transform);
|
self.0.item_outer(index, wl, keep_previous, transform)
|
||||||
} else {
|
} else {
|
||||||
self.1.widget_outer(index - a_len, wl, keep_previous, transform);
|
self.1.item_outer(index - a_len, wl, keep_previous, transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,4 +500,113 @@ impl<A: UiNodeList, B: UiNodeList> UiNodeList for UiNodeListChain<A, B> {
|
||||||
self.1.item_render_update(index - a_len, ctx, update)
|
self.1.item_render_update(index - a_len, ctx, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_id(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_id(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_state(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_state(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_state_mut(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_state_mut(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_bounds_info(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_bounds_info(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_border_info(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_border_info(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_render_info(index)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_render_info(index - a_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
self.0.render_node_filtered(&mut filter, ctx, frame);
|
||||||
|
let offset = self.0.len();
|
||||||
|
self.1.render_node_filtered(
|
||||||
|
|mut a| {
|
||||||
|
a.index += offset;
|
||||||
|
filter(a)
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
frame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
let a_len = self.0.len();
|
||||||
|
if index < a_len {
|
||||||
|
self.0.try_item_outer(index, wl, keep_previous, transform)
|
||||||
|
} else {
|
||||||
|
self.1.try_item_outer(index - a_len, wl, keep_previous, transform)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
self.0.try_outer_all(wl, keep_previous, &mut transform);
|
||||||
|
let offset = self.0.len();
|
||||||
|
self.1.try_outer_all(wl, keep_previous, |wlt, mut args| {
|
||||||
|
args.index += offset;
|
||||||
|
transform(wlt, args);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, mut filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
let a_count = self.0.count_nodes(&mut filter);
|
||||||
|
|
||||||
|
let offset = self.0.len();
|
||||||
|
let b_count = self.1.count_nodes(|mut args| {
|
||||||
|
args.index += offset;
|
||||||
|
filter(args)
|
||||||
|
});
|
||||||
|
|
||||||
|
a_count + b_count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ use crate::{
|
||||||
BoxedWidget, UiNode, Widget, WidgetId,
|
BoxedWidget, UiNode, Widget, WidgetId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::UiNodeFilterArgs;
|
||||||
|
|
||||||
/// A vector of boxed [`Widget`] items that remains sorted.
|
/// A vector of boxed [`Widget`] items that remains sorted.
|
||||||
///
|
///
|
||||||
/// This type is a [`WidgetList`] that can be modified during runtime, and automatically remains sorted
|
/// This type is a [`WidgetList`] that can be modified during runtime, and automatically remains sorted
|
||||||
|
@ -372,6 +374,81 @@ impl UiNodeList for SortedWidgetVec {
|
||||||
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
||||||
self.vec[index].render_update(ctx, update);
|
self.vec[index].render_update(ctx, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
self.vec[index].try_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
self.vec[index].try_state()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
self.vec[index].try_state_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
self.vec[index].try_bounds_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
self.vec[index].try_border_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
self.vec[index].try_render_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
for (i, w) in self.iter().enumerate() {
|
||||||
|
if filter(UiNodeFilterArgs::new(i, w)) {
|
||||||
|
w.render(ctx, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
let w = &mut self.vec[index];
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i| i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new(index, w.try_state_mut(), size))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
for (i, w) in self.vec.iter_mut().enumerate() {
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i| i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new(i, w.try_state_mut(), size));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, mut filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
let mut count = 0;
|
||||||
|
for (i, w) in self.iter().enumerate() {
|
||||||
|
if filter(UiNodeFilterArgs::new(i, w)) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl WidgetList for SortedWidgetVec {
|
impl WidgetList for SortedWidgetVec {
|
||||||
fn boxed_widget_all(mut self) -> WidgetVec {
|
fn boxed_widget_all(mut self) -> WidgetVec {
|
||||||
|
@ -381,27 +458,27 @@ impl WidgetList for SortedWidgetVec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_id(&self, index: usize) -> WidgetId {
|
fn item_id(&self, index: usize) -> WidgetId {
|
||||||
self.vec[index].id()
|
self.vec[index].id()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state(&self, index: usize) -> &StateMap {
|
fn item_state(&self, index: usize) -> &StateMap {
|
||||||
self.vec[index].state()
|
self.vec[index].state()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state_mut(&mut self, index: usize) -> &mut StateMap {
|
fn item_state_mut(&mut self, index: usize) -> &mut StateMap {
|
||||||
self.vec[index].state_mut()
|
self.vec[index].state_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
fn item_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
||||||
self.vec[index].bounds_info()
|
self.vec[index].bounds_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
fn item_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
||||||
self.vec[index].border_info()
|
self.vec[index].border_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
fn item_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
||||||
self.vec[index].render_info()
|
self.vec[index].render_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,26 +508,26 @@ impl WidgetList for SortedWidgetVec {
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_outer<F>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
{
|
{
|
||||||
let w = &mut self.vec[index];
|
let w = &mut self.vec[index];
|
||||||
let size = w.bounds_info().outer_size();
|
let size = w.bounds_info().outer_size();
|
||||||
wl.with_outer(w, keep_previous, |wlt, w| {
|
wl.with_outer(w, keep_previous, |wlt, w| {
|
||||||
transform(wlt, PosLayoutArgs::new(index, Some(w.state_mut()), size));
|
transform(wlt, PosLayoutArgs::new(index, Some(w.state_mut()), size))
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs) ,
|
||||||
{
|
{
|
||||||
for (i, w) in self.vec.iter_mut().enumerate() {
|
for (i, w) in self.vec.iter_mut().enumerate() {
|
||||||
let size = w.bounds_info().outer_size();
|
let size = w.bounds_info().outer_size();
|
||||||
wl.with_outer(w, keep_previous, |wlt, w| {
|
wl.with_outer(w, keep_previous, |wlt, w| {
|
||||||
transform(wlt, PosLayoutArgs::new(i, Some(w.state_mut()), size));
|
transform(wlt, PosLayoutArgs::new(i, Some(w.state_mut()), size));
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use super::WidgetFilterArgs;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{InfoContext, LayoutContext, RenderContext, StateMap, WidgetContext},
|
context::{InfoContext, LayoutContext, RenderContext, StateMap, WidgetContext},
|
||||||
event::EventUpdateArgs,
|
event::EventUpdateArgs,
|
||||||
node_vec,
|
node_vec,
|
||||||
render::{FrameBuilder, FrameUpdate},
|
render::{FrameBuilder, FrameUpdate},
|
||||||
ui_list::{PosLayoutArgs, PreLayoutArgs, UiListObserver, UiNodeList, UiNodeVec, WidgetList, WidgetVec},
|
ui_list::{
|
||||||
|
PosLayoutArgs, PreLayoutArgs, UiListObserver, UiNodeFilterArgs, UiNodeList, UiNodeVec, WidgetFilterArgs, WidgetList, WidgetVec,
|
||||||
|
},
|
||||||
units::PxSize,
|
units::PxSize,
|
||||||
widget_info::{
|
widget_info::{
|
||||||
WidgetBorderInfo, WidgetBoundsInfo, WidgetInfoBuilder, WidgetLayout, WidgetLayoutTranslation, WidgetRenderInfo, WidgetSubscriptions,
|
WidgetBorderInfo, WidgetBoundsInfo, WidgetInfoBuilder, WidgetLayout, WidgetLayoutTranslation, WidgetRenderInfo, WidgetSubscriptions,
|
||||||
|
@ -84,59 +85,59 @@ macro_rules! impl_tuples {
|
||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_id(&self, index: usize) -> WidgetId {
|
fn item_id(&self, index: usize) -> WidgetId {
|
||||||
match index {
|
match index {
|
||||||
$($n => self.items.$n.id(),)+
|
$($n => self.items.$n.id(),)+
|
||||||
_ => panic!("index {index} out of range for length {}", self.len())
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state(&self, index: usize) -> &StateMap {
|
fn item_state(&self, index: usize) -> &StateMap {
|
||||||
match index {
|
match index {
|
||||||
$($n => self.items.$n.state(),)+
|
$($n => self.items.$n.state(),)+
|
||||||
_ => panic!("index {index} out of range for length {}", self.len())
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state_mut(&mut self, index: usize) -> &mut StateMap {
|
fn item_state_mut(&mut self, index: usize) -> &mut StateMap {
|
||||||
match index {
|
match index {
|
||||||
$($n => self.items.$n.state_mut(),)+
|
$($n => self.items.$n.state_mut(),)+
|
||||||
_ => panic!("index {index} out of range for length {}", self.len())
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
fn item_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
||||||
match index {
|
match index {
|
||||||
$($n => self.items.$n.bounds_info(),)+
|
$($n => self.items.$n.bounds_info(),)+
|
||||||
_ => panic!("index {index} out of range for length {}", self.len())
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
fn item_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
||||||
match index {
|
match index {
|
||||||
$($n => self.items.$n.border_info(),)+
|
$($n => self.items.$n.border_info(),)+
|
||||||
_ => panic!("index {index} out of range for length {}", self.len())
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
fn item_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
||||||
match index {
|
match index {
|
||||||
$($n => self.items.$n.render_info(),)+
|
$($n => self.items.$n.render_info(),)+
|
||||||
_ => panic!("index {index} out of range for length {}", self.len())
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_outer<F>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
{
|
{
|
||||||
match index {
|
match index {
|
||||||
$($n => {
|
$($n => {
|
||||||
let w = &mut self.items.$n;
|
let w = &mut self.items.$n;
|
||||||
let size = w.bounds_info().outer_size();
|
let size = w.bounds_info().outer_size();
|
||||||
wl.with_outer(w, keep_previous, |wlt, w| {
|
wl.with_outer(w, keep_previous, |wlt, w| {
|
||||||
transform(wlt, PosLayoutArgs::new($n, Some(w.state_mut()), size));
|
transform(wlt, PosLayoutArgs::new($n, Some(w.state_mut()), size))
|
||||||
});
|
})
|
||||||
})+
|
})+
|
||||||
_ => panic!("index {index} out of range for length {}", self.len())
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
}
|
}
|
||||||
|
@ -288,6 +289,117 @@ macro_rules! impl_tuples {
|
||||||
_ => panic!("index {index} out of range for length {}", self.len()),
|
_ => panic!("index {index} out of range for length {}", self.len()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
match index {
|
||||||
|
$(
|
||||||
|
$n => self.items.$n.try_id(),
|
||||||
|
)+
|
||||||
|
_ => panic!("index {index} out of range for length {}", self.len()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
match index {
|
||||||
|
$(
|
||||||
|
$n => self.items.$n.try_state(),
|
||||||
|
)+
|
||||||
|
_ => panic!("index {index} out of range for length {}", self.len()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
match index {
|
||||||
|
$(
|
||||||
|
$n => self.items.$n.try_state_mut(),
|
||||||
|
)+
|
||||||
|
_ => panic!("index {index} out of range for length {}", self.len()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
match index {
|
||||||
|
$(
|
||||||
|
$n => self.items.$n.try_bounds_info(),
|
||||||
|
)+
|
||||||
|
_ => panic!("index {index} out of range for length {}", self.len()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
match index {
|
||||||
|
$(
|
||||||
|
$n => self.items.$n.try_border_info(),
|
||||||
|
)+
|
||||||
|
_ => panic!("index {index} out of range for length {}", self.len()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
match index {
|
||||||
|
$(
|
||||||
|
$n => self.items.$n.try_render_info(),
|
||||||
|
)+
|
||||||
|
_ => panic!("index {index} out of range for length {}", self.len()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
$(
|
||||||
|
if filter(UiNodeFilterArgs::new($n, &self.items.$n)) {
|
||||||
|
self.items.$n.render(ctx, frame);
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
match index {
|
||||||
|
$($n => {
|
||||||
|
let w = &mut self.items.$n;
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i|i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new($n, w.try_state_mut(), size))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})+
|
||||||
|
_ => panic!("index {index} out of range for length {}", self.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
$(
|
||||||
|
let w = &mut self.items.$n;
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i|i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new($n, w.try_state_mut(), size));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, mut filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
let mut count = 0;
|
||||||
|
$(
|
||||||
|
if filter(UiNodeFilterArgs::new($n, &self.items.$n)) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -388,6 +500,56 @@ macro_rules! empty_node_list {
|
||||||
fn item_render_update(&self, index: usize, _: &mut RenderContext, _: &mut FrameUpdate) {
|
fn item_render_update(&self, index: usize, _: &mut RenderContext, _: &mut FrameUpdate) {
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
panic!("index {index} out of range for length 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
panic!("index {index} out of range for length 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
panic!("index {index} out of range for length 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
panic!("index {index} out of range for length 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
panic!("index {index} out of range for length 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
panic!("index {index} out of range for length 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, _: F, _: &mut RenderContext, _: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, _: &mut WidgetLayout, _: bool, _: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
panic!("index {index} out of range for length 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, _: &mut WidgetLayout, _: bool, _: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, _: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(super::UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)+}
|
)+}
|
||||||
}
|
}
|
||||||
|
@ -413,33 +575,33 @@ impl WidgetList for WidgetList0 {
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_id(&self, index: usize) -> WidgetId {
|
fn item_id(&self, index: usize) -> WidgetId {
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state(&self, index: usize) -> &StateMap {
|
fn item_state(&self, index: usize) -> &StateMap {
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state_mut(&mut self, index: usize) -> &mut StateMap {
|
fn item_state_mut(&mut self, index: usize) -> &mut StateMap {
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
fn item_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
fn item_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
fn item_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_outer<F>(&mut self, index: usize, _: &mut WidgetLayout, _: bool, _: F)
|
fn item_outer<F, R>(&mut self, index: usize, _: &mut WidgetLayout, _: bool, _: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
{
|
{
|
||||||
panic!("index {index} out of range for length 0")
|
panic!("index {index} out of range for length 0")
|
||||||
}
|
}
|
||||||
|
|
|
@ -389,33 +389,108 @@ impl UiNodeList for WidgetVec {
|
||||||
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
||||||
self.vec[index].render_update(ctx, update);
|
self.vec[index].render_update(ctx, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
self.vec[index].try_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
self.vec[index].try_state()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
self.vec[index].try_state_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
self.vec[index].try_bounds_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
self.vec[index].try_border_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
self.vec[index].try_render_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
for (i, w) in self.iter().enumerate() {
|
||||||
|
if filter(UiNodeFilterArgs::new(i, w)) {
|
||||||
|
w.render(ctx, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
let w = &mut self.vec[index];
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i| i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new(index, w.try_state_mut(), size))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
for (i, w) in self.vec.iter_mut().enumerate() {
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i| i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new(i, w.try_state_mut(), size));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, mut filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
let mut count = 0;
|
||||||
|
for (i, w) in self.iter().enumerate() {
|
||||||
|
if filter(UiNodeFilterArgs::new(i, w)) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl WidgetList for WidgetVec {
|
impl WidgetList for WidgetVec {
|
||||||
fn boxed_widget_all(self) -> WidgetVec {
|
fn boxed_widget_all(self) -> WidgetVec {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_id(&self, index: usize) -> WidgetId {
|
fn item_id(&self, index: usize) -> WidgetId {
|
||||||
self.vec[index].id()
|
self.vec[index].id()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state(&self, index: usize) -> &StateMap {
|
fn item_state(&self, index: usize) -> &StateMap {
|
||||||
self.vec[index].state()
|
self.vec[index].state()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state_mut(&mut self, index: usize) -> &mut StateMap {
|
fn item_state_mut(&mut self, index: usize) -> &mut StateMap {
|
||||||
self.vec[index].state_mut()
|
self.vec[index].state_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
fn item_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
||||||
self.vec[index].bounds_info()
|
self.vec[index].bounds_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
fn item_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
||||||
self.vec[index].border_info()
|
self.vec[index].border_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
fn item_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
||||||
self.vec[index].render_info()
|
self.vec[index].render_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,15 +520,15 @@ impl WidgetList for WidgetVec {
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_outer<F>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
{
|
{
|
||||||
let w = &mut self.vec[index];
|
let w = &mut self.vec[index];
|
||||||
let size = w.bounds_info().outer_size();
|
let size = w.bounds_info().outer_size();
|
||||||
wl.with_outer(w, keep_previous, |wlt, w| {
|
wl.with_outer(w, keep_previous, |wlt, w| {
|
||||||
transform(wlt, PosLayoutArgs::new(index, Some(w.state_mut()), size));
|
transform(wlt, PosLayoutArgs::new(index, Some(w.state_mut()), size))
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
|
@ -839,6 +914,81 @@ impl UiNodeList for UiNodeVec {
|
||||||
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
||||||
self.vec[index].render_update(ctx, update);
|
self.vec[index].render_update(ctx, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
self.vec[index].try_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
self.vec[index].try_state()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
self.vec[index].try_state_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
self.vec[index].try_bounds_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
self.vec[index].try_border_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
self.vec[index].try_render_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
for (i, w) in self.iter().enumerate() {
|
||||||
|
if filter(UiNodeFilterArgs::new(i, w)) {
|
||||||
|
w.render(ctx, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
let w = &mut self.vec[index];
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i| i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new(index, w.try_state_mut(), size))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, mut transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
for (i, w) in self.vec.iter_mut().enumerate() {
|
||||||
|
if let Some(size) = w.try_bounds_info().map(|i| i.outer_size()) {
|
||||||
|
wl.try_with_outer(w, keep_previous, |wlt, w| {
|
||||||
|
transform(wlt, PosLayoutArgs::new(i, w.try_state_mut(), size));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, mut filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
let mut count = 0;
|
||||||
|
for (i, w) in self.iter().enumerate() {
|
||||||
|
if filter(UiNodeFilterArgs::new(i, w)) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`WidgetVec`] containing the arguments.
|
/// Creates a [`WidgetVec`] containing the arguments.
|
||||||
|
@ -902,3 +1052,5 @@ macro_rules! node_vec {
|
||||||
}
|
}
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::node_vec;
|
pub use crate::node_vec;
|
||||||
|
|
||||||
|
use super::UiNodeFilterArgs;
|
||||||
|
|
|
@ -183,6 +183,75 @@ impl<W: WidgetList> UiNodeList for ZSortedWidgetList<W> {
|
||||||
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
fn item_render_update(&self, index: usize, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
||||||
self.list.item_render_update(index, ctx, update)
|
self.list.item_render_update(index, ctx, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_item_id(&self, index: usize) -> Option<WidgetId> {
|
||||||
|
self.list.try_item_id(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state(&self, index: usize) -> Option<&StateMap> {
|
||||||
|
self.list.try_item_state(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_state_mut(&mut self, index: usize) -> Option<&mut StateMap> {
|
||||||
|
self.list.try_item_state_mut(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_bounds_info(&self, index: usize) -> Option<&WidgetBoundsInfo> {
|
||||||
|
self.list.try_item_bounds_info(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_border_info(&self, index: usize) -> Option<&WidgetBorderInfo> {
|
||||||
|
self.list.try_item_border_info(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_render_info(&self, index: usize) -> Option<&WidgetRenderInfo> {
|
||||||
|
self.list.try_item_render_info(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
if self.lookup.is_empty() {
|
||||||
|
self.list.render_node_filtered(filter, ctx, frame);
|
||||||
|
} else {
|
||||||
|
for &i in &self.lookup {
|
||||||
|
let i = i as usize;
|
||||||
|
let args = UiNodeFilterArgs {
|
||||||
|
index: i,
|
||||||
|
id: self.try_item_id(i),
|
||||||
|
bounds_info: self.try_item_bounds_info(i),
|
||||||
|
border_info: self.try_item_border_info(i),
|
||||||
|
render_info: self.try_item_render_info(i),
|
||||||
|
state: self.try_item_state(i),
|
||||||
|
};
|
||||||
|
if filter(args) {
|
||||||
|
self.item_render(i, ctx, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> Option<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
|
{
|
||||||
|
self.list.try_item_outer(index, wl, keep_previous, transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
||||||
|
{
|
||||||
|
self.list.try_outer_all(wl, keep_previous, transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_nodes<F>(&self, filter: F) -> usize
|
||||||
|
where
|
||||||
|
F: FnMut(UiNodeFilterArgs) -> bool,
|
||||||
|
{
|
||||||
|
self.list.count_nodes(filter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<W: WidgetList> WidgetList for ZSortedWidgetList<W> {
|
impl<W: WidgetList> WidgetList for ZSortedWidgetList<W> {
|
||||||
fn count<F>(&self, filter: F) -> usize
|
fn count<F>(&self, filter: F) -> usize
|
||||||
|
@ -196,28 +265,28 @@ impl<W: WidgetList> WidgetList for ZSortedWidgetList<W> {
|
||||||
self.list.boxed_widget_all()
|
self.list.boxed_widget_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_id(&self, index: usize) -> WidgetId {
|
fn item_id(&self, index: usize) -> WidgetId {
|
||||||
self.list.widget_id(index)
|
self.list.item_id(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state(&self, index: usize) -> &StateMap {
|
fn item_state(&self, index: usize) -> &StateMap {
|
||||||
self.list.widget_state(index)
|
self.list.item_state(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_state_mut(&mut self, index: usize) -> &mut StateMap {
|
fn item_state_mut(&mut self, index: usize) -> &mut StateMap {
|
||||||
self.list.widget_state_mut(index)
|
self.list.item_state_mut(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
fn item_bounds_info(&self, index: usize) -> &WidgetBoundsInfo {
|
||||||
self.list.widget_bounds_info(index)
|
self.list.item_bounds_info(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
fn item_border_info(&self, index: usize) -> &WidgetBorderInfo {
|
||||||
self.list.widget_border_info(index)
|
self.list.item_border_info(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
fn item_render_info(&self, index: usize) -> &WidgetRenderInfo {
|
||||||
self.list.widget_render_info(index)
|
self.list.item_render_info(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
fn render_filtered<F>(&self, mut filter: F, ctx: &mut RenderContext, frame: &mut FrameBuilder)
|
||||||
|
@ -231,10 +300,11 @@ impl<W: WidgetList> WidgetList for ZSortedWidgetList<W> {
|
||||||
let i = i as usize;
|
let i = i as usize;
|
||||||
let args = WidgetFilterArgs {
|
let args = WidgetFilterArgs {
|
||||||
index: i,
|
index: i,
|
||||||
bounds_info: self.widget_bounds_info(i),
|
id: self.item_id(i),
|
||||||
border_info: self.widget_border_info(i),
|
bounds_info: self.item_bounds_info(i),
|
||||||
render_info: self.widget_render_info(i),
|
border_info: self.item_border_info(i),
|
||||||
state: self.widget_state(i),
|
render_info: self.item_render_info(i),
|
||||||
|
state: self.item_state(i),
|
||||||
};
|
};
|
||||||
if filter(args) {
|
if filter(args) {
|
||||||
self.item_render(i, ctx, frame);
|
self.item_render(i, ctx, frame);
|
||||||
|
@ -243,11 +313,11 @@ impl<W: WidgetList> WidgetList for ZSortedWidgetList<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget_outer<F>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn item_outer<F, R>(&mut self, index: usize, wl: &mut WidgetLayout, keep_previous: bool, transform: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs),
|
F: FnOnce(&mut WidgetLayoutTranslation, PosLayoutArgs) -> R,
|
||||||
{
|
{
|
||||||
self.list.widget_outer(index, wl, keep_previous, transform)
|
self.list.item_outer(index, wl, keep_previous, transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
fn outer_all<F>(&mut self, wl: &mut WidgetLayout, keep_previous: bool, transform: F)
|
||||||
|
@ -467,7 +537,7 @@ pub trait WidgetListZIndexExt {
|
||||||
}
|
}
|
||||||
impl<L: WidgetList> WidgetListZIndexExt for L {
|
impl<L: WidgetList> WidgetListZIndexExt for L {
|
||||||
fn widget_z_index(&self, index: usize) -> ZIndex {
|
fn widget_z_index(&self, index: usize) -> ZIndex {
|
||||||
self.widget_state(index).copy(ZIndexKey).unwrap_or_default()
|
self.item_state(index).copy(ZIndexKey).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_all_z(&mut self, ctx: &mut WidgetContext, sort_z: &mut bool) {
|
fn init_all_z(&mut self, ctx: &mut WidgetContext, sort_z: &mut bool) {
|
||||||
|
|
|
@ -272,6 +272,68 @@ pub trait UiNode: 'static {
|
||||||
{
|
{
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets if this node is a [`Widget`] implementer.
|
||||||
|
fn is_widget(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [`Widget::id`] if this node [`is_widget`].
|
||||||
|
///
|
||||||
|
/// [`is_widget`]: UiNode::is_widget
|
||||||
|
fn try_id(&self) -> Option<WidgetId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [`Widget::state`] if this node [`is_widget`].
|
||||||
|
///
|
||||||
|
/// [`is_widget`]: UiNode::is_widget
|
||||||
|
fn try_state(&self) -> Option<&StateMap> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [`Widget::state_mut`] if this node [`is_widget`].
|
||||||
|
///
|
||||||
|
/// [`is_widget`]: UiNode::is_widget
|
||||||
|
fn try_state_mut(&mut self) -> Option<&mut StateMap> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [`Widget::bounds_info`] if this node [`is_widget`].
|
||||||
|
///
|
||||||
|
/// [`is_widget`]: UiNode::is_widget
|
||||||
|
fn try_bounds_info(&self) -> Option<&WidgetBoundsInfo> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [`Widget::border_info`] if this node [`is_widget`].
|
||||||
|
///
|
||||||
|
/// [`is_widget`]: UiNode::is_widget
|
||||||
|
fn try_border_info(&self) -> Option<&WidgetBorderInfo> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [`Widget::render_info`] if this node [`is_widget`].
|
||||||
|
///
|
||||||
|
/// [`is_widget`]: UiNode::is_widget
|
||||||
|
fn try_render_info(&self) -> Option<&WidgetRenderInfo> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets this node as a [`BoxedWidget`], if the node [`is_widget`] this is the same as
|
||||||
|
/// [`Widget::boxed_wgt`], otherwise a new widget is generated with the node as the *inner*.
|
||||||
|
///
|
||||||
|
/// [`is_widget`]: Self::is_widget
|
||||||
|
fn into_widget(self) -> BoxedWidget
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
use crate::widget_base::implicit_base::nodes;
|
||||||
|
|
||||||
|
let node = nodes::inner(self.cfg_boxed());
|
||||||
|
let wgt = nodes::widget(node, WidgetId::new_unique());
|
||||||
|
wgt.boxed_wgt()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -285,6 +347,15 @@ pub trait UiNodeBoxed: 'static {
|
||||||
fn layout_boxed(&mut self, ctx: &mut LayoutContext, wl: &mut WidgetLayout) -> PxSize;
|
fn layout_boxed(&mut self, ctx: &mut LayoutContext, wl: &mut WidgetLayout) -> PxSize;
|
||||||
fn render_boxed(&self, ctx: &mut RenderContext, frame: &mut FrameBuilder);
|
fn render_boxed(&self, ctx: &mut RenderContext, frame: &mut FrameBuilder);
|
||||||
fn render_update_boxed(&self, ctx: &mut RenderContext, update: &mut FrameUpdate);
|
fn render_update_boxed(&self, ctx: &mut RenderContext, update: &mut FrameUpdate);
|
||||||
|
|
||||||
|
fn is_widget_boxed(&self) -> bool;
|
||||||
|
fn try_id_boxed(&self) -> Option<WidgetId>;
|
||||||
|
fn try_state_boxed(&self) -> Option<&StateMap>;
|
||||||
|
fn try_state_mut_boxed(&mut self) -> Option<&mut StateMap>;
|
||||||
|
fn try_bounds_info_boxed(&self) -> Option<&WidgetBoundsInfo>;
|
||||||
|
fn try_border_info_boxed(&self) -> Option<&WidgetBorderInfo>;
|
||||||
|
fn try_render_info_boxed(&self) -> Option<&WidgetRenderInfo>;
|
||||||
|
fn into_widget_boxed(self: Box<Self>) -> BoxedWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: UiNode> UiNodeBoxed for U {
|
impl<U: UiNode> UiNodeBoxed for U {
|
||||||
|
@ -323,6 +394,38 @@ impl<U: UiNode> UiNodeBoxed for U {
|
||||||
fn render_update_boxed(&self, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
fn render_update_boxed(&self, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
||||||
self.render_update(ctx, update);
|
self.render_update(ctx, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_widget_boxed(&self) -> bool {
|
||||||
|
self.is_widget()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_id_boxed(&self) -> Option<WidgetId> {
|
||||||
|
self.try_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state_boxed(&self) -> Option<&StateMap> {
|
||||||
|
self.try_state()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state_mut_boxed(&mut self) -> Option<&mut StateMap> {
|
||||||
|
self.try_state_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_bounds_info_boxed(&self) -> Option<&WidgetBoundsInfo> {
|
||||||
|
self.try_bounds_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_border_info_boxed(&self) -> Option<&WidgetBorderInfo> {
|
||||||
|
self.try_border_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_render_info_boxed(&self) -> Option<&WidgetRenderInfo> {
|
||||||
|
self.try_render_info()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_widget_boxed(self: Box<Self>) -> BoxedWidget {
|
||||||
|
self.into_widget()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An [`UiNode`] in a box.
|
/// An [`UiNode`] in a box.
|
||||||
|
@ -375,6 +478,41 @@ impl UiNode for BoxedUiNode {
|
||||||
{
|
{
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_widget(&self) -> bool {
|
||||||
|
self.as_ref().is_widget_boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_id(&self) -> Option<WidgetId> {
|
||||||
|
self.as_ref().try_id_boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state(&self) -> Option<&StateMap> {
|
||||||
|
self.as_ref().try_state_boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state_mut(&mut self) -> Option<&mut StateMap> {
|
||||||
|
self.as_mut().try_state_mut_boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_bounds_info(&self) -> Option<&WidgetBoundsInfo> {
|
||||||
|
self.as_ref().try_bounds_info_boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_border_info(&self) -> Option<&WidgetBorderInfo> {
|
||||||
|
self.as_ref().try_border_info_boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_render_info(&self) -> Option<&WidgetRenderInfo> {
|
||||||
|
self.as_ref().try_render_info_boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_widget(self) -> BoxedWidget
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.into_widget_boxed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: UiNode> UiNode for Option<U> {
|
impl<U: UiNode> UiNode for Option<U> {
|
||||||
|
@ -433,6 +571,75 @@ impl<U: UiNode> UiNode for Option<U> {
|
||||||
node.render_update(ctx, update);
|
node.render_update(ctx, update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn boxed(self) -> BoxedUiNode
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Some(node) => node.boxed(),
|
||||||
|
None => NilUiNode.boxed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_widget(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Some(node) => node.is_widget(),
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_id(&self) -> Option<WidgetId> {
|
||||||
|
match self {
|
||||||
|
Some(node) => node.try_id(),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state(&self) -> Option<&StateMap> {
|
||||||
|
match self {
|
||||||
|
Some(node) => node.try_state(),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state_mut(&mut self) -> Option<&mut StateMap> {
|
||||||
|
match self {
|
||||||
|
Some(node) => node.try_state_mut(),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_bounds_info(&self) -> Option<&WidgetBoundsInfo> {
|
||||||
|
match self {
|
||||||
|
Some(node) => node.try_bounds_info(),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_border_info(&self) -> Option<&WidgetBorderInfo> {
|
||||||
|
match self {
|
||||||
|
Some(node) => node.try_border_info(),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_render_info(&self) -> Option<&WidgetRenderInfo> {
|
||||||
|
match self {
|
||||||
|
Some(node) => node.try_render_info(),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_widget(self) -> BoxedWidget
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Some(node) => node.into_widget(),
|
||||||
|
None => NilUiNode.into_widget(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! declare_widget_test_calls {
|
macro_rules! declare_widget_test_calls {
|
||||||
|
@ -657,6 +864,48 @@ impl UiNode for BoxedWidget {
|
||||||
fn render_update(&self, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
fn render_update(&self, ctx: &mut RenderContext, update: &mut FrameUpdate) {
|
||||||
self.as_ref().render_update_boxed(ctx, update);
|
self.as_ref().render_update_boxed(ctx, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn boxed(self) -> BoxedUiNode
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_widget(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_id(&self) -> Option<WidgetId> {
|
||||||
|
Some(self.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state(&self) -> Option<&StateMap> {
|
||||||
|
Some(self.state())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state_mut(&mut self) -> Option<&mut StateMap> {
|
||||||
|
Some(self.state_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_bounds_info(&self) -> Option<&WidgetBoundsInfo> {
|
||||||
|
Some(self.bounds_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_border_info(&self) -> Option<&WidgetBorderInfo> {
|
||||||
|
Some(self.border_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_render_info(&self) -> Option<&WidgetRenderInfo> {
|
||||||
|
Some(self.render_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_widget(self) -> BoxedWidget
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Widget for BoxedWidget {
|
impl Widget for BoxedWidget {
|
||||||
fn id(&self) -> WidgetId {
|
fn id(&self) -> WidgetId {
|
||||||
|
@ -682,6 +931,13 @@ impl Widget for BoxedWidget {
|
||||||
fn render_info(&self) -> &WidgetRenderInfo {
|
fn render_info(&self) -> &WidgetRenderInfo {
|
||||||
self.as_ref().render_info_boxed()
|
self.as_ref().render_info_boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn boxed_wgt(self) -> BoxedWidget
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A UI node that does not contain any other node, only takes the minimum space and renders nothing.
|
/// A UI node that does not contain any other node, only takes the minimum space and renders nothing.
|
||||||
|
|
|
@ -368,18 +368,6 @@ pub mod implicit_base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &mut WidgetContext) {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
if !self.inited {
|
|
||||||
tracing::error!(target: "widget_base", "`UiNode::update` called in not inited widget {:?}", self.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.subscriptions.borrow().update_intersects(ctx.updates) {
|
|
||||||
let (_, updates) = ctx.widget_context(self.id, &self.info, &mut self.state, |ctx| self.child.update(ctx));
|
|
||||||
*self.pending_updates.get_mut() |= updates;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event<EU: EventUpdateArgs>(&mut self, ctx: &mut WidgetContext, args: &EU) {
|
fn event<EU: EventUpdateArgs>(&mut self, ctx: &mut WidgetContext, args: &EU) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if !self.inited {
|
if !self.inited {
|
||||||
|
@ -392,6 +380,18 @@ pub mod implicit_base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, ctx: &mut WidgetContext) {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
if !self.inited {
|
||||||
|
tracing::error!(target: "widget_base", "`UiNode::update` called in not inited widget {:?}", self.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.subscriptions.borrow().update_intersects(ctx.updates) {
|
||||||
|
let (_, updates) = ctx.widget_context(self.id, &self.info, &mut self.state, |ctx| self.child.update(ctx));
|
||||||
|
*self.pending_updates.get_mut() |= updates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn layout(&mut self, ctx: &mut LayoutContext, wl: &mut WidgetLayout) -> PxSize {
|
fn layout(&mut self, ctx: &mut LayoutContext, wl: &mut WidgetLayout) -> PxSize {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if !self.inited {
|
if !self.inited {
|
||||||
|
@ -442,6 +442,41 @@ pub mod implicit_base {
|
||||||
}
|
}
|
||||||
// else, don't need to do anything, updates are additive.
|
// else, don't need to do anything, updates are additive.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_widget(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_id(&self) -> Option<WidgetId> {
|
||||||
|
Some(self.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state(&self) -> Option<&StateMap> {
|
||||||
|
Some(self.state())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_state_mut(&mut self) -> Option<&mut StateMap> {
|
||||||
|
Some(self.state_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_bounds_info(&self) -> Option<&WidgetBoundsInfo> {
|
||||||
|
Some(self.bounds_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_border_info(&self) -> Option<&WidgetBorderInfo> {
|
||||||
|
Some(self.border_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_render_info(&self) -> Option<&WidgetRenderInfo> {
|
||||||
|
Some(self.render_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_widget(self) -> crate::BoxedWidget
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.boxed_wgt()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<T: UiNode> Widget for WidgetNode<T> {
|
impl<T: UiNode> Widget for WidgetNode<T> {
|
||||||
fn id(&self) -> WidgetId {
|
fn id(&self) -> WidgetId {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
var::{Var, VarValue, VarsRead, WithVarsRead},
|
var::{Var, VarValue, VarsRead, WithVarsRead},
|
||||||
widget_base::Visibility,
|
widget_base::Visibility,
|
||||||
window::WindowId,
|
window::WindowId,
|
||||||
Widget, WidgetId,
|
UiNode, Widget, WidgetId,
|
||||||
};
|
};
|
||||||
|
|
||||||
unique_id_64! {
|
unique_id_64! {
|
||||||
|
@ -233,17 +233,43 @@ impl WidgetLayout {
|
||||||
keep_previous: bool,
|
keep_previous: bool,
|
||||||
translate: impl FnOnce(&mut WidgetLayoutTranslation, &mut W) -> R,
|
translate: impl FnOnce(&mut WidgetLayoutTranslation, &mut W) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
let prev_outer = widget.bounds_info().outer_offset();
|
self.with_outer_impl(widget.bounds_info().clone(), widget, keep_previous, translate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies [`with_outer`] to the `node` if it is a full widget.
|
||||||
|
///
|
||||||
|
/// Returns `Some(_)` if `translate` was called, or `None` if the `node` was not a full widget.
|
||||||
|
///
|
||||||
|
/// [`with_outer`]: Self::with_outer
|
||||||
|
pub fn try_with_outer<N: UiNode, R>(
|
||||||
|
&mut self,
|
||||||
|
node: &mut N,
|
||||||
|
keep_previous: bool,
|
||||||
|
translate: impl FnOnce(&mut WidgetLayoutTranslation, &mut N) -> R,
|
||||||
|
) -> Option<R> {
|
||||||
|
node.try_bounds_info()
|
||||||
|
.cloned()
|
||||||
|
.map(|info| self.with_outer_impl(info, node, keep_previous, translate))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_outer_impl<T, R>(
|
||||||
|
&mut self,
|
||||||
|
bounds: WidgetBoundsInfo,
|
||||||
|
target: &mut T,
|
||||||
|
keep_previous: bool,
|
||||||
|
translate: impl FnOnce(&mut WidgetLayoutTranslation, &mut T) -> R,
|
||||||
|
) -> R {
|
||||||
|
let prev_outer = bounds.outer_offset();
|
||||||
|
|
||||||
if !keep_previous {
|
if !keep_previous {
|
||||||
widget.bounds_info().set_outer_offset(PxVector::zero());
|
bounds.set_outer_offset(PxVector::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut wl = WidgetLayout {
|
let mut wl = WidgetLayout {
|
||||||
t: WidgetLayoutTranslation {
|
t: WidgetLayoutTranslation {
|
||||||
offset_buf: PxVector::zero(),
|
offset_buf: PxVector::zero(),
|
||||||
baseline: Px(0),
|
baseline: Px(0),
|
||||||
known: Some(widget.bounds_info().clone()),
|
known: Some(bounds),
|
||||||
known_target: KnownTarget::Outer,
|
known_target: KnownTarget::Outer,
|
||||||
},
|
},
|
||||||
known_prev_offsets: [PxVector::zero(); 3],
|
known_prev_offsets: [PxVector::zero(); 3],
|
||||||
|
@ -252,10 +278,12 @@ impl WidgetLayout {
|
||||||
child_offset_changed: false,
|
child_offset_changed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = translate(&mut wl, widget);
|
let size = translate(&mut wl, target);
|
||||||
|
|
||||||
if prev_outer != widget.bounds_info().outer_offset() {
|
let bounds = wl.t.known.unwrap();
|
||||||
widget.bounds_info().update_offsets_version();
|
|
||||||
|
if prev_outer != bounds.outer_offset() {
|
||||||
|
bounds.update_offsets_version();
|
||||||
self.child_offset_changed = true;
|
self.child_offset_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ pub mod h_stack {
|
||||||
|ctx| {
|
|ctx| {
|
||||||
size.width = Px(0);
|
size.width = Px(0);
|
||||||
for i in 0..self.children.len() {
|
for i in 0..self.children.len() {
|
||||||
let o_size = self.children.widget_bounds_info(i).outer_size();
|
let o_size = self.children.item_bounds_info(i).outer_size();
|
||||||
if Some(o_size.height) != ctx.constrains().y.max() {
|
if Some(o_size.height) != ctx.constrains().y.max() {
|
||||||
// only need second pass for items that don't fill
|
// only need second pass for items that don't fill
|
||||||
let (a_size, _) = wl.with_child(ctx, |ctx, wl| {
|
let (a_size, _) = wl.with_child(ctx, |ctx, wl| {
|
||||||
|
@ -133,7 +133,7 @@ pub mod h_stack {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// item already fills width, but may have moved due to sibling new fill size
|
// item already fills width, but may have moved due to sibling new fill size
|
||||||
self.children.widget_outer(i, wl, false, |wlt, _| {
|
self.children.item_outer(i, wl, false, |wlt, _| {
|
||||||
wlt.translate(PxVector::new(size.width, Px(0)));
|
wlt.translate(PxVector::new(size.width, Px(0)));
|
||||||
|
|
||||||
if o_size.width > Px(0) {
|
if o_size.width > Px(0) {
|
||||||
|
@ -302,7 +302,7 @@ pub mod v_stack {
|
||||||
|ctx| {
|
|ctx| {
|
||||||
size.height = Px(0);
|
size.height = Px(0);
|
||||||
for i in 0..self.children.len() {
|
for i in 0..self.children.len() {
|
||||||
let o_size = self.children.widget_bounds_info(i).outer_size();
|
let o_size = self.children.item_bounds_info(i).outer_size();
|
||||||
if Some(o_size.width) != ctx.constrains().x.max() {
|
if Some(o_size.width) != ctx.constrains().x.max() {
|
||||||
// only need second pass for items that don't fill
|
// only need second pass for items that don't fill
|
||||||
let (a_size, _) = wl.with_child(ctx, |ctx, wl| {
|
let (a_size, _) = wl.with_child(ctx, |ctx, wl| {
|
||||||
|
@ -317,7 +317,7 @@ pub mod v_stack {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// item already fills width, but may have moved due to sibling new fill size
|
// item already fills width, but may have moved due to sibling new fill size
|
||||||
self.children.widget_outer(i, wl, false, |wlt, _| {
|
self.children.item_outer(i, wl, false, |wlt, _| {
|
||||||
wlt.translate(PxVector::new(Px(0), size.height));
|
wlt.translate(PxVector::new(Px(0), size.height));
|
||||||
|
|
||||||
if o_size.height > Px(0) {
|
if o_size.height > Px(0) {
|
||||||
|
|
Loading…
Reference in New Issue