mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 22:30:03 -04:00
Replace eframe::Frame commands and WindowInfo with egui (#3564)
* Part of https://github.com/emilk/egui/issues/3556 ## In short You now almost never need to use `eframe::Frame` - instead use `ui.input(|i| i.viewport())` for information about the current viewport (native window), and use `ctx.send_viewport_cmd` to modify it. ## In detail This PR removes most commands from `eframe::Frame`, and replaces them with `ViewportCommand`. So `frame.close()` becomes `ctx.send_viewport_cmd(ViewportCommand::Close)`, etc. `frame.info().window_info` is now also gone, replaced with `ui.input(|i| i.viewport())`. `frame.info().native_pixels_per_point` is replaced with `ui.input(|i| i.raw.native_pixels_per_point)`. `RawInput` now contains one `ViewportInfo` for each viewport. Screenshots are taken with `ctx.send_viewport_cmd(ViewportCommand::Screenshots)` and are returned in `egui::Event` which you can check with: ``` ust ui.input(|i| { for event in &i.raw.events { if let egui::Event::Screenshot { viewport_id, image } = event { // handle it here } } }); ``` ### Motivation You no longer need to pass around the `&eframe::Frame` everywhere. This also opens the door for other integrations to use the same API of `ViewportCommand`s.
This commit is contained in:
@@ -227,7 +227,7 @@ struct ContextImpl {
|
||||
|
||||
impl ContextImpl {
|
||||
fn begin_frame_mut(&mut self, mut new_raw_input: RawInput) {
|
||||
let ids = new_raw_input.viewport.ids;
|
||||
let ids = new_raw_input.viewport_ids;
|
||||
let viewport_id = ids.this;
|
||||
self.viewport_stack.push(ids);
|
||||
let viewport = self.viewports.entry(viewport_id).or_default();
|
||||
@@ -2555,15 +2555,16 @@ impl Context {
|
||||
/// Send a command to the current viewport.
|
||||
///
|
||||
/// This lets you affect the current viewport, e.g. resizing the window.
|
||||
pub fn send_viewport_command(&self, command: ViewportCommand) {
|
||||
self.send_viewport_command_to(self.viewport_id(), command);
|
||||
pub fn send_viewport_cmd(&self, command: ViewportCommand) {
|
||||
self.send_viewport_cmd_to(self.viewport_id(), command);
|
||||
}
|
||||
|
||||
/// Send a command to a speicfic viewport.
|
||||
///
|
||||
/// This lets you affect another viewport, e.g. resizing its window.
|
||||
pub fn send_viewport_command_to(&self, id: ViewportId, command: ViewportCommand) {
|
||||
pub fn send_viewport_cmd_to(&self, id: ViewportId, command: ViewportCommand) {
|
||||
self.write(|ctx| ctx.viewport_for(id).commands.push(command));
|
||||
self.request_repaint_of(id);
|
||||
}
|
||||
|
||||
/// This creates a new native window, if possible.
|
||||
@@ -2572,6 +2573,9 @@ impl Context {
|
||||
///
|
||||
/// You need to call this each frame when the child viewport should exist.
|
||||
///
|
||||
/// You can check if the user wants to close the viewport by checking the
|
||||
/// [`crate::ViewportInfo::close_requested`] flags found in [`crate::InputState::viewport`].
|
||||
///
|
||||
/// The given callback will be called whenever the child viewport needs repainting,
|
||||
/// e.g. on an event or when [`Self::request_repaint`] is called.
|
||||
/// This means it may be called multiple times, for instance while the
|
||||
@@ -2629,6 +2633,9 @@ impl Context {
|
||||
///
|
||||
/// You need to call this each frame when the child viewport should exist.
|
||||
///
|
||||
/// You can check if the user wants to close the viewport by checking the
|
||||
/// [`crate::ViewportInfo::close_requested`] flags found in [`crate::InputState::viewport`].
|
||||
///
|
||||
/// The given ui function will be called immediately.
|
||||
/// This may only be called on the main thread.
|
||||
/// This call will pause the current viewport and render the child viewport in its own window.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//! The input needed by egui.
|
||||
|
||||
use crate::{emath::*, ViewportIdPair};
|
||||
use epaint::ColorImage;
|
||||
|
||||
use crate::{emath::*, ViewportIdMap, ViewportIdPair};
|
||||
|
||||
/// What the integrations provides to egui at the start of each frame.
|
||||
///
|
||||
@@ -13,8 +15,11 @@ use crate::{emath::*, ViewportIdPair};
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct RawInput {
|
||||
/// Information about the viwport the input is part of.
|
||||
pub viewport: ViewportInfo,
|
||||
/// The id of the active viewport, and out parent.
|
||||
pub viewport_ids: ViewportIdPair,
|
||||
|
||||
/// Information about all egui viewports.
|
||||
pub viewports: ViewportIdMap<ViewportInfo>,
|
||||
|
||||
/// Position and size of the area that egui should use, in points.
|
||||
/// Usually you would set this to
|
||||
@@ -27,10 +32,19 @@ pub struct RawInput {
|
||||
pub screen_rect: Option<Rect>,
|
||||
|
||||
/// Also known as device pixel ratio, > 1 for high resolution screens.
|
||||
///
|
||||
/// If text looks blurry you probably forgot to set this.
|
||||
/// Set this the first frame, whenever it changes, or just on every frame.
|
||||
pub pixels_per_point: Option<f32>,
|
||||
|
||||
/// The OS native pixels-per-point.
|
||||
///
|
||||
/// This should always be set, if known.
|
||||
///
|
||||
/// On web this takes browser scaling into account,
|
||||
/// and orresponds to [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) in JavaScript.
|
||||
pub native_pixels_per_point: Option<f32>,
|
||||
|
||||
/// Maximum size of one side of the font texture.
|
||||
///
|
||||
/// Ask your graphics drivers about this. This corresponds to `GL_MAX_TEXTURE_SIZE`.
|
||||
@@ -75,9 +89,11 @@ pub struct RawInput {
|
||||
impl Default for RawInput {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
viewport: ViewportInfo::default(),
|
||||
viewport_ids: Default::default(),
|
||||
viewports: Default::default(),
|
||||
screen_rect: None,
|
||||
pixels_per_point: None,
|
||||
native_pixels_per_point: None,
|
||||
max_texture_side: None,
|
||||
time: None,
|
||||
predicted_dt: 1.0 / 60.0,
|
||||
@@ -97,9 +113,11 @@ impl RawInput {
|
||||
/// * [`Self::dropped_files`] is moved.
|
||||
pub fn take(&mut self) -> RawInput {
|
||||
RawInput {
|
||||
viewport: self.viewport.take(),
|
||||
viewport_ids: self.viewport_ids,
|
||||
viewports: self.viewports.clone(),
|
||||
screen_rect: self.screen_rect.take(),
|
||||
pixels_per_point: self.pixels_per_point.take(),
|
||||
pixels_per_point: self.pixels_per_point.take(), // take the diff
|
||||
native_pixels_per_point: self.native_pixels_per_point, // copy
|
||||
max_texture_side: self.max_texture_side.take(),
|
||||
time: self.time.take(),
|
||||
predicted_dt: self.predicted_dt,
|
||||
@@ -114,9 +132,11 @@ impl RawInput {
|
||||
/// Add on new input.
|
||||
pub fn append(&mut self, newer: Self) {
|
||||
let Self {
|
||||
viewport,
|
||||
viewport_ids,
|
||||
viewports,
|
||||
screen_rect,
|
||||
pixels_per_point,
|
||||
native_pixels_per_point,
|
||||
max_texture_side,
|
||||
time,
|
||||
predicted_dt,
|
||||
@@ -127,9 +147,11 @@ impl RawInput {
|
||||
focused,
|
||||
} = newer;
|
||||
|
||||
self.viewport = viewport;
|
||||
self.viewport_ids = viewport_ids;
|
||||
self.viewports = viewports;
|
||||
self.screen_rect = screen_rect.or(self.screen_rect);
|
||||
self.pixels_per_point = pixels_per_point.or(self.pixels_per_point);
|
||||
self.native_pixels_per_point = native_pixels_per_point.or(self.native_pixels_per_point);
|
||||
self.max_texture_side = max_texture_side.or(self.max_texture_side);
|
||||
self.time = time; // use latest time
|
||||
self.predicted_dt = predicted_dt; // use latest dt
|
||||
@@ -143,23 +165,50 @@ impl RawInput {
|
||||
|
||||
/// Information about the current viewport,
|
||||
/// given as input each frame.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
///
|
||||
/// `None` means "unknown".
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct ViewportInfo {
|
||||
/// Id of us and our parent.
|
||||
pub ids: ViewportIdPair,
|
||||
/// Parent viewport, if known.
|
||||
pub parent: Option<crate::ViewportId>,
|
||||
|
||||
/// Viewport inner position and size, only the drowable area
|
||||
/// unit = physical pixels
|
||||
pub inner_rect_px: Option<Rect>,
|
||||
|
||||
/// Viewport outer position and size, drowable area + decorations
|
||||
/// unit = physical pixels
|
||||
pub outer_rect_px: Option<Rect>,
|
||||
/// Name of the viewport, if known.
|
||||
pub title: Option<String>,
|
||||
|
||||
/// The user requested the viewport should close,
|
||||
/// e.g. by pressing the close button in the window decoration.
|
||||
pub close_requested: bool,
|
||||
|
||||
/// Number of physical pixels per ui point.
|
||||
pub pixels_per_point: f32,
|
||||
|
||||
/// Current monitor size in egui points.
|
||||
pub monitor_size: Option<Vec2>,
|
||||
|
||||
/// The inner rectangle of the native window, in monitor space and ui points scale.
|
||||
///
|
||||
/// This is the content rectangle of the viewport.
|
||||
pub inner_rect: Option<Rect>,
|
||||
|
||||
/// The outer rectangle of the native window, in monitor space and ui points scale.
|
||||
///
|
||||
/// This is the content rectangle plus decoration chrome.
|
||||
pub outer_rect: Option<Rect>,
|
||||
|
||||
/// Are we minimized?
|
||||
pub minimized: Option<bool>,
|
||||
|
||||
/// Are we maximized?
|
||||
pub maximized: Option<bool>,
|
||||
|
||||
/// Are we in fullscreen mode?
|
||||
pub fullscreen: Option<bool>,
|
||||
|
||||
/// Is the window focused and able to receive input?
|
||||
///
|
||||
/// This should be the same as [`RawInput::focused`].
|
||||
pub focused: Option<bool>,
|
||||
}
|
||||
|
||||
impl ViewportInfo {
|
||||
@@ -169,15 +218,74 @@ impl ViewportInfo {
|
||||
|
||||
pub fn ui(&self, ui: &mut crate::Ui) {
|
||||
let Self {
|
||||
ids,
|
||||
inner_rect_px,
|
||||
outer_rect_px,
|
||||
parent,
|
||||
title,
|
||||
close_requested,
|
||||
pixels_per_point,
|
||||
monitor_size,
|
||||
inner_rect,
|
||||
outer_rect,
|
||||
minimized,
|
||||
maximized,
|
||||
fullscreen,
|
||||
focused,
|
||||
} = self;
|
||||
ui.label(format!("ids: {ids:?}"));
|
||||
ui.label(format!("inner_rect_px: {inner_rect_px:?}"));
|
||||
ui.label(format!("outer_rect_px: {outer_rect_px:?}"));
|
||||
ui.label(format!("close_requested: {close_requested:?}"));
|
||||
|
||||
crate::Grid::new("viewport_info").show(ui, |ui| {
|
||||
ui.label("Parent:");
|
||||
ui.label(opt_as_str(parent));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Title:");
|
||||
ui.label(opt_as_str(title));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Close requested:");
|
||||
ui.label(close_requested.to_string());
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Pixels per point:");
|
||||
ui.label(pixels_per_point.to_string());
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Monitor size:");
|
||||
ui.label(opt_as_str(monitor_size));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Inner rect:");
|
||||
ui.label(opt_rect_as_string(inner_rect));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Outer rect:");
|
||||
ui.label(opt_rect_as_string(outer_rect));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Minimized:");
|
||||
ui.label(opt_as_str(minimized));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Maximized:");
|
||||
ui.label(opt_as_str(maximized));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Fullscreen:");
|
||||
ui.label(opt_as_str(fullscreen));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Focused:");
|
||||
ui.label(opt_as_str(focused));
|
||||
ui.end_row();
|
||||
|
||||
fn opt_rect_as_string(v: &Option<Rect>) -> String {
|
||||
v.as_ref().map_or(String::new(), |r| {
|
||||
format!("Pos: {:?}, size: {:?}", r.min, r.size())
|
||||
})
|
||||
}
|
||||
|
||||
fn opt_as_str<T: std::fmt::Debug>(v: &Option<T>) -> String {
|
||||
v.as_ref().map_or(String::new(), |v| format!("{v:?}"))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,6 +460,12 @@ pub enum Event {
|
||||
/// An assistive technology (e.g. screen reader) requested an action.
|
||||
#[cfg(feature = "accesskit")]
|
||||
AccessKitActionRequest(accesskit::ActionRequest),
|
||||
|
||||
/// The reply of a screenshot requested with [`crate::ViewportCommand::Screenshot`].
|
||||
Screenshot {
|
||||
viewport_id: crate::ViewportId,
|
||||
image: std::sync::Arc<ColorImage>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Mouse button (or similar for touch input)
|
||||
@@ -980,8 +1094,11 @@ fn format_kb_shortcut() {
|
||||
impl RawInput {
|
||||
pub fn ui(&self, ui: &mut crate::Ui) {
|
||||
let Self {
|
||||
viewport_ids,
|
||||
viewports,
|
||||
screen_rect,
|
||||
pixels_per_point,
|
||||
native_pixels_per_point,
|
||||
max_texture_side,
|
||||
time,
|
||||
predicted_dt,
|
||||
@@ -990,15 +1107,31 @@ impl RawInput {
|
||||
hovered_files,
|
||||
dropped_files,
|
||||
focused,
|
||||
viewport,
|
||||
} = self;
|
||||
|
||||
viewport.ui(ui);
|
||||
ui.label(format!(
|
||||
"Active viwport: {:?}, parent: {:?}",
|
||||
viewport_ids.this, viewport_ids.parent,
|
||||
));
|
||||
for (id, viewport) in viewports {
|
||||
ui.group(|ui| {
|
||||
ui.label(format!("Viewport {id:?}"));
|
||||
ui.push_id(id, |ui| {
|
||||
viewport.ui(ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
ui.label(format!("screen_rect: {screen_rect:?} points"));
|
||||
ui.label(format!("pixels_per_point: {pixels_per_point:?}"))
|
||||
.on_hover_text(
|
||||
"Also called HDPI factor.\nNumber of physical pixels per each logical pixel.",
|
||||
);
|
||||
ui.label(format!(
|
||||
"native_pixels_per_point: {native_pixels_per_point:?}"
|
||||
))
|
||||
.on_hover_text(
|
||||
"Also called HDPI factor.\nNumber of physical pixels per each logical pixel.",
|
||||
);
|
||||
ui.label(format!("max_texture_side: {max_texture_side:?}"));
|
||||
if let Some(time) = time {
|
||||
ui.label(format!("time: {time:.3} s"));
|
||||
|
||||
@@ -210,6 +210,7 @@ impl OpenUrl {
|
||||
///
|
||||
/// [user_attention_type]: https://docs.rs/winit/latest/winit/window/enum.UserAttentionType.html
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub enum UserAttentionType {
|
||||
/// Request an elevated amount of animations and flair for the window and the task bar or dock icon.
|
||||
Critical,
|
||||
|
||||
@@ -15,19 +15,15 @@ pub mod kb_shortcuts {
|
||||
/// Let the user scale the GUI (change `Context::pixels_per_point`) by pressing
|
||||
/// Cmd+Plus, Cmd+Minus or Cmd+0, just like in a browser.
|
||||
///
|
||||
/// When using [`eframe`](https://github.com/emilk/egui/tree/master/crates/eframe), you want to call this as:
|
||||
/// ```ignore
|
||||
/// // On web, the browser controls the gui zoom.
|
||||
/// if !frame.is_web() {
|
||||
/// egui::gui_zoom::zoom_with_keyboard_shortcuts(
|
||||
/// ctx,
|
||||
/// frame.info().native_pixels_per_point,
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
pub fn zoom_with_keyboard_shortcuts(ctx: &Context, native_pixels_per_point: Option<f32>) {
|
||||
/// # let ctx = &egui::Context::default();
|
||||
/// // On web, the browser controls the gui zoom.
|
||||
/// #[cfg(not(target_arch = "wasm32"))]
|
||||
/// egui::gui_zoom::zoom_with_keyboard_shortcuts(ctx);
|
||||
/// ```
|
||||
pub fn zoom_with_keyboard_shortcuts(ctx: &Context) {
|
||||
if ctx.input_mut(|i| i.consume_shortcut(&kb_shortcuts::ZOOM_RESET)) {
|
||||
if let Some(native_pixels_per_point) = native_pixels_per_point {
|
||||
if let Some(native_pixels_per_point) = ctx.input(|i| i.raw.native_pixels_per_point) {
|
||||
ctx.set_pixels_per_point(native_pixels_per_point);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -231,6 +231,11 @@ impl InputState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Info about the active viewport
|
||||
pub fn viewport(&self) -> &ViewportInfo {
|
||||
self.raw.viewports.get(&self.raw.viewport_ids.this).expect("Failed to find current viewport in egui RawInput. This is the fault of the egui backend")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn screen_rect(&self) -> Rect {
|
||||
self.screen_rect
|
||||
|
||||
@@ -559,7 +559,7 @@ impl Memory {
|
||||
self.window_interactions
|
||||
.retain(|id, _| viewports.contains(id));
|
||||
|
||||
self.viewport_id = new_input.viewport.ids.this;
|
||||
self.viewport_id = new_input.viewport_ids.this;
|
||||
self.interactions
|
||||
.entry(self.viewport_id)
|
||||
.or_default()
|
||||
|
||||
@@ -38,12 +38,26 @@
|
||||
//!
|
||||
//! ## Using the viewports
|
||||
//! Only one viewport is active at any one time, identified with [`Context::viewport_id`].
|
||||
//! You can send commands to other viewports using [`Context::send_viewport_command_to`].
|
||||
//! You can modify the current (change the title, resize the window, etc) by sending
|
||||
//! a [`ViewportCommand`] to it using [`Context::send_viewport_cmd`].
|
||||
//! You can interact with other viewports using [`Context::send_viewport_cmd_to`].
|
||||
//!
|
||||
//! There is an example in <https://github.com/emilk/egui/tree/master/examples/multiple_viewports/src/main.rs>.
|
||||
//!
|
||||
//! You can find all available viewports in [`crate::RawInput::viewports`] and the active viewport in
|
||||
//! [`crate::InputState::viewport`]:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # let ctx = &egui::Context::default();
|
||||
//! ctx.input(|i| {
|
||||
//! dbg!(&i.viewport()); // Current viewport
|
||||
//! dbg!(&i.raw.viewports); // All viewports
|
||||
//! });
|
||||
//! ```
|
||||
//!
|
||||
//! ## For integrations
|
||||
//! * There is a [`crate::RawInput::viewport`] with information about the current viewport.
|
||||
//! * There is a [`crate::InputState::viewport`] with information about the current viewport.
|
||||
//! * There is a [`crate::RawInput::viewports`] with information about all viewports.
|
||||
//! * The repaint callback set by [`Context::set_request_repaint_callback`] points to which viewport should be repainted.
|
||||
//! * [`crate::FullOutput::viewport_output`] is a list of viewports which should result in their own independent windows.
|
||||
//! * To support immediate viewports you need to call [`Context::set_immediate_viewport_renderer`].
|
||||
@@ -636,13 +650,6 @@ pub enum CursorGrab {
|
||||
Locked,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub enum UserAttentionType {
|
||||
Informational,
|
||||
Critical,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub enum ResizeDirection {
|
||||
@@ -655,7 +662,7 @@ pub enum ResizeDirection {
|
||||
SouthWest,
|
||||
}
|
||||
|
||||
/// You can send a [`ViewportCommand`] to the viewport with [`Context::send_viewport_command`].
|
||||
/// You can send a [`ViewportCommand`] to the viewport with [`Context::send_viewport_cmd`].
|
||||
///
|
||||
/// All coordinates are in logical points.
|
||||
///
|
||||
@@ -663,7 +670,13 @@ pub enum ResizeDirection {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub enum ViewportCommand {
|
||||
/// Set the title
|
||||
/// Request this viewport to be closed.
|
||||
///
|
||||
/// For the root viewport, this usually results in the application shutting down.
|
||||
/// For other viewports, the [`crate::ViewportInfo::close_requested`] flag will be set.
|
||||
Close,
|
||||
|
||||
/// Set the window title.
|
||||
Title(String),
|
||||
|
||||
/// Turn the window transparent or not.
|
||||
@@ -709,21 +722,45 @@ pub enum ViewportCommand {
|
||||
maximize: bool,
|
||||
},
|
||||
Minimized(bool),
|
||||
|
||||
/// Maximize or unmaximize window.
|
||||
Maximized(bool),
|
||||
|
||||
/// Turn borderless fullscreen on/off.
|
||||
Fullscreen(bool),
|
||||
|
||||
/// Show window decorations, i.e. the chrome around the content
|
||||
/// with the title bar, close buttons, resize handles, etc.
|
||||
Decorations(bool),
|
||||
|
||||
/// Set window to be always-on-top, always-on-bottom, or neither.
|
||||
WindowLevel(WindowLevel),
|
||||
|
||||
/// The the window icon.
|
||||
WindowIcon(Option<Arc<ColorImage>>),
|
||||
|
||||
IMEPosition(Pos2),
|
||||
IMEAllowed(bool),
|
||||
IMEPurpose(IMEPurpose),
|
||||
|
||||
RequestUserAttention(Option<UserAttentionType>),
|
||||
/// Bring the window into focus (native only).
|
||||
///
|
||||
/// This command puts the window on top of other applications and takes input focus away from them,
|
||||
/// which, if unexpected, will disturb the user.
|
||||
///
|
||||
/// Has no effect on Wayland, or if the window is minimized or invisible.
|
||||
Focus,
|
||||
|
||||
/// If the window is unfocused, attract the user's attention (native only).
|
||||
///
|
||||
/// Typically, this means that the window will flash on the taskbar, or bounce, until it is interacted with.
|
||||
///
|
||||
/// When the window comes into focus, or if `None` is passed, the attention request will be automatically reset.
|
||||
///
|
||||
/// See [winit's documentation][user_attention_details] for platform-specific effect details.
|
||||
///
|
||||
/// [user_attention_details]: https://docs.rs/winit/latest/winit/window/enum.UserAttentionType.html
|
||||
RequestUserAttention(crate::UserAttentionType),
|
||||
|
||||
SetTheme(SystemTheme),
|
||||
|
||||
@@ -737,6 +774,29 @@ pub enum ViewportCommand {
|
||||
CursorVisible(bool),
|
||||
|
||||
CursorHitTest(bool),
|
||||
|
||||
/// Take a screenshot.
|
||||
///
|
||||
/// The results are returned in `crate::Event::Screenshot`.
|
||||
Screenshot,
|
||||
}
|
||||
|
||||
impl ViewportCommand {
|
||||
/// Construct a command to center the viewport on the monitor, if possible.
|
||||
pub fn center_on_screen(ctx: &crate::Context) -> Option<Self> {
|
||||
ctx.input(|i| {
|
||||
let outer_rect = i.viewport().outer_rect?;
|
||||
let size = outer_rect.size();
|
||||
let monitor_size = i.viewport().monitor_size?;
|
||||
if 1.0 < monitor_size.x && 1.0 < monitor_size.y {
|
||||
let x = (monitor_size.x - size.x) / 2.0;
|
||||
let y = (monitor_size.y - size.y) / 2.0;
|
||||
Some(Self::OuterPosition([x, y].into()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a viewport, i.e. a native window.
|
||||
|
||||
Reference in New Issue
Block a user