Browse Source

eframe: ask if the window is minimized or maximized (#2672)

* eframe: ask if the window is minimized or maximized

* Improve note
pull/2701/head
Emil Ernerfeldt 2 years ago
committed by GitHub
parent
commit
660566c499
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      crates/eframe/src/epi.rs
  2. 43
      crates/eframe/src/native/epi_integration.rs
  3. 82
      examples/custom_window_frame/src/main.rs

6
crates/eframe/src/epi.rs

@ -841,6 +841,12 @@ pub struct WindowInfo {
/// Are we in fullscreen mode?
pub fullscreen: bool,
/// Are we minimized?
pub minimized: bool,
/// Are we maximized?
pub maximized: bool,
/// Window inner size in egui points (logical pixels).
pub size: egui::Vec2,

43
crates/eframe/src/native/epi_integration.rs

@ -12,6 +12,14 @@ use egui_winit::{native_pixels_per_point, EventResponse, WindowSettings};
use crate::{epi, Theme, WindowInfo};
#[derive(Default)]
pub struct WindowState {
// We cannot simply call `winit::Window::is_minimized/is_maximized`
// because that deadlocks on mac.
pub minimized: bool,
pub maximized: bool,
}
pub fn points_to_size(points: egui::Vec2) -> winit::dpi::LogicalSize<f64> {
winit::dpi::LogicalSize {
width: points.x as f64,
@ -19,7 +27,11 @@ pub fn points_to_size(points: egui::Vec2) -> winit::dpi::LogicalSize<f64> {
}
}
pub fn read_window_info(window: &winit::window::Window, pixels_per_point: f32) -> WindowInfo {
pub fn read_window_info(
window: &winit::window::Window,
pixels_per_point: f32,
window_state: &WindowState,
) -> WindowInfo {
let position = window
.outer_position()
.ok()
@ -38,9 +50,13 @@ pub fn read_window_info(window: &winit::window::Window, pixels_per_point: f32) -
.inner_size()
.to_logical::<f32>(pixels_per_point.into());
// NOTE: calling window.is_minimized() or window.is_maximized() deadlocks on Mac.
WindowInfo {
position,
fullscreen: window.fullscreen().is_some(),
minimized: window_state.minimized,
maximized: window_state.maximized,
size: egui::Vec2 {
x: size.width,
y: size.height,
@ -198,6 +214,7 @@ pub fn handle_app_output(
window: &winit::window::Window,
current_pixels_per_point: f32,
app_output: epi::backend::AppOutput,
window_state: &mut WindowState,
) {
let epi::backend::AppOutput {
close: _,
@ -257,10 +274,12 @@ pub fn handle_app_output(
if let Some(minimized) = minimized {
window.set_minimized(minimized);
window_state.minimized = minimized;
}
if let Some(maximized) = maximized {
window.set_maximized(maximized);
window_state.maximized = maximized;
}
}
@ -287,6 +306,7 @@ pub struct EpiIntegration {
/// When set, it is time to close the native window.
close: bool,
can_drag_window: bool,
window_state: WindowState,
}
impl EpiIntegration {
@ -306,12 +326,17 @@ impl EpiIntegration {
let native_pixels_per_point = window.scale_factor() as f32;
let window_state = WindowState {
minimized: window.is_minimized().unwrap_or(false),
maximized: window.is_maximized(),
};
let frame = epi::Frame {
info: epi::IntegrationInfo {
system_theme,
cpu_usage: None,
native_pixels_per_point: Some(native_pixels_per_point),
window_info: read_window_info(window, egui_ctx.pixels_per_point()),
window_info: read_window_info(window, egui_ctx.pixels_per_point(), &window_state),
},
output: epi::backend::AppOutput {
visible: Some(true),
@ -336,6 +361,7 @@ impl EpiIntegration {
pending_full_output: Default::default(),
close: false,
can_drag_window: false,
window_state,
}
}
@ -417,12 +443,16 @@ impl EpiIntegration {
) -> egui::FullOutput {
let frame_start = std::time::Instant::now();
self.frame.info.window_info = read_window_info(window, self.egui_ctx.pixels_per_point());
self.frame.info.window_info =
read_window_info(window, self.egui_ctx.pixels_per_point(), &self.window_state);
let raw_input = self.egui_winit.take_egui_input(window);
// Run user code:
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
crate::profile_scope!("App::update");
app.update(egui_ctx, &mut self.frame);
});
self.pending_full_output.append(full_output);
let full_output = std::mem::take(&mut self.pending_full_output);
@ -435,7 +465,12 @@ impl EpiIntegration {
tracing::debug!("App::on_close_event returned {}", self.close);
}
self.frame.output.visible = app_output.visible; // this is handled by post_present
handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
handle_app_output(
window,
self.egui_ctx.pixels_per_point(),
app_output,
&mut self.window_state,
);
}
let frame_time = frame_start.elapsed().as_secs_f64() as f32;

82
examples/custom_window_frame/src/main.rs

@ -22,9 +22,7 @@ fn main() -> Result<(), eframe::Error> {
}
#[derive(Default)]
struct MyApp {
maximized: bool,
}
struct MyApp {}
impl eframe::App for MyApp {
fn clear_color(&self, _visuals: &egui::Visuals) -> [f32; 4] {
@ -32,7 +30,7 @@ impl eframe::App for MyApp {
}
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
custom_window_frame(self, ctx, frame, "egui with custom frame", |ui| {
custom_window_frame(ctx, frame, "egui with custom frame", |ui| {
ui.label("This is just the contents of the window");
ui.horizontal(|ui| {
ui.label("egui theme:");
@ -43,7 +41,6 @@ impl eframe::App for MyApp {
}
fn custom_window_frame(
app: &mut MyApp,
ctx: &egui::Context,
frame: &mut eframe::Frame,
title: &str,
@ -55,6 +52,8 @@ fn custom_window_frame(
// Height of the title bar
let height = 28.0;
let button_height = 16.0;
CentralPanel::default()
.frame(Frame::none())
.show(ctx, |ui| {
@ -97,46 +96,47 @@ fn custom_window_frame(
ui.interact(title_bar_rect, Id::new("title_bar"), Sense::click());
if title_bar_response.double_clicked() {
app.maximized = !app.maximized;
frame.set_maximized(app.maximized);
frame.set_maximized(!frame.info().window_info.maximized);
} else if title_bar_response.is_pointer_button_down_on() {
frame.drag_window();
}
// Add the close button:
let close_response = ui.put(
Rect::from_min_size(rect.left_top(), Vec2::splat(height)),
Button::new(RichText::new("❌").size(height - 4.0)).frame(false),
);
if close_response.clicked() {
frame.close();
}
let minimized_response = ui.put(
Rect::from_min_size(
rect.left_top() + vec2((height - 4.0) * 1.0, 0.0),
Vec2::splat(height),
),
Button::new(RichText::new("🗕").size(height - 4.0)).frame(false),
);
if minimized_response.clicked() {
frame.set_minimized(true);
}
let maximized_response = ui.put(
Rect::from_min_size(
rect.left_top() + vec2((height - 4.0) * 2.0, 0.0),
Vec2::splat(height),
),
Button::new(
RichText::new(if app.maximized { "🗗" } else { "🗖" }).size(height - 4.0),
)
.frame(false),
);
if maximized_response.clicked() {
app.maximized = !app.maximized;
frame.set_maximized(app.maximized);
}
ui.allocate_ui_at_rect(title_bar_rect, |ui| {
ui.horizontal_centered(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.visuals_mut().button_frame = false;
let close_response = ui
.add(Button::new(RichText::new("❌").size(button_height)))
.on_hover_text("Close the window");
if close_response.clicked() {
frame.close();
}
let minimized_response = ui
.add(Button::new(RichText::new("🗕").size(button_height)))
.on_hover_text("Minimize the window");
if minimized_response.clicked() {
frame.set_minimized(true);
}
if frame.info().window_info.maximized {
let maximized_response = ui
.add(Button::new(RichText::new("🗖").size(button_height)))
.on_hover_text("Restore window");
if maximized_response.clicked() {
frame.set_maximized(false);
}
} else {
let maximized_response = ui
.add(Button::new(RichText::new("🗗").size(button_height)))
.on_hover_text("Maximize window");
if maximized_response.clicked() {
frame.set_maximized(true);
}
}
});
});
// Add the contents:
let content_rect = {

Loading…
Cancel
Save