Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor window creation. #485

Merged
merged 2 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,13 @@ impl Application {
self
}

/// create a new window for the application, if you want multiple windows,
/// just chain more window method to the builder
/// Create a new window for the application, if you want multiple windows,
/// just chain more window method to the builder.
///
/// # Note
///
/// Using `None` as a configuration argument is equivalent to using
/// `WindowConfig::default()`.
pub fn window<V: IntoView + 'static>(
mut self,
app_view: impl FnOnce(WindowId) -> V + 'static,
Expand All @@ -128,7 +133,7 @@ impl Application {
self.handle.as_mut().unwrap().new_window(
&self.event_loop,
Box::new(|window_id| app_view(window_id).into_any()),
config,
config.unwrap_or_default(),
);
self
}
Expand Down
190 changes: 92 additions & 98 deletions src/app_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl ApplicationHandle {
for event in events {
match event {
AppUpdateEvent::NewWindow { view_fn, config } => {
self.new_window(event_loop, view_fn, config)
self.new_window(event_loop, view_fn, config.unwrap_or_default())
}
AppUpdateEvent::CloseWindow { window_id } => {
self.close_window(window_id, event_loop);
Expand Down Expand Up @@ -248,113 +248,107 @@ impl ApplicationHandle {
&mut self,
event_loop: &EventLoopWindowTarget<UserEvent>,
view_fn: Box<dyn FnOnce(WindowId) -> Box<dyn View>>,
config: Option<WindowConfig>,
#[allow(unused_variables)] WindowConfig {
size,
position,
show_titlebar,
transparent,
fullscreen,
window_icon,
title,
enabled_buttons,
resizable,
undecorated,
window_level,
apply_default_theme,
mac_os_config,
}: WindowConfig,
) {
let mut window_builder = floem_winit::window::WindowBuilder::new();
let transparent = config.as_ref().and_then(|c| c.transparent).unwrap_or(false);
let apply_default_theme = if let Some(config) = config {
if let Some(size) = config.size {
let size = if size.width == 0.0 || size.height == 0.0 {
Size::new(800.0, 600.0)
} else {
size
};
window_builder =
window_builder.with_inner_size(LogicalSize::new(size.width, size.height));
}
if let Some(pos) = config.position {
window_builder = window_builder.with_position(LogicalPosition::new(pos.x, pos.y));
}
if let Some(show_titlebar) = config.show_titlebar {
#[cfg(target_os = "macos")]
if !show_titlebar {
use floem_winit::platform::macos::WindowBuilderExtMacOS;
window_builder = window_builder
.with_movable(false)
.with_title_hidden(true)
.with_titlebar_transparent(true)
.with_fullsize_content_view(true)
.with_traffic_lights_offset(11.0, 16.0);
}
#[cfg(not(target_os = "macos"))]
if !show_titlebar {
window_builder = window_builder.with_decorations(false);
}
let mut window_builder = floem_winit::window::WindowBuilder::new()
.with_decorations(!undecorated)
.with_transparent(transparent)
.with_fullscreen(fullscreen)
.with_window_level(window_level)
.with_window_icon(window_icon)
.with_resizable(resizable)
.with_enabled_buttons(enabled_buttons)
.with_inner_size(LogicalSize::new(size.width, size.height));

if let Some(pos) = position {
window_builder = window_builder.with_position(LogicalPosition::new(pos.x, pos.y));
}

if let Some(title) = title {
window_builder = window_builder.with_title(title);
}

#[cfg(not(target_os = "macos"))]
if !show_titlebar {
window_builder = window_builder.with_decorations(false);
}

#[cfg(target_os = "macos")]
if !show_titlebar {
use floem_winit::platform::macos::WindowBuilderExtMacOS;
window_builder = window_builder
.with_movable(false)
.with_title_hidden(true)
.with_titlebar_transparent(true)
.with_fullsize_content_view(true)
.with_traffic_lights_offset(11.0, 16.0);
}

#[cfg(target_os = "macos")]
if undecorated {
use floem_winit::platform::macos::WindowBuilderExtMacOS;
// A palette-style window that will only obtain window focus but
// not actually propagate the first mouse click it receives is
// very unlikely to be expected behavior - these typically are
// used for something that offers a quick choice and are closed
// in a single pointer gesture.
window_builder = window_builder.with_accepts_first_mouse(true);
}

#[cfg(target_os = "macos")]
if let Some(mac) = mac_os_config {
use floem_winit::platform::macos::WindowBuilderExtMacOS;
if let Some(val) = mac.movable_by_window_background {
window_builder = window_builder.with_movable_by_window_background(val);
}
if let Some(undecorated) = config.undecorated {
window_builder = window_builder.with_decorations(!undecorated);
#[cfg(target_os = "macos")]
if undecorated {
use floem_winit::platform::macos::WindowBuilderExtMacOS;
// A palette-style window that will only obtain window focus but
// not actually propagate the first mouse click it receives is
// very unlikely to be expected behavior - these typically are
// used for something that offers a quick choice and are closed
// in a single pointer gesture.
window_builder = window_builder.with_accepts_first_mouse(true);
}
if let Some(val) = mac.titlebar_transparent {
window_builder = window_builder.with_titlebar_transparent(val);
}
if let Some(transparent) = config.transparent {
window_builder = window_builder.with_transparent(transparent);
if let Some(val) = mac.titlebar_hidden {
window_builder = window_builder.with_titlebar_hidden(val);
}
if let Some(fullscreen) = config.fullscreen {
window_builder = window_builder.with_fullscreen(Some(fullscreen));
if let Some(val) = mac.full_size_content_view {
window_builder = window_builder.with_fullsize_content_view(val);
}
if let Some(window_level) = config.window_level {
window_builder = window_builder.with_window_level(window_level);
if let Some(val) = mac.movable {
window_builder = window_builder.with_movable(val);
}
if let Some(title) = config.title {
window_builder = window_builder.with_title(title);
if let Some((x, y)) = mac.traffic_lights_offset {
window_builder = window_builder.with_traffic_lights_offset(x, y);
}
if let Some(window_icon) = config.window_icon {
window_builder = window_builder.with_window_icon(Some(window_icon));
if let Some(val) = mac.accepts_first_mouse {
window_builder = window_builder.with_accepts_first_mouse(val);
}
#[cfg(target_os = "macos")]
if let Some(mac) = config.mac_os_config {
use floem_winit::platform::macos::WindowBuilderExtMacOS;
if let Some(val) = mac.movable_by_window_background {
window_builder = window_builder.with_movable_by_window_background(val);
}
if let Some(val) = mac.titlebar_transparent {
window_builder = window_builder.with_titlebar_transparent(val);
}
if let Some(val) = mac.titlebar_hidden {
window_builder = window_builder.with_titlebar_hidden(val);
}
if let Some(val) = mac.full_size_content_view {
window_builder = window_builder.with_fullsize_content_view(val);
}
if let Some(val) = mac.movable {
window_builder = window_builder.with_movable(val);
}
if let Some((x, y)) = mac.traffic_lights_offset {
window_builder = window_builder.with_traffic_lights_offset(x, y);
}
if let Some(val) = mac.accepts_first_mouse {
window_builder = window_builder.with_accepts_first_mouse(val);
}
if let Some(val) = mac.option_as_alt {
window_builder = window_builder.with_option_as_alt(val.into());
}
if let Some(title) = mac.tabbing_identifier {
window_builder = window_builder.with_tabbing_identifier(title.as_str());
}
if let Some(disallow_hidpi) = mac.disallow_high_dpi {
window_builder = window_builder.with_disallow_hidpi(disallow_hidpi);
}
if let Some(shadow) = mac.has_shadow {
window_builder = window_builder.with_has_shadow(shadow);
}
if let Some(val) = mac.option_as_alt {
window_builder = window_builder.with_option_as_alt(val.into());
}
config.apply_default_theme.unwrap_or(true)
} else {
true
};
if let Some(title) = mac.tabbing_identifier {
window_builder = window_builder.with_tabbing_identifier(title.as_str());
}
if let Some(disallow_hidpi) = mac.disallow_high_dpi {
window_builder = window_builder.with_disallow_hidpi(disallow_hidpi);
}
if let Some(shadow) = mac.has_shadow {
window_builder = window_builder.with_has_shadow(shadow);
}
}

let result = window_builder.build(event_loop);
let window = match result {
Ok(window) => window,
Err(_) => return,
let Ok(window) = window_builder.build(event_loop) else {
return;
};
let window_id = window.id();
let window_handle = WindowHandle::new(window, view_fn, transparent, apply_default_theme);
Expand Down
8 changes: 1 addition & 7 deletions src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,13 +967,7 @@ pub fn capture(window_id: WindowId) {
EventPropagation::Continue
})
},
Some(WindowConfig {
size: Some(Size {
width: 1200.0,
height: 800.0,
}),
..Default::default()
}),
Some(WindowConfig::default().size((1200.0, 800.0))),
);
}

Expand Down
70 changes: 53 additions & 17 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,85 +10,121 @@ use peniko::kurbo::{Point, Size};
use crate::app::{add_app_update_event, AppUpdateEvent};
use crate::view::IntoView;

#[derive(Default, Debug)]
#[derive(Debug)]
pub struct WindowConfig {
pub(crate) size: Option<Size>,
pub(crate) size: Size,
pub(crate) position: Option<Point>,
pub(crate) show_titlebar: Option<bool>,
pub(crate) transparent: Option<bool>,
pub(crate) show_titlebar: bool,
pub(crate) transparent: bool,
pub(crate) fullscreen: Option<Fullscreen>,
pub(crate) window_icon: Option<Icon>,
pub(crate) title: Option<String>,
pub(crate) enabled_buttons: Option<WindowButtons>,
pub(crate) resizable: Option<bool>,
pub(crate) undecorated: Option<bool>,
pub(crate) window_level: Option<WindowLevel>,
pub(crate) apply_default_theme: Option<bool>,
pub(crate) enabled_buttons: WindowButtons,
pub(crate) resizable: bool,
pub(crate) undecorated: bool,
pub(crate) window_level: WindowLevel,
pub(crate) apply_default_theme: bool,
#[allow(dead_code)]
pub(crate) mac_os_config: Option<MacOSWindowConfig>,
}

impl Default for WindowConfig {
fn default() -> Self {
Self {
size: Size::new(800.0, 600.0),
position: None,
show_titlebar: true,
transparent: false,
fullscreen: None,
window_icon: None,
title: None,
enabled_buttons: WindowButtons::all(),
resizable: true,
undecorated: false,
window_level: WindowLevel::Normal,
apply_default_theme: true,
mac_os_config: None,
}
}
}

impl WindowConfig {
/// Sets new window size.
///
/// # Panics
///
/// Panics if either width or height of new size is zero.
pub fn size(mut self, size: impl Into<Size>) -> Self {
self.size = Some(size.into());
self.size = size.into();
self
}

#[inline]
pub fn position(mut self, position: Point) -> Self {
self.position = Some(position);
self
}

#[inline]
pub fn show_titlebar(mut self, show_titlebar: bool) -> Self {
self.show_titlebar = Some(show_titlebar);
self.show_titlebar = show_titlebar;
self
}

#[inline]
pub fn undecorated(mut self, undecorated: bool) -> Self {
self.undecorated = Some(undecorated);
self.undecorated = undecorated;
self
}

#[inline]
pub fn with_transparent(mut self, transparent: bool) -> Self {
self.transparent = Some(transparent);
self.transparent = transparent;
self
}

#[inline]
pub fn fullscreen(mut self, fullscreen: Fullscreen) -> Self {
self.fullscreen = Some(fullscreen);
self
}

#[inline]
pub fn window_icon(mut self, window_icon: Icon) -> Self {
self.window_icon = Some(window_icon);
self
}

#[inline]
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}

#[inline]
pub fn enabled_buttons(mut self, enabled_buttons: WindowButtons) -> Self {
self.enabled_buttons = Some(enabled_buttons);
self.enabled_buttons = enabled_buttons;
self
}

#[inline]
pub fn resizable(mut self, resizable: bool) -> Self {
self.resizable = Some(resizable);
self.resizable = resizable;
self
}

#[inline]
pub fn window_level(mut self, window_level: WindowLevel) -> Self {
self.window_level = Some(window_level);
self.window_level = window_level;
self
}

/// If set to true, the stylesheet for Floem's default theme will be
/// injected into your window. You may want to disable this when using a
/// completely custom theme.
#[inline]
pub fn apply_default_theme(mut self, apply_default_theme: bool) -> Self {
self.apply_default_theme = Some(apply_default_theme);
self.apply_default_theme = apply_default_theme;
self
}

Expand Down