mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 13:20:05 -04:00
Some more work for multiples windows support
This commit is contained in:
@@ -10,7 +10,7 @@ pub mod panel;
|
||||
pub mod popup;
|
||||
pub(crate) mod resize;
|
||||
pub mod scroll_area;
|
||||
pub(crate) mod window;
|
||||
pub mod window;
|
||||
|
||||
pub use {
|
||||
area::Area,
|
||||
|
||||
@@ -6,6 +6,115 @@ use epaint::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Hash, PartialEq, Clone, Default)]
|
||||
pub struct WindowBuilder {
|
||||
pub title: String,
|
||||
pub name: Option<String>,
|
||||
pub position: Option<(i32, i32)>,
|
||||
pub inner_size: Option<(u32, u32)>,
|
||||
pub fullscreen: bool,
|
||||
pub maximized: bool,
|
||||
pub resizable: bool,
|
||||
pub transparent: bool,
|
||||
pub decorations: bool,
|
||||
pub icon: Option<(u32, u32, Vec<u8>)>,
|
||||
pub active: bool,
|
||||
pub visible: bool,
|
||||
pub title_hidden: bool,
|
||||
pub titlebar_transparent: bool,
|
||||
pub fullsize_content_view: bool,
|
||||
pub min_inner_size: Option<(u32, u32)>,
|
||||
pub max_inner_size: Option<(u32, u32)>,
|
||||
pub drag_and_drop: bool,
|
||||
}
|
||||
|
||||
impl WindowBuilder {
|
||||
pub fn with_title(mut self, title: impl Into<String>) -> Self {
|
||||
self.title = title.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_decorations(mut self, decorations: bool) -> Self {
|
||||
self.decorations = decorations;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_fullscreen(mut self, fullscreen: bool) -> Self {
|
||||
self.fullscreen = fullscreen;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_maximized(mut self, maximized: bool) -> Self {
|
||||
self.maximized = maximized;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_resizable(mut self, resizable: bool) -> Self {
|
||||
self.resizable = resizable;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_transparent(mut self, transparent: bool) -> Self {
|
||||
self.transparent = transparent;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_window_icon(mut self, icon: Option<(u32, u32, Vec<u8>)>) -> Self {
|
||||
self.icon = icon;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_active(mut self, active: bool) -> Self {
|
||||
self.active = active;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_visible(mut self, visible: bool) -> Self {
|
||||
self.visible = visible;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_title_hidden(mut self, title_hidden: bool) -> Self {
|
||||
self.title_hidden = title_hidden;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_titlebar_transparent(mut self, value: bool) -> Self {
|
||||
self.titlebar_transparent = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_fullsize_content_view(mut self, value: bool) -> Self {
|
||||
self.fullsize_content_view = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_inner_size(mut self, value: (u32, u32)) -> Self {
|
||||
self.inner_size = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_min_inner_size(mut self, value: (u32, u32)) -> Self {
|
||||
self.min_inner_size = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_max_inner_size(mut self, value: (u32, u32)) -> Self {
|
||||
self.max_inner_size = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_drag_and_drop(mut self, value: bool) -> Self {
|
||||
self.drag_and_drop = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_position(mut self, value: (i32, i32)) -> Self {
|
||||
self.position = Some(value);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for a floating window which can be dragged, closed, collapsed, resized and scrolled (off by default).
|
||||
///
|
||||
/// You can customize:
|
||||
@@ -287,6 +396,8 @@ impl<'open> Window<'open> {
|
||||
ctx: &Context,
|
||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||
) -> Option<InnerResponse<Option<R>>> {
|
||||
let window_id =
|
||||
ctx.data_mut(|data| *data.get_temp_mut_or(self.area.id.with("window_id"), 0));
|
||||
let Window {
|
||||
title,
|
||||
open,
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
input_state::*, layers::GraphicLayers, memory::Options, os::OperatingSystem,
|
||||
output::FullOutput, util::IdTypeMap, TextureHandle, *,
|
||||
};
|
||||
use ahash::HashMap;
|
||||
use epaint::{mutex::*, stats::*, text::Fonts, TessellationOptions, *};
|
||||
|
||||
/// Information given to the backend about when it is time to repaint the ui.
|
||||
@@ -21,6 +22,9 @@ pub struct RequestRepaintInfo {
|
||||
/// This can be compared to [`Context::frame_nr`] to see if we've already
|
||||
/// triggered the painting of the next frame.
|
||||
pub current_frame_nr: u64,
|
||||
|
||||
/// This is used to specify what window to redraw
|
||||
pub window_id: u64,
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -80,11 +84,11 @@ impl Default for Repaint {
|
||||
}
|
||||
|
||||
impl Repaint {
|
||||
fn request_repaint(&mut self) {
|
||||
self.request_repaint_after(std::time::Duration::ZERO);
|
||||
fn request_repaint(&mut self, window_id: u64) {
|
||||
self.request_repaint_after(std::time::Duration::ZERO, window_id);
|
||||
}
|
||||
|
||||
fn request_repaint_after(&mut self, after: std::time::Duration) {
|
||||
fn request_repaint_after(&mut self, after: std::time::Duration, window_id: u64) {
|
||||
if after == std::time::Duration::ZERO {
|
||||
// Do a few extra frames to let things settle.
|
||||
// This is a bit of a hack, and we don't support it for `repaint_after` callbacks yet.
|
||||
@@ -100,6 +104,7 @@ impl Repaint {
|
||||
let info = RequestRepaintInfo {
|
||||
after,
|
||||
current_frame_nr: self.frame_nr,
|
||||
window_id: window_id,
|
||||
};
|
||||
(callback)(info);
|
||||
}
|
||||
@@ -155,6 +160,9 @@ struct ContextImpl {
|
||||
|
||||
repaint: Repaint,
|
||||
|
||||
windows: HashMap<String, (WindowBuilder, u64, bool)>,
|
||||
current_window_id: u64,
|
||||
|
||||
/// Written to during the frame.
|
||||
layer_rects_this_frame: ahash::HashMap<LayerId, Vec<(Id, Rect)>>,
|
||||
|
||||
@@ -956,7 +964,7 @@ impl Context {
|
||||
/// (this will work on `eframe`).
|
||||
pub fn request_repaint(&self) {
|
||||
// request two frames of repaint, just to cover some corner cases (frame delays):
|
||||
self.write(|ctx| ctx.repaint.request_repaint());
|
||||
self.write(|ctx| ctx.repaint.request_repaint(ctx.current_window_id));
|
||||
}
|
||||
|
||||
/// Request repaint after at most the specified duration elapses.
|
||||
@@ -988,9 +996,9 @@ impl Context {
|
||||
/// timeout takes 500 milliseconds AFTER the vsync swap buffer.
|
||||
/// So, its not that we are requesting repaint within X duration. We are rather timing out
|
||||
/// during app idle time where we are not receiving any new input events.
|
||||
pub fn request_repaint_after(&self, duration: std::time::Duration) {
|
||||
pub fn request_repaint_after(&self, duration: std::time::Duration, window_id: u64) {
|
||||
// Maybe we can check if duration is ZERO, and call self.request_repaint()?
|
||||
self.write(|ctx| ctx.repaint.request_repaint_after(duration));
|
||||
self.write(|ctx| ctx.repaint.request_repaint_after(duration, window_id));
|
||||
}
|
||||
|
||||
/// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`].
|
||||
@@ -1260,11 +1268,19 @@ impl Context {
|
||||
let repaint_after = self.write(|ctx| ctx.repaint.end_frame());
|
||||
let shapes = self.drain_paint_lists();
|
||||
|
||||
let windows = self.write(|ctx| {
|
||||
ctx.windows
|
||||
.drain()
|
||||
.map(|(_, (builder, id, _))| (id, builder))
|
||||
.collect()
|
||||
});
|
||||
|
||||
FullOutput {
|
||||
platform_output,
|
||||
repaint_after,
|
||||
textures_delta,
|
||||
shapes,
|
||||
windows,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1869,6 +1885,30 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
use containers::window::WindowBuilder;
|
||||
/// # Windows
|
||||
impl Context {
|
||||
pub fn set_current_window_id(&self, window_id: u64) {
|
||||
self.write(|ctx| ctx.current_window_id = window_id);
|
||||
}
|
||||
pub fn current_window_id(&self) -> u64 {
|
||||
self.read(|ctx| ctx.current_window_id)
|
||||
}
|
||||
|
||||
pub fn create_window(&self, window_builder: WindowBuilder) -> u64 {
|
||||
self.write(|ctx| {
|
||||
if let Some(window) = ctx.windows.get(&window_builder.title) {
|
||||
window.1
|
||||
} else {
|
||||
let id = ctx.windows.len() as u64 + 1;
|
||||
ctx.windows
|
||||
.insert(window_builder.title.clone(), (window_builder, id, true));
|
||||
id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_impl_send_sync() {
|
||||
fn assert_send_sync<T: Send + Sync>() {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! All the data egui returns to the backend at the end of each frame.
|
||||
|
||||
use crate::WidgetType;
|
||||
use crate::{window::WindowBuilder, WidgetType};
|
||||
|
||||
/// What egui emits each frame from [`crate::Context::run`].
|
||||
///
|
||||
@@ -30,6 +30,8 @@ pub struct FullOutput {
|
||||
///
|
||||
/// You can use [`crate::Context::tessellate`] to turn this into triangles.
|
||||
pub shapes: Vec<epaint::ClippedShape>,
|
||||
|
||||
pub windows: Vec<(u64, WindowBuilder)>,
|
||||
}
|
||||
|
||||
impl FullOutput {
|
||||
@@ -40,12 +42,14 @@ impl FullOutput {
|
||||
repaint_after,
|
||||
textures_delta,
|
||||
shapes,
|
||||
mut windows,
|
||||
} = newer;
|
||||
|
||||
self.platform_output.append(platform_output);
|
||||
self.repaint_after = repaint_after; // if the last frame doesn't need a repaint, then we don't need to repaint
|
||||
self.textures_delta.append(textures_delta);
|
||||
self.shapes = shapes; // Only paint the latest
|
||||
self.windows.append(&mut windows);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user