Skip to content

Commit b0475ca

Browse files
committed
Add example of testing ui positioning without a real window.
1 parent 8c42799 commit b0475ca

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

crates/bevy_window/src/window.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ impl Window {
232232
cursor_locked: window_descriptor.cursor_locked,
233233
cursor_icon: CursorIcon::Default,
234234
physical_cursor_position: None,
235-
raw_window_handle: raw_window_handle.map(|handle| RawWindowHandleWrapper::new(handle)),
235+
raw_window_handle: raw_window_handle.map(RawWindowHandleWrapper::new),
236236
focused: true,
237237
mode: window_descriptor.mode,
238238
#[cfg(target_arch = "wasm32")]

tests/how_to_test_ui.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use bevy::prelude::*;
2+
use bevy_internal::asset::AssetPlugin;
3+
use bevy_internal::core_pipeline::CorePipelinePlugin;
4+
use bevy_internal::input::InputPlugin;
5+
use bevy_internal::render::options::WgpuOptions;
6+
use bevy_internal::render::RenderPlugin;
7+
use bevy_internal::sprite::SpritePlugin;
8+
use bevy_internal::text::TextPlugin;
9+
use bevy_internal::ui::UiPlugin;
10+
use bevy_internal::window::{WindowId, WindowPlugin};
11+
12+
const WINDOW_WIDTH: u32 = 200;
13+
const WINDOW_HEIGHT: u32 = 100;
14+
15+
struct HeadlessUiPlugin;
16+
17+
impl Plugin for HeadlessUiPlugin {
18+
fn build(&self, app: &mut App) {
19+
// These tests are meant to be ran on systems without gpu, or display.
20+
// To make this work, we tell bevy not to look for any rendering backends.
21+
app.insert_resource(WgpuOptions {
22+
backends: None,
23+
..Default::default()
24+
})
25+
// To test the positioning of UI elements,
26+
// we first need a window to position these elements in.
27+
.insert_resource({
28+
let mut windows = Windows::default();
29+
windows.add(Window::new(
30+
// At the moment, all ui elements are placed in the primary window.
31+
WindowId::primary(),
32+
&WindowDescriptor::default(),
33+
WINDOW_WIDTH,
34+
WINDOW_HEIGHT,
35+
1.0,
36+
None,
37+
// Because this test is running without a real window, we pass `None` here.
38+
None,
39+
));
40+
windows
41+
})
42+
.add_plugins(MinimalPlugins)
43+
.add_plugin(TransformPlugin)
44+
.add_plugin(WindowPlugin::default())
45+
.add_plugin(InputPlugin)
46+
.add_plugin(AssetPlugin)
47+
.add_plugin(RenderPlugin)
48+
.add_plugin(CorePipelinePlugin)
49+
.add_plugin(SpritePlugin)
50+
.add_plugin(TextPlugin)
51+
.add_plugin(UiPlugin);
52+
}
53+
}
54+
55+
#[test]
56+
fn test_button_translation() {
57+
let mut app = App::new();
58+
app.add_plugin(HeadlessUiPlugin)
59+
.add_startup_system(setup_button_test);
60+
61+
// First call to `update` also runs the startup systems.
62+
app.update();
63+
64+
let mut query = app.world.query_filtered::<Entity, With<Button>>();
65+
let button = *query.iter(&app.world).collect::<Vec<_>>().first().unwrap();
66+
67+
// The button's translation got updated because the UI system had a window to place it in.
68+
// If we hadn't added a window, the button's translation would at this point be all zero's.
69+
let button_transform = app.world.entity(button).get::<Transform>().unwrap();
70+
assert_eq!(
71+
button_transform.translation.x.floor() as u32,
72+
WINDOW_WIDTH / 2
73+
);
74+
assert_eq!(
75+
button_transform.translation.y.floor() as u32,
76+
WINDOW_HEIGHT / 2
77+
);
78+
}
79+
80+
fn setup_button_test(mut commands: Commands) {
81+
commands.spawn_bundle(UiCameraBundle::default());
82+
commands.spawn_bundle(ButtonBundle {
83+
style: Style {
84+
size: Size::new(Val::Px(150.0), Val::Px(65.0)),
85+
// Center this button in the middle of the window.
86+
margin: Rect::all(Val::Auto),
87+
..Default::default()
88+
},
89+
..Default::default()
90+
});
91+
}

0 commit comments

Comments
 (0)