use std::collections::HashMap;
use noesis_runtime::input::{CaptureMode, FocusManager, FocusNavigationDirection};
use noesis_runtime::view::{FrameworkElement, View};
use noesis_runtime::xaml_provider::XamlProvider;
const SCENE: &str = r##"<?xml version="1.0" encoding="utf-8"?>
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="#FF202020" Width="200" Height="200">
<StackPanel x:Name="Root">
<Button x:Name="One" Content="One" Width="120" Height="40"/>
<Button x:Name="Two" Content="Two" Width="120" Height="40"/>
</StackPanel>
</Grid>"##;
struct InMem {
bytes: HashMap<String, Vec<u8>>,
}
impl XamlProvider for InMem {
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn load_xaml(&mut self, uri: &str) -> Option<&[u8]> {
self.bytes.get(uri).map(Vec::as_slice)
}
}
#[test]
fn capture_focus_roundtrip() {
if let (Ok(name), Ok(key)) = (
std::env::var("NOESIS_LICENSE_NAME"),
std::env::var("NOESIS_LICENSE_KEY"),
) {
noesis_runtime::set_license(&name, &key);
}
noesis_runtime::init();
{
let mut bytes = HashMap::new();
bytes.insert("scene.xaml".to_string(), SCENE.as_bytes().to_vec());
let _registered = noesis_runtime::xaml_provider::set_xaml_provider(InMem { bytes });
let root = FrameworkElement::load("scene.xaml").expect("load scene");
let mut one = root.find_name("One").expect("find One");
let mut two = root.find_name("Two").expect("find Two");
let mut view = View::create(root);
view.set_size(200, 200);
view.activate();
assert!(view.update(0.0), "first update builds tree");
let _ = view.update(0.016);
assert!(!one.is_mouse_captured(), "nothing captured initially");
assert!(one.mouse_captured().is_none(), "Mouse::GetCaptured null");
assert!(
one.capture_mouse(),
"capture_mouse should succeed in a live View"
);
let _ = view.update(0.032);
assert!(one.is_mouse_captured(), "is_mouse_captured flips true");
let captured = one.mouse_captured().expect("a captured element");
assert_eq!(
captured.as_ptr(),
one.raw(),
"Mouse::GetCaptured points at the capturing element"
);
assert_ne!(captured.as_ptr(), two.raw());
one.release_mouse_capture();
let _ = view.update(0.048);
assert!(!one.is_mouse_captured(), "release flips it back to false");
assert!(
one.mouse_captured().is_none(),
"nothing captured after release"
);
assert!(
two.capture_mouse_mode(CaptureMode::SubTree),
"capture with SubTree mode"
);
let _ = view.update(0.064);
assert!(two.is_mouse_captured(), "two now captured");
assert_eq!(
two.mouse_captured().expect("captured").as_ptr(),
two.raw(),
"captured element is two"
);
assert!(two.capture_mouse_mode(CaptureMode::None) || !two.is_mouse_captured());
two.release_mouse_capture();
let _ = view.update(0.08);
assert!(!one.is_keyboard_focused(), "not focused before focus()");
assert!(one.focus(), "Button accepts focus");
let _ = view.update(0.096);
assert!(
one.is_keyboard_focused(),
"is_keyboard_focused true after focus()"
);
assert!(one.is_focused(), "logical focus too");
let focused = one.keyboard_focused().expect("a focused element");
assert_eq!(
focused.as_ptr(),
one.raw(),
"Keyboard::GetFocused points at the focused button"
);
let panel = two.logical_parent().expect("button has a logical parent");
assert!(
panel.is_keyboard_focus_within(),
"ancestor reports keyboard focus within"
);
assert!(two.focus(), "two accepts focus");
let _ = view.update(0.112);
assert!(two.is_keyboard_focused(), "two now keyboard-focused");
assert!(!one.is_keyboard_focused(), "one lost keyboard focus");
assert!(
!FocusManager::is_focus_scope(&one),
"not a scope by default"
);
assert!(
FocusManager::set_is_focus_scope(&one, true),
"set IsFocusScope"
);
assert!(
FocusManager::is_focus_scope(&one),
"IsFocusScope round-trips true"
);
assert!(FocusManager::set_is_focus_scope(&one, false));
assert!(!FocusManager::is_focus_scope(&one), "and back to false");
assert!(
FocusManager::set_is_focus_scope(&panel, true),
"panel is a scope"
);
assert!(
FocusManager::set_focused_element(&panel, Some(&one)),
"set FocusedElement"
);
let focused_in_scope =
FocusManager::focused_element(&panel).expect("a focused element in the scope");
assert_eq!(
focused_in_scope.as_ptr(),
one.raw(),
"FocusManager.FocusedElement round-trips to `one`"
);
let scope = FocusManager::focus_scope(&one).expect("an enclosing focus scope");
assert_eq!(
scope.as_ptr(),
panel.raw(),
"GetFocusScope resolves to the marked panel"
);
assert!(one.focus());
let _ = view.update(0.128);
assert!(one.is_keyboard_focused());
let moved = one.move_focus(FocusNavigationDirection::Next, true);
let _ = view.update(0.144);
assert!(moved, "MoveFocus(Next) reports it moved focus");
assert!(
!one.is_keyboard_focused(),
"focus left `one` after MoveFocus(Next)"
);
assert!(one.focus_engage(false), "focus_engage focuses the element");
let _ = view.update(0.16);
assert!(one.is_keyboard_focused(), "engage path focused `one`");
assert!(
!one.capture_touch(99),
"no active touch device #99 to capture"
);
let _ = view.touch_down(60, 100, 7);
let _ = view.update(0.176);
assert!(
one.capture_touch(7),
"CaptureTouch(7) succeeds once the touch device is active"
);
let _ = view.update(0.184);
assert!(
!one.is_mouse_captured(),
"touch capture is separate from mouse capture"
);
let _ = view.touch_up(60, 100, 7);
let _ = view.update(0.192);
assert!(one.focus());
let _ = view.update(0.2);
let predicted = one
.predict_focus(FocusNavigationDirection::Down)
.expect("PredictFocus(Down) resolves to a candidate");
assert_eq!(
predicted.as_ptr(),
two.raw(),
"PredictFocus(Down) points at the button below"
);
assert!(
one.predict_focus(FocusNavigationDirection::Next).is_none(),
"PredictFocus does not support tab-order Next"
);
assert_eq!(
one.predict_focus_name(FocusNavigationDirection::Down)
.as_deref(),
Some("Two"),
"PredictFocus(Down) lands on the button named `Two`"
);
assert!(
one.predict_focus_name(FocusNavigationDirection::Next)
.is_none(),
"no name when PredictFocus has no candidate"
);
drop(view);
}
noesis_runtime::shutdown();
}