1
0
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:
Konkitoman
2023-07-18 15:29:56 +03:00
parent 7cbe26a1a1
commit c91de8a871
9 changed files with 382 additions and 144 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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>() {}

View File

@@ -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);
}
}