@@ -9,7 +9,7 @@ use bevy_render::{
99 texture:: Image ,
1010} ;
1111use bevy_transform:: prelude:: GlobalTransform ;
12- use bevy_utils:: smallvec:: SmallVec ;
12+ use bevy_utils:: { smallvec:: SmallVec , warn_once } ;
1313use bevy_window:: { PrimaryWindow , WindowRef } ;
1414use std:: num:: { NonZeroI16 , NonZeroU16 } ;
1515use thiserror:: Error ;
@@ -1844,22 +1844,69 @@ impl TargetCamera {
18441844 }
18451845}
18461846
1847+ #[ derive( Component ) ]
1848+ /// Marker used to identify default cameras, they will have priority over the [`PrimaryWindow`] camera.
1849+ ///
1850+ /// This is useful if the [`PrimaryWindow`] has two cameras, one of them used
1851+ /// just for debug purposes and the user wants a way to choose the default [`Camera`]
1852+ /// without having to add a [`TargetCamera`] to the root node.
1853+ ///
1854+ /// Another use is when the user wants the Ui to be in another window by default,
1855+ /// all that is needed is to place this component on the camera
1856+ ///
1857+ /// ```
1858+ /// # use bevy_ui::prelude::*;
1859+ /// # use bevy_ecs::prelude::Commands;
1860+ /// # use bevy_render::camera::{Camera, RenderTarget};
1861+ /// # use bevy_core_pipeline::prelude::Camera2dBundle;
1862+ /// # use bevy_window::{Window, WindowRef};
1863+ ///
1864+ /// fn spawn_camera(mut commands: Commands) {
1865+ /// let another_window = commands.spawn(Window {
1866+ /// title: String::from("Another window"),
1867+ /// ..Default::default()
1868+ /// }).id();
1869+ /// commands.spawn((
1870+ /// Camera2dBundle {
1871+ /// camera: Camera {
1872+ /// target: RenderTarget::Window(WindowRef::Entity(another_window)),
1873+ /// ..Default::default()
1874+ /// },
1875+ /// ..Default::default()
1876+ /// },
1877+ /// // We add the Marker here so all Ui will spawn in
1878+ /// // another window if no TargetCamera is specified
1879+ /// IsDefaultUiCamera
1880+ /// ));
1881+ /// }
1882+ /// ```
1883+ pub struct IsDefaultUiCamera ;
1884+
18471885#[ derive( SystemParam ) ]
18481886pub struct DefaultUiCamera < ' w , ' s > {
18491887 cameras : Query < ' w , ' s , ( Entity , & ' static Camera ) > ,
1888+ default_cameras : Query < ' w , ' s , Entity , ( With < Camera > , With < IsDefaultUiCamera > ) > ,
18501889 primary_window : Query < ' w , ' s , Entity , With < PrimaryWindow > > ,
18511890}
18521891
18531892impl < ' w , ' s > DefaultUiCamera < ' w , ' s > {
18541893 pub fn get ( & self ) -> Option < Entity > {
1855- self . cameras
1856- . iter ( )
1857- . filter ( |( _, c) | match c. target {
1858- RenderTarget :: Window ( WindowRef :: Primary ) => true ,
1859- RenderTarget :: Window ( WindowRef :: Entity ( w) ) => self . primary_window . get ( w) . is_ok ( ) ,
1860- _ => false ,
1861- } )
1862- . max_by_key ( |( e, c) | ( c. order , * e) )
1863- . map ( |( e, _) | e)
1894+ self . default_cameras . get_single ( ) . ok ( ) . or_else ( || {
1895+ // If there isn't a single camera and the query isn't empty, there is two or more cameras queried.
1896+ if !self . default_cameras . is_empty ( ) {
1897+ warn_once ! ( "Two or more Entities with IsDefaultUiCamera found when only one Camera with this marker is allowed." ) ;
1898+ }
1899+ self . cameras
1900+ . iter ( )
1901+ . filter ( |( _, c) | match c. target {
1902+ RenderTarget :: Window ( WindowRef :: Primary ) => true ,
1903+ RenderTarget :: Window ( WindowRef :: Entity ( w) ) => {
1904+ self . primary_window . get ( w) . is_ok ( )
1905+ }
1906+ _ => false ,
1907+ } )
1908+ . max_by_key ( |( e, c) | ( c. order , * e) )
1909+ . map ( |( e, _) | e)
1910+ } )
18641911 }
18651912}
0 commit comments