More refactor.

This commit is contained in:
Samuel Guerra 2023-04-11 23:46:21 -03:00
parent 3bbf4683e1
commit 636d9c8782
19 changed files with 361 additions and 370 deletions

View File

@ -451,7 +451,7 @@ pub mod img_window {
})
}
}
fn img_window(title: impl IntoVar<Text>, child: impl UiNode) -> Window {
fn img_window(title: impl IntoVar<Text>, child: impl UiNode) -> WindowCfg {
img_window!(title; child)
}

View File

@ -22,7 +22,7 @@ fn app_main() {
App::default().run_window(main_window());
}
async fn main_window() -> Window {
async fn main_window() -> WindowCfg {
// WINDOWS.exit_on_last_close().set(false);
let window_vars = WINDOW_CTRL.vars();

View File

@ -87,7 +87,7 @@ fn shortcut_scoped() {
assert_eq!(&*TEST_TRACE.read(), &vec![format!("scoped-wgt / Widget({widget_id:?})")]);
}
async fn listener_window(focused_wgt: bool) -> Window {
async fn listener_window(focused_wgt: bool) -> WindowCfg {
#[ui_node(struct FooHandlerNode {
handle: Option<CommandHandle>,
handle_scoped: Option<CommandHandle>,

View File

@ -1637,7 +1637,7 @@ impl<E: AppExtension> TestAppBuilder<E> {
pub fn run(self, child: impl UiNode) -> TestApp {
self.run_window(window!(child; id = "window root"))
}
pub fn run_window(self, window: Window) -> TestApp {
pub fn run_window(self, window: WindowCfg) -> TestApp {
let mut app = self.app.run_headless(false);
let (focus_changed, return_focus_changed) = {

View File

@ -15,7 +15,7 @@ use super::{Image, ImageManager, ImageVar, ImagesService, IMAGES, IMAGES_SV};
impl ImagesService {
fn render<N>(&mut self, render: N) -> ImageVar
where
N: FnOnce() -> Window + Send + Sync + 'static,
N: FnOnce() -> WindowCfg + Send + Sync + 'static,
{
let result = var(Image::new_none(None));
self.render_img(
@ -37,7 +37,7 @@ impl ImagesService {
let scale_factor = scale_factor.into();
self.render(move || {
let node = render();
Window::new_container(
WindowCfg::new_container(
WidgetId::new_unique(),
StartPosition::Default,
false,
@ -52,7 +52,7 @@ impl ImagesService {
pub(super) fn render_img<N>(&mut self, render: N, result: &ArcVar<Image>)
where
N: FnOnce() -> Window + Send + Sync + 'static,
N: FnOnce() -> WindowCfg + Send + Sync + 'static,
{
self.render.requests.push(RenderRequest {
render: Box::new(render),
@ -75,7 +75,7 @@ impl IMAGES {
/// [`IMAGE_RENDER.retain`]: IMAGE_RENDER::retain
pub fn render<N>(&self, render: N) -> ImageVar
where
N: FnOnce() -> Window + Send + Sync + 'static,
N: FnOnce() -> WindowCfg + Send + Sync + 'static,
{
IMAGES_SV.write().render(render)
}
@ -178,7 +178,7 @@ struct ActiveRenderer {
}
struct RenderRequest {
render: Box<dyn FnOnce() -> Window + Send + Sync>,
render: Box<dyn FnOnce() -> WindowCfg + Send + Sync>,
image: WeakArcVar<Image>,
}

View File

@ -18,7 +18,7 @@ use crate::{
units::*,
var::{AnyVar, IntoValue, IntoVar, LocalVar, ReadOnlyArcVar},
widget_instance::UiNode,
window::{FrameCaptureMode, Window, WindowId, WINDOW_CTRL},
window::{FrameCaptureMode, WindowCfg, WindowId, WINDOW_CTRL},
};
pub use crate::app::view_process::{ImageDataFormat, ImageDownscale, ImagePpi};
@ -442,7 +442,7 @@ impl std::hash::Hasher for ImageHasher {
}
// We don't use Arc<dyn ..> because of this issue: https://github.com/rust-lang/rust/issues/69757
type RenderFn = Arc<Box<dyn Fn(&ImageRenderArgs) -> Window + Send + Sync>>;
type RenderFn = Arc<Box<dyn Fn(&ImageRenderArgs) -> WindowCfg + Send + Sync>>;
/// Arguments for the [`ImageSource::Render`] closure.
///
@ -517,7 +517,7 @@ impl ImageSource {
/// [`Images::render`]: crate::image::Images::render
pub fn render<F>(new_img: F) -> Self
where
F: Fn(&ImageRenderArgs) -> Window + Send + Sync + 'static,
F: Fn(&ImageRenderArgs) -> WindowCfg + Send + Sync + 'static,
{
Self::Render(
Arc::new(Box::new(move |args| {
@ -564,7 +564,7 @@ impl ImageSource {
Self::render(move |args| {
WINDOW_CTRL.vars().parent().set_ne(args.parent);
let node = render(args);
Window::new_container(
WindowCfg::new_container(
crate::widget_instance::WidgetId::new_unique(),
crate::window::StartPosition::Default,
false,

View File

@ -509,7 +509,7 @@ mod context {
use crate::window::*;
let mut app = app.run_headless(false);
WINDOWS.open(async move { crate::window::Window::new_test(root) });
WINDOWS.open(async move { crate::window::WindowCfg::new_test(root) });
let _ = app.update(false);
app
}

View File

@ -131,12 +131,12 @@ pub trait AppRunWindowExt {
/// [`WINDOW`]: crate::context::WINDOW
fn run_window<F>(self, new_window: F)
where
F: Future<Output = Window> + Send + 'static;
F: Future<Output = WindowCfg> + Send + 'static;
}
impl<E: AppExtension> AppRunWindowExt for AppExtended<E> {
fn run_window<F>(self, new_window: F)
where
F: Future<Output = Window> + Send + 'static,
F: Future<Output = WindowCfg> + Send + 'static,
{
self.run(async move {
WINDOWS.open(new_window);
@ -158,7 +158,7 @@ pub trait HeadlessAppWindowExt {
/// [`WINDOW`]: crate::context::WINDOW
fn open_window<F>(&mut self, new_window: F) -> WindowId
where
F: Future<Output = Window> + Send + 'static;
F: Future<Output = WindowCfg> + Send + 'static;
/// Cause the headless window to think it is focused in the screen.
fn focus_window(&mut self, window_id: WindowId);
@ -176,12 +176,12 @@ pub trait HeadlessAppWindowExt {
/// Open a new headless window and update the app until the window closes.
fn run_window<F>(&mut self, new_window: F)
where
F: Send + Future<Output = Window> + 'static;
F: Send + Future<Output = WindowCfg> + 'static;
}
impl HeadlessAppWindowExt for HeadlessApp {
fn open_window<F>(&mut self, new_window: F) -> WindowId
where
F: Future<Output = Window> + Send + 'static,
F: Future<Output = WindowCfg> + Send + 'static,
{
let response = WINDOWS.open(new_window);
self.run_task(async move {
@ -242,7 +242,7 @@ impl HeadlessAppWindowExt for HeadlessApp {
fn run_window<F>(&mut self, new_window: F)
where
F: Future<Output = Window> + Send + 'static,
F: Future<Output = WindowCfg> + Send + 'static,
{
let window_id = self.open_window(new_window);
while WINDOWS.is_open(window_id) {

View File

@ -27,7 +27,7 @@ use crate::{
use super::{
commands::{WindowCommands, MINIMIZE_CMD, RESTORE_CMD},
FrameCaptureMode, FrameImageReadyArgs, HeadlessMonitor, MonitorInfo, StartPosition, TransformChangedArgs, Window, WindowChangedArgs,
FrameCaptureMode, FrameImageReadyArgs, HeadlessMonitor, MonitorInfo, StartPosition, TransformChangedArgs, WindowCfg, WindowChangedArgs,
WindowChrome, WindowIcon, WindowId, WindowMode, WindowVars, FRAME_IMAGE_READY_EVENT, MONITORS_CHANGED_EVENT, TRANSFORM_CHANGED_EVENT,
WINDOWS, WINDOW_CHANGED_EVENT,
};
@ -63,7 +63,7 @@ struct HeadedCtrl {
root_font_size: Dip,
}
impl HeadedCtrl {
pub fn new(vars: &WindowVars, commands: WindowCommands, content: Window) -> Self {
pub fn new(vars: &WindowVars, commands: WindowCommands, content: WindowCfg) -> Self {
Self {
window: None,
waiting_view: false,
@ -1037,7 +1037,7 @@ struct HeadlessWithRendererCtrl {
var_bindings: VarHandles,
}
impl HeadlessWithRendererCtrl {
pub fn new(vars: &WindowVars, commands: WindowCommands, content: Window) -> Self {
pub fn new(vars: &WindowVars, commands: WindowCommands, content: WindowCfg) -> Self {
Self {
surface: None,
waiting_view: false,
@ -1281,7 +1281,7 @@ struct HeadlessCtrl {
var_bindings: VarHandles,
}
impl HeadlessCtrl {
pub fn new(vars: &WindowVars, commands: WindowCommands, content: Window) -> Self {
pub fn new(vars: &WindowVars, commands: WindowCommands, content: WindowCfg) -> Self {
Self {
vars: vars.clone(),
headless_monitor: content.headless_monitor,
@ -1471,7 +1471,7 @@ struct ContentCtrl {
previous_transforms: IdMap<WidgetId, PxTransform>,
}
impl ContentCtrl {
pub fn new(vars: WindowVars, commands: WindowCommands, window: Window) -> Self {
pub fn new(vars: WindowVars, commands: WindowCommands, window: WindowCfg) -> Self {
Self {
vars,
commands,
@ -1855,7 +1855,7 @@ enum WindowCtrlMode {
HeadlessWithRenderer(HeadlessWithRendererCtrl),
}
impl WindowCtrl {
pub fn new(vars: &WindowVars, commands: WindowCommands, mode: WindowMode, content: Window) -> Self {
pub fn new(vars: &WindowVars, commands: WindowCommands, mode: WindowMode, content: WindowCfg) -> Self {
WindowCtrl(match mode {
WindowMode::Headed => WindowCtrlMode::Headed(HeadedCtrl::new(vars, commands, content)),
WindowMode::Headless => WindowCtrlMode::Headless(HeadlessCtrl::new(vars, commands, content)),

View File

@ -75,7 +75,7 @@ impl WindowsService {
}
}
fn open_impl(&mut self, id: WindowId, new_window: UiTask<Window>, force_headless: Option<WindowMode>) -> ResponseVar<WindowOpenArgs> {
fn open_impl(&mut self, id: WindowId, new_window: UiTask<WindowCfg>, force_headless: Option<WindowMode>) -> ResponseVar<WindowOpenArgs> {
let (responder, response) = response_var();
let request = OpenWindowRequest {
id,
@ -255,7 +255,7 @@ impl WINDOWS {
/// can use the context [`WINDOW`] to set variables that will be read on init with the new value.
///
/// [loaded]: Self::is_loaded
pub fn open(&self, new_window: impl Future<Output = Window> + Send + 'static) -> ResponseVar<WindowOpenArgs> {
pub fn open(&self, new_window: impl Future<Output = WindowCfg> + Send + 'static) -> ResponseVar<WindowOpenArgs> {
WINDOWS_SV
.write()
.open_impl(WindowId::new_unique(), UiTask::new(None, new_window), None)
@ -269,7 +269,7 @@ impl WINDOWS {
pub fn open_id(
&self,
window_id: impl Into<WindowId>,
new_window: impl Future<Output = Window> + Send + 'static,
new_window: impl Future<Output = WindowCfg> + Send + 'static,
) -> ResponseVar<WindowOpenArgs> {
let window_id = window_id.into();
self.assert_id_unused(window_id);
@ -286,7 +286,7 @@ impl WINDOWS {
/// [`open`]: WINDOWS::open
pub fn open_headless(
&self,
new_window: impl Future<Output = Window> + Send + 'static,
new_window: impl Future<Output = WindowCfg> + Send + 'static,
with_renderer: bool,
) -> ResponseVar<WindowOpenArgs> {
WINDOWS_SV.write().open_impl(
@ -308,7 +308,7 @@ impl WINDOWS {
pub fn open_headless_id(
&self,
window_id: impl Into<WindowId>,
new_window: impl Future<Output = Window> + Send + 'static,
new_window: impl Future<Output = WindowCfg> + Send + 'static,
with_renderer: bool,
) -> ResponseVar<WindowOpenArgs> {
let window_id = window_id.into();
@ -535,7 +535,7 @@ impl WINDOWS {
pub fn focus_or_open(
&self,
window_id: impl Into<WindowId>,
open: impl Future<Output = Window> + Send + 'static,
open: impl Future<Output = WindowCfg> + Send + 'static,
) -> Option<ResponseVar<WindowOpenArgs>> {
let window_id = window_id.into();
if self.focus(window_id).is_ok() {
@ -1004,7 +1004,7 @@ impl AppWindowInfo {
}
struct OpenWindowRequest {
id: WindowId,
new: Mutex<UiTask<Window>>, // never locked, makes `OpenWindowRequest: Sync`
new: Mutex<UiTask<WindowCfg>>, // never locked, makes `OpenWindowRequest: Sync`
force_headless: Option<WindowMode>,
responder: ResponderVar<WindowOpenArgs>,
}
@ -1016,7 +1016,7 @@ struct CloseWindowRequest {
struct AppWindowTask {
ctx: WindowCtx,
mode: WindowMode,
task: Mutex<UiTask<Window>>, // never locked, used to make `AppWindowTask: Sync`
task: Mutex<UiTask<WindowCfg>>, // never locked, used to make `AppWindowTask: Sync`
responder: ResponderVar<WindowOpenArgs>,
}
impl AppWindowTask {
@ -1024,7 +1024,7 @@ impl AppWindowTask {
id: WindowId,
mode: WindowMode,
color_scheme: ColorScheme,
new: UiTask<Window>,
new: UiTask<WindowCfg>,
responder: ResponderVar<WindowOpenArgs>,
) -> Self {
let primary_scale_factor = MONITORS

View File

@ -153,7 +153,7 @@ impl crate::var::IntoValue<WindowId> for &'static StaticWindowId {}
/// More window configuration is accessible using the [`WindowVars`] type.
///
/// [`WindowVars`]: crate::window::WindowVars
pub struct Window {
pub struct WindowCfg {
pub(super) id: WidgetId,
pub(super) start_position: StartPosition,
pub(super) kiosk: bool,
@ -163,7 +163,7 @@ pub struct Window {
pub(super) start_focused: bool,
pub(super) child: BoxedUiNode,
}
impl Window {
impl WindowCfg {
/// New window from a `root` node that forms the window root widget.
///
/// * `root_id` - Widget ID of `root`.
@ -186,7 +186,7 @@ impl Window {
start_focused: bool,
root: impl UiNode,
) -> Self {
Window {
WindowCfg {
id: root_id,
start_position,
kiosk,
@ -218,7 +218,7 @@ impl Window {
start_focused: bool,
child: impl UiNode,
) -> Self {
Window::new_root(
WindowCfg::new_root(
root_id,
start_position,
kiosk,
@ -233,7 +233,7 @@ impl Window {
/// New test window.
#[cfg(any(test, doc, feature = "test_util"))]
pub fn new_test(child: impl UiNode) -> Self {
Window::new_container(
WindowCfg::new_container(
WidgetId::named("test-window-root"),
StartPosition::Default,
false,

View File

@ -156,7 +156,7 @@ pub mod prelude {
UiNodeListChain, UiNodeVec, WidgetId, ZIndex,
},
window::{
AppRunWindowExt, AutoSize, CursorIcon, FocusIndicator, HeadlessAppWindowExt, MonitorId, MonitorQuery, StartPosition, Window,
AppRunWindowExt, AutoSize, CursorIcon, FocusIndicator, HeadlessAppWindowExt, MonitorId, MonitorQuery, StartPosition, WindowCfg,
WindowChangedArgs, WindowChrome, WindowCloseRequestedArgs, WindowIcon, WindowId, WindowOpenArgs, WindowState, WindowVars,
WINDOWS, WINDOW_CTRL,
},

View File

@ -84,9 +84,9 @@ mod view;
#[doc(inline)]
pub use view::*;
mod window_wgt;
pub mod window;
#[doc(inline)]
pub use window_wgt::window;
pub use window::Window;
/// Minimal widget.
///

View File

@ -63,7 +63,7 @@ mod tests {
IMAGES.load_in_headless().set(true);
let ok = Arc::new(AtomicBool::new(false));
let window_id = app.open_window(async_clmv!(ok, {
Window! {
WindowCfg! {
child = image! {
source = img.clone();
img_error_fn = wgt_fn!(ok, |_| {

View File

@ -0,0 +1,300 @@
//!: Window widget, properties and helpers.
use crate::core::focus::*;
use crate::core::window::{HeadlessMonitor, StartPosition, WindowCfg};
use crate::prelude::new_widget::*;
pub mod commands;
pub mod nodes;
mod window_properties;
pub use nodes::{AnchorMode, AnchorOffset, AnchorSize, AnchorTransform, LayerIndex, LAYERS};
pub use window_properties::*;
/// A window container.
///
/// The instance type is [`WindowCfg`], that can be given to the [`WINDOWS`](crate::core::window::WINDOWS) service
/// to open a system window that is kept in sync with the window properties set in the widget.
///
/// # Examples
///
/// ```no_run
/// use zero_ui::prelude::*;
///
/// App::default().run_window(async {
/// window! {
/// title = "Window 1";
/// child = text!("Window 1");
/// }
/// })
/// ```
/// See [`run_window`](crate::core::window::AppRunWindowExt::run_window) for more details.
#[widget($crate::widgets::Window)]
pub struct Window(Container);
impl Window {
#[widget(on_start)]
fn on_start(&mut self) {
defaults! {
self;
background_color = color_scheme_map(rgb(0.1, 0.1, 0.1), rgb(0.9, 0.9, 0.9));
txt_color = color_scheme_map(rgb(0.92, 0.92, 0.92), rgb(0.08, 0.08, 0.08));
focus_highlight = {
offsets: FOCUS_HIGHLIGHT_OFFSETS_VAR,
widths: FOCUS_HIGHLIGHT_WIDTHS_VAR,
sides: color_scheme_map(
BorderSides::dashed(rgba(200, 200, 200, 1.0)),
BorderSides::dashed(colors::BLACK)
),
};
clear_color = color_scheme_map(rgb(0.1, 0.1, 0.1), rgb(0.9, 0.9, 0.9));
focus_scope = true;
tab_nav = TabNav::Cycle;
directional_nav = DirectionalNav::Cycle;
focus_scope_behavior = FocusScopeOnFocus::LastFocused;
save_state = SaveState::enabled();
// Use the `FONT_SIZE_VAR` default as the root font size.
font_size = crate::widgets::text::FONT_SIZE_VAR;
}
self.builder().push_build_action(|wgt| {
#[cfg(inspector)]
{
let can_inspect = wgt.capture_var_or_else(property_id!(can_inspect), || true);
wgt.push_intrinsic(NestGroup::EVENT, "inspect_cmd", |child| commands::inspect_node(child, can_inspect));
}
wgt.push_intrinsic(NestGroup::EVENT, "layers", nodes::layers);
wgt.push_intrinsic(NestGroup::CONTEXT, "context", nodes::color_scheme);
});
}
pub fn build(&mut self) -> WindowCfg {
let mut wgt = self.take_builder();
WindowCfg::new_root(
wgt.capture_value_or_else(property_id!(id), WidgetId::new_unique),
wgt.capture_value_or_default::<StartPosition>(property_id!(start_position)),
wgt.capture_value_or_default(property_id!(kiosk)),
wgt.capture_value_or_else(property_id!(allow_transparency), || true),
wgt.capture_value_or_default::<Option<RenderMode>>(property_id!(render_mode)),
wgt.capture_value_or_default::<HeadlessMonitor>(property_id!(headless_monitor)),
wgt.capture_value_or_default(property_id!(start_focused)),
wgt.build(),
)
}
}
/// Window position when it opens.
#[property(LAYOUT, capture, impl(Window))]
pub fn start_position(child: impl UiNode, position: impl IntoValue<StartPosition>) -> impl UiNode {}
/// If the Inspector can be opened for this window.
///
/// The default value is `true`, but only applies if built with the `inspector` feature.
#[cfg(inspector)]
#[property(LAYOUT, capture, impl(Window))]
pub fn can_inspect(child: impl UiNode, enabled: impl IntoVar<bool>) -> impl UiNode {}
/// Extra configuration for the window when run in [headless mode](crate::core::window::WindowMode::is_headless).
///
/// When a window runs in headed mode some values are inferred by window context, such as the scale factor that
/// is taken from the monitor. In headless mode these values can be configured manually.
#[property(LAYOUT, capture, impl(Window))]
pub fn headless_monitor(child: impl UiNode, monitor: impl IntoValue<HeadlessMonitor>) -> impl UiNode {}
/// If the window is forced to be the foreground keyboard focus after opening.
///
/// By default the windows manager decides if the window will receive focus after opening, usually it is focused
/// only if the process that started the window already has focus. Setting the property to `true` ensures that focus
/// is moved to the new window, potentially stealing the focus from other apps and disrupting the user.
#[property(CONTEXT, capture, impl(Window))]
pub fn start_focused(child: impl UiNode, enabled: impl IntoValue<bool>) -> impl UiNode {}
/// Lock-in kiosk mode.
///
/// In kiosk mode the only window states allowed are full-screen or full-screen exclusive, and
/// all subsequent windows opened are child of the kiosk window.
///
/// Note that this does not configure the windows manager,
/// you still need to setup a kiosk environment, it does not block `ALT+TAB`. This just stops the
/// app itself from accidentally exiting kiosk mode.
#[property(CONTEXT, capture, impl(Window))]
pub fn kiosk(child: impl UiNode, kiosk: impl IntoValue<bool>) -> impl UiNode {}
/// If semi-transparent content is "see-through", mixin with the OS pixels "behind" the window.
///
/// This is `true` by default, as it avoids the screen flashing black for windows opening in maximized or fullscreen modes
/// in the Microsoft Windows OS.
///
/// Note that to make use of this feature you must unset the [`clear_color`] and [`background_color`] or set then to
/// a semi-transparent color. The composition is a simple alpha blend, effects like blur do not apply to
/// the pixels "behind" the window.
///
/// [`clear_color`]: fn@clear_color
/// [`background_color`]: fn@background_color
#[property(CONTEXT, capture, impl(Window))]
pub fn allow_transparency(child: impl UiNode, allow: impl IntoValue<bool>) -> impl UiNode {}
/// Render performance mode overwrite for this window, if set to `None` the [`WINDOWS.default_render_mode`] is used.
///
/// # Examples
///
/// Prefer `Dedicated` renderer backend for just this window:
///
/// ```no_run
/// use zero_ui::prelude::*;
///
/// fn example() -> Window {
/// let selected_mode = WINDOW_CTRL.vars().render_mode();
/// window! {
/// title = "Render Mode";
/// render_mode = RenderMode::Dedicated;
/// child = text!(selected_mode.map(|m| formatx!("Preference: Dedicated\nActual: {m:?}")));
/// }
/// }
/// ```
///
/// The `view-process` will try to match the mode, if it is not available a fallback mode is selected,
/// see [`RenderMode`] for more details about each mode and fallbacks.
///
/// [`WINDOWS.default_render_mode`]: crate::core::window::WINDOWS::default_render_mode
#[property(CONTEXT, capture, impl(Window))]
pub fn render_mode(child: impl UiNode, mode: impl IntoValue<Option<RenderMode>>) -> impl UiNode {}
todo! {
/// Event just after the window opens.
///
/// This event notifies once per window, after the window content is inited.
///
/// This property is the [`on_pre_window_open`] so window handlers see it first.
///
/// [`on_pre_window_open`]: fn@events::window::on_pre_window_open
pub events::window::on_pre_window_open as on_open;
/// Event just after the window loads.
///
/// This event notifies once per window, after the window content is inited, updated, layout and the first frame
/// was send to the renderer. Windows are considered *loaded* after the first layout and all [`WindowLoadingHandle`]
/// have expired or dropped.
///
/// This property is the [`on_pre_window_load`] so window handlers see it first.
///
/// [`WindowLoadingHandle`]: crate::core::window::WindowLoadingHandle
/// [`on_pre_window_load`]: fn@events::window::on_pre_window_load
pub events::window::on_pre_window_load as on_load;
/// On window close requested.
///
/// This event notifies every time the user or the app tries to close the window, you can stop propagation
/// to stop the window from being closed.
pub events::window::on_window_close_requested as on_close_requested;
/// On window deinited.
///
/// This event notifies once after the window content is deinited because it is closing.
pub events::widget::on_deinit as on_close;
/// On window position changed.
///
/// This event notifies every time the user or app changes the window position. You can also track the window
/// position using the [`actual_position`] variable.
///
/// This property is the [`on_pre_window_moved`] so window handlers see it first.
///
/// [`actual_position`]: crate::core::window::WindowVars::actual_position
/// [`on_pre_window_moved`]: fn@events::window::on_pre_window_moved
pub events::window::on_pre_window_moved as on_moved;
/// On window size changed.
///
/// This event notifies every time the user or app changes the window content area size. You can also track
/// the window size using the [`actual_size`] variable.
///
/// This property is the [`on_pre_window_resized`] so window handlers see it first.
///
/// [`actual_size`]: crate::core::window::WindowVars::actual_size
/// [`on_pre_window_resized`]: fn@events::window::on_pre_window_resized
pub events::window::on_pre_window_resized as on_resized;
/// On window state changed.
///
/// This event notifies every time the user or app changes the window state. You can also track the window
/// state by setting [`state`] to a read-write variable.
///
/// This property is the [`on_pre_window_state_changed`] so window handlers see it first.
///
/// [`state`]: fn@state
/// [`on_pre_window_state_changed`]: fn@events::window::on_pre_window_state_changed
pub events::window::on_pre_window_state_changed as on_state_changed;
/// On window maximized.
///
/// This event notifies every time the user or app changes the window state to maximized.
///
/// This property is the [`on_pre_window_maximized`] so window handlers see it first.
///
/// [`on_pre_window_maximized`]: fn@events::window::on_pre_window_maximized
pub events::window::on_pre_window_maximized as on_maximized;
/// On window exited the maximized state.
///
/// This event notifies every time the user or app changes the window state to a different state from maximized.
///
/// This property is the [`on_pre_window_unmaximized`] so window handlers see it first.
///
/// [`on_pre_window_unmaximized`]: fn@events::window::on_pre_window_unmaximized
pub events::window::on_pre_window_unmaximized as on_unmaximized;
/// On window minimized.
///
/// This event notifies every time the user or app changes the window state to maximized.
///
/// This property is the [`on_pre_window_maximized`] so window handlers see it first.
///
/// [`on_pre_window_maximized`]: fn@events::window::on_pre_window_maximized
pub events::window::on_pre_window_minimized as on_minimized;
/// On window exited the minimized state.
///
/// This event notifies every time the user or app changes the window state to a different state from minimized.
///
/// This property is the [`on_pre_window_unminimized`] so window handlers see it first.
///
/// [`on_pre_window_unminimized`]: fn@events::window::on_pre_window_unminimized
pub events::window::on_pre_window_unminimized as on_unminimized;
/// On window state changed to [`Normal`].
///
/// This event notifies every time the user or app changes the window state to [`Normal`].
///
/// This property is the [`on_pre_window_restored`] so window handlers see it first.
///
/// [`Normal`]: crate::core::window::WindowState::Normal
/// [`on_pre_window_restored`]: fn@events::window::on_pre_window_restored
pub events::window::on_pre_window_restored as on_restored;
/// On window enter one of the fullscreen states.
///
/// This event notifies every time the user or app changes the window state to [`Fullscreen`] or [`Exclusive`].
///
/// This property is the [`on_pre_window_fullscreen`] so window handlers see it first.
///
/// [`Fullscreen`]: crate::core::window::WindowState::Fullscreen
/// [`Exclusive`]: crate::core::window::WindowState::Exclusive
/// [`on_pre_window_fullscreen`]: fn@events::window::on_pre_window_fullscreen
pub events::window::on_pre_window_fullscreen as on_fullscreen;
/// On window is no longer fullscreen.
///
/// This event notifies every time the user or app changed the window state to one that is not fullscreen.
///
/// This property is the [`on_pre_window_exited_fullscreen`] so window handlers see it first.
///
/// [`on_pre_window_exited_fullscreen`]: fn@events::window::on_pre_window_exited_fullscreen
pub events::window::on_pre_window_exited_fullscreen as on_exited_fullscreen;
/// On window frame rendered.
///
/// If [`frame_image_capture`](fn@frame_image_capture) is set
pub events::window::on_pre_frame_image_ready as on_frame_image_ready;
}

View File

@ -64,7 +64,7 @@ mod inspector_window {
use crate::core::{inspector::*, window::*};
use crate::prelude::new_widget::*;
pub fn new(inspected: WindowId, inspector_text: ArcVar<Text>) -> Window {
pub fn new(inspected: WindowId, inspector_text: ArcVar<Text>) -> WindowCfg {
use crate::widgets::*;
let parent = WINDOWS.vars(inspected).unwrap().parent().get().unwrap_or(inspected);

View File

@ -11,6 +11,8 @@ use crate::core::window::{
use crate::prelude::new_property::*;
use serde::{Deserialize, Serialize};
use super::Window;
fn bind_window_var<T, V>(child: impl UiNode, user_var: impl IntoVar<T>, select: impl Fn(&WindowVars) -> V + Send + 'static) -> impl UiNode
where
T: VarValue + PartialEq,
@ -50,7 +52,7 @@ macro_rules! set_properties {
#[doc = "Binds the [`"$ident "`](WindowVars::"$ident ") window var with the property value."]
///
/// The binding is bidirectional and the window variable is assigned on init.
#[property(CONTEXT)]
#[property(CONTEXT, impl(Window))]
pub fn $ident(child: impl UiNode, $ident: impl IntoVar<$Type>) -> impl UiNode {
bind_window_var(child, $ident, |w|w.$ident().clone())
}
@ -95,18 +97,18 @@ set_properties! {
}
macro_rules! map_properties {
($(
$ident:ident . $member:ident = $name:ident : $Type:ty,
)+) => {$(paste::paste! {
#[doc = "Binds the `"$member "` of the [`"$ident "`](WindowVars::"$ident ") window var with the property value."]
///
/// The binding is bidirectional and the window variable is assigned on init.
#[property(CONTEXT)]
pub fn $name(child: impl UiNode, $name: impl IntoVar<$Type>) -> impl UiNode {
bind_window_var(child, $name, |w|w.$ident().map_ref_bidi(|v| &v.$member, |v|&mut v.$member))
}
})+}
($(
$ident:ident . $member:ident = $name:ident : $Type:ty,
)+) => {$(paste::paste! {
#[doc = "Binds the `"$member "` of the [`"$ident "`](WindowVars::"$ident ") window var with the property value."]
///
/// The binding is bidirectional and the window variable is assigned on init.
#[property(CONTEXT, impl(Window))]
pub fn $name(child: impl UiNode, $name: impl IntoVar<$Type>) -> impl UiNode {
bind_window_var(child, $name, |w|w.$ident().map_ref_bidi(|v| &v.$member, |v|&mut v.$member))
}
})+}
}
map_properties! {
position.x = x: Length,
position.y = y: Length,
@ -124,7 +126,7 @@ map_properties! {
/// It is visible if window content does not completely fill the content area, this
/// can happen if you do not set a background or the background is semi-transparent, also
/// can happen during very fast resizes.
#[property(CONTEXT, default(colors::WHITE))]
#[property(CONTEXT, default(colors::WHITE), impl(Window))]
pub fn clear_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
#[ui_node(struct ClearColorNode {
child: impl UiNode,
@ -247,7 +249,7 @@ impl_from_and_into_var! {
///
/// This property is enabled by default in the `window!` widget, it is recommended to open the window with a name if
/// the app can open more than one window.
#[property(CONTEXT, default(SaveState::Disabled))]
#[property(CONTEXT, default(SaveState::Disabled), impl(Window))]
pub fn save_state(child: impl UiNode, enabled: impl IntoValue<SaveState>) -> impl UiNode {
enum Task {
None,

View File

@ -1,311 +0,0 @@
use crate::core::focus::*;
use crate::core::window::{HeadlessMonitor, StartPosition, Window};
use crate::prelude::new_widget::*;
pub mod commands;
pub mod nodes;
pub mod window_properties;
/// A window container.
///
/// The instance type is [`Window`], that can be given to the [`WINDOWS`](crate::core::window::WINDOWS) service
/// to open a system window that is kept in sync with the window properties set in the widget.
///
/// # Examples
///
/// ```no_run
/// use zero_ui::prelude::*;
///
/// App::default().run_window(async {
/// window! {
/// title = "Window 1";
/// child = text!("Window 1");
/// }
/// })
/// ```
/// See [`run_window`](crate::core::window::AppRunWindowExt::run_window) for more details.
#[widget($crate::widgets::window)]
pub mod window {
use super::*;
use crate::widgets::mixins::focusable_mixin::vis::*;
use crate::properties::{events, focus};
inherit!(container);
pub use super::{commands, nodes};
#[doc(inline)]
pub use nodes::{AnchorMode, AnchorOffset, AnchorSize, AnchorTransform, LayerIndex, LAYERS};
#[doc(inline)]
pub use crate::widgets::window_wgt::window_properties::{
always_on_top, auto_size, auto_size_origin, chrome, color_scheme, font_size, frame_capture_mode, height, icon, max_height,
max_size, max_width, min_height, min_size, min_width, modal, monitor, movable, parent, position, resizable, size, state,
taskbar_visible, title, visible, width, x, y, *,
};
properties! {
/// Window position when it opens.
pub start_position(impl IntoValue<StartPosition>);
background_color = color_scheme_map(rgb(0.1, 0.1, 0.1), rgb(0.9, 0.9, 0.9));
txt_color = color_scheme_map(rgb(0.92, 0.92, 0.92), rgb(0.08, 0.08, 0.08));
focus_highlight = {
offsets: FOCUS_HIGHLIGHT_OFFSETS_VAR,
widths: FOCUS_HIGHLIGHT_WIDTHS_VAR,
sides: color_scheme_map(
BorderSides::dashed(rgba(200, 200, 200, 1.0)),
BorderSides::dashed(colors::BLACK)
),
};
clear_color = color_scheme_map(rgb(0.1, 0.1, 0.1), rgb(0.9, 0.9, 0.9));
focus_scope = true;
/// Windows cycle TAB navigation by default.
pub focus::tab_nav = TabNav::Cycle;
/// Windows cycle arrow navigation by default.
pub focus::directional_nav = DirectionalNav::Cycle;
/// Windows remember the last focused widget and return focus when the window is focused.
pub focus::focus_scope_behavior = FocusScopeOnFocus::LastFocused;
/// If the Inspector can be opened for this window.
///
/// The default value is `true`, but only applies if built with the `inspector` feature.
#[cfg(inspector)]
pub can_inspect(impl IntoVar<bool>);
/// Extra configuration for the window when run in [headless mode](crate::core::window::WindowMode::is_headless).
///
/// When a window runs in headed mode some values are inferred by window context, such as the scale factor that
/// is taken from the monitor. In headless mode these values can be configured manually.
pub headless_monitor(impl IntoValue<HeadlessMonitor>);
/// If the window is forced to be the foreground keyboard focus after opening.
///
/// By default the windows manager decides if the window will receive focus after opening, usually it is focused
/// only if the process that started the window already has focus. Setting the property to `true` ensures that focus
/// is moved to the new window, potentially stealing the focus from other apps and disrupting the user.
pub start_focused(impl IntoValue<bool>);
/// Lock-in kiosk mode.
///
/// In kiosk mode the only window states allowed are full-screen or full-screen exclusive, and
/// all subsequent windows opened are child of the kiosk window.
///
/// Note that this does not configure the windows manager,
/// you still need to setup a kiosk environment, it does not block `ALT+TAB`. This just stops the
/// app itself from accidentally exiting kiosk mode.
pub kiosk(impl IntoValue<bool>);
/// If semi-transparent content is "see-through", mixin with the OS pixels "behind" the window.
///
/// This is `true` by default, as it avoids the screen flashing black for windows opening in maximized or fullscreen modes
/// in the Microsoft Windows OS.
///
/// Note that to make use of this feature you must unset the [`clear_color`] and [`background_color`] or set then to
/// a semi-transparent color. The composition is a simple alpha blend, effects like blur do not apply to
/// the pixels "behind" the window.
///
/// [`clear_color`]: fn@clear_color
/// [`background_color`]: fn@background_color
pub allow_transparency(impl IntoValue<bool>);
/// Render performance mode overwrite for this window, if set to `None` the [`WINDOWS.default_render_mode`] is used.
///
/// # Examples
///
/// Prefer `Dedicated` renderer backend for just this window:
///
/// ```no_run
/// use zero_ui::prelude::*;
///
/// fn example() -> Window {
/// let selected_mode = WINDOW_CTRL.vars().render_mode();
/// window! {
/// title = "Render Mode";
/// render_mode = RenderMode::Dedicated;
/// child = text!(selected_mode.map(|m| formatx!("Preference: Dedicated\nActual: {m:?}")));
/// }
/// }
/// ```
///
/// The `view-process` will try to match the mode, if it is not available a fallback mode is selected,
/// see [`RenderMode`] for more details about each mode and fallbacks.
///
/// [`WINDOWS.default_render_mode`]: crate::core::window::WINDOWS::default_render_mode
pub render_mode(impl IntoValue<Option<RenderMode>>);
/// Save and restore the window state.
save_state = SaveState::enabled();
/// Event just after the window opens.
///
/// This event notifies once per window, after the window content is inited.
///
/// This property is the [`on_pre_window_open`] so window handlers see it first.
///
/// [`on_pre_window_open`]: fn@events::window::on_pre_window_open
pub events::window::on_pre_window_open as on_open;
/// Event just after the window loads.
///
/// This event notifies once per window, after the window content is inited, updated, layout and the first frame
/// was send to the renderer. Windows are considered *loaded* after the first layout and all [`WindowLoadingHandle`]
/// have expired or dropped.
///
/// This property is the [`on_pre_window_load`] so window handlers see it first.
///
/// [`WindowLoadingHandle`]: crate::core::window::WindowLoadingHandle
/// [`on_pre_window_load`]: fn@events::window::on_pre_window_load
pub events::window::on_pre_window_load as on_load;
/// On window close requested.
///
/// This event notifies every time the user or the app tries to close the window, you can stop propagation
/// to stop the window from being closed.
pub events::window::on_window_close_requested as on_close_requested;
/// On window deinited.
///
/// This event notifies once after the window content is deinited because it is closing.
pub events::widget::on_deinit as on_close;
/// On window position changed.
///
/// This event notifies every time the user or app changes the window position. You can also track the window
/// position using the [`actual_position`] variable.
///
/// This property is the [`on_pre_window_moved`] so window handlers see it first.
///
/// [`actual_position`]: crate::core::window::WindowVars::actual_position
/// [`on_pre_window_moved`]: fn@events::window::on_pre_window_moved
pub events::window::on_pre_window_moved as on_moved;
/// On window size changed.
///
/// This event notifies every time the user or app changes the window content area size. You can also track
/// the window size using the [`actual_size`] variable.
///
/// This property is the [`on_pre_window_resized`] so window handlers see it first.
///
/// [`actual_size`]: crate::core::window::WindowVars::actual_size
/// [`on_pre_window_resized`]: fn@events::window::on_pre_window_resized
pub events::window::on_pre_window_resized as on_resized;
/// On window state changed.
///
/// This event notifies every time the user or app changes the window state. You can also track the window
/// state by setting [`state`] to a read-write variable.
///
/// This property is the [`on_pre_window_state_changed`] so window handlers see it first.
///
/// [`state`]: fn@state
/// [`on_pre_window_state_changed`]: fn@events::window::on_pre_window_state_changed
pub events::window::on_pre_window_state_changed as on_state_changed;
/// On window maximized.
///
/// This event notifies every time the user or app changes the window state to maximized.
///
/// This property is the [`on_pre_window_maximized`] so window handlers see it first.
///
/// [`on_pre_window_maximized`]: fn@events::window::on_pre_window_maximized
pub events::window::on_pre_window_maximized as on_maximized;
/// On window exited the maximized state.
///
/// This event notifies every time the user or app changes the window state to a different state from maximized.
///
/// This property is the [`on_pre_window_unmaximized`] so window handlers see it first.
///
/// [`on_pre_window_unmaximized`]: fn@events::window::on_pre_window_unmaximized
pub events::window::on_pre_window_unmaximized as on_unmaximized;
/// On window minimized.
///
/// This event notifies every time the user or app changes the window state to maximized.
///
/// This property is the [`on_pre_window_maximized`] so window handlers see it first.
///
/// [`on_pre_window_maximized`]: fn@events::window::on_pre_window_maximized
pub events::window::on_pre_window_minimized as on_minimized;
/// On window exited the minimized state.
///
/// This event notifies every time the user or app changes the window state to a different state from minimized.
///
/// This property is the [`on_pre_window_unminimized`] so window handlers see it first.
///
/// [`on_pre_window_unminimized`]: fn@events::window::on_pre_window_unminimized
pub events::window::on_pre_window_unminimized as on_unminimized;
/// On window state changed to [`Normal`].
///
/// This event notifies every time the user or app changes the window state to [`Normal`].
///
/// This property is the [`on_pre_window_restored`] so window handlers see it first.
///
/// [`Normal`]: crate::core::window::WindowState::Normal
/// [`on_pre_window_restored`]: fn@events::window::on_pre_window_restored
pub events::window::on_pre_window_restored as on_restored;
/// On window enter one of the fullscreen states.
///
/// This event notifies every time the user or app changes the window state to [`Fullscreen`] or [`Exclusive`].
///
/// This property is the [`on_pre_window_fullscreen`] so window handlers see it first.
///
/// [`Fullscreen`]: crate::core::window::WindowState::Fullscreen
/// [`Exclusive`]: crate::core::window::WindowState::Exclusive
/// [`on_pre_window_fullscreen`]: fn@events::window::on_pre_window_fullscreen
pub events::window::on_pre_window_fullscreen as on_fullscreen;
/// On window is no longer fullscreen.
///
/// This event notifies every time the user or app changed the window state to one that is not fullscreen.
///
/// This property is the [`on_pre_window_exited_fullscreen`] so window handlers see it first.
///
/// [`on_pre_window_exited_fullscreen`]: fn@events::window::on_pre_window_exited_fullscreen
pub events::window::on_pre_window_exited_fullscreen as on_exited_fullscreen;
/// On window frame rendered.
///
/// If [`frame_image_capture`](fn@frame_image_capture) is set
pub events::window::on_pre_frame_image_ready as on_frame_image_ready;
/// Use the `FONT_SIZE_VAR` default as the root font size.
font_size = crate::widgets::text::FONT_SIZE_VAR;
}
fn include(wgt: &mut WidgetBuilder) {
wgt.push_build_action(|wgt| {
#[cfg(inspector)]
{
let can_inspect = wgt.capture_var_or_else(property_id!(self::can_inspect), || true);
wgt.push_intrinsic(NestGroup::EVENT, "inspect_cmd", |child| commands::inspect_node(child, can_inspect));
}
wgt.push_intrinsic(NestGroup::EVENT, "layers", nodes::layers);
wgt.push_intrinsic(NestGroup::CONTEXT, "context", nodes::color_scheme);
});
}
fn build(mut wgt: WidgetBuilder) -> Window {
Window::new_root(
wgt.capture_value_or_else(property_id!(self::id), WidgetId::new_unique),
wgt.capture_value_or_default::<StartPosition>(property_id!(self::start_position)),
wgt.capture_value_or_default(property_id!(self::kiosk)),
wgt.capture_value_or_else(property_id!(self::allow_transparency), || true),
wgt.capture_value_or_default::<Option<RenderMode>>(property_id!(self::render_mode)),
wgt.capture_value_or_default::<HeadlessMonitor>(property_id!(self::headless_monitor)),
wgt.capture_value_or_default(property_id!(self::start_focused)),
wgt.build(),
)
}
}