-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Multiple viewports/windows #3172
Conversation
Whoa, this looks very promising - thanks for working on this ❤️ I tried running My biggest feedback so far is to add docstrings to the code. I'm trying to follow along in Second piece of feedback: wrap the naked Lastly: run |
Thank you for more motivation and feedback! ❤️
Today i will add |
This is the end of the day for me! I updated the viewports example and i added some documentation! Tomorrow i will make every Popup to use a |
This is the end of the day for me! I made I changed ViewportBuilder, everything in it to be optional. this will allow to create a viewport and run stuff in it without changing the window attributes, this will be used for And move code from eframe to egui-winit to be more generic. |
All coordinates in egui, including How do you plan on handling the coordinate system of multiple windows? |
If I want to try this out, is there any sort of feedback you'd be looking for in particular? Or should I simply tell you if I notice anything odd. |
@stefnotch |
Is it intentional that the windows apparently don't update unless they're being resized? I tried out the viewport demo, and this is what I got. I cannot press any of the buttons. Code_2023-08-23-0321.webmOperating system: Windows 10 |
That is not normal! |
@konkitoman Lovely, that does fix the issue.
Operating system: Windows 10 Steps to reproduce: firefox_2023-08-23-0324.webm |
But you can resize the The spamming of
You are sure that is a bugged state or is crashing, look in the console, but that thing is not happening to me! |
This is how is working for me! OS: Arch Linux video.mp4The video is on speed up some times to 130% or 200%, because i was needed to be less than 10MB The starching is because of X11! When appear two viewports from nowhere, is because "Sync Viewport" and "Async Viewport" has the same state for showing the two other viewports! I unchecked every window/viewport from the main viewport at the end to show how the child viewport of the child viewport is closing! |
It might be a Windows specific bug. It only seems to happen if I repeatedly, and quickly, toggle "Force embedding". |
@stefnotch The main window is closing normally? Because in Wine resize and closing is not working! "Force embedding" is some thing that should be set at the start of the program, but should work and at runtime! |
@konkitoman I tested it on Windows 10.
|
Thanks @stefnotch
The problem with resizing is fixed in winit 0.29.1-beta
If you are referring to this is not really a bug is implemented badly, because if the window can be resize is only annoying! Now i see that when you said:
The window is getting smaller and smaller, and the bugged state is happening when the window has width=1, at the beginning the blue bar i was thinking that was a encoder artifact!
|
I wanted to see the auto merge conflict and i pressed "Ready for review" by mistake! |
…wport_outer_pos, viewport_inner_size, viewport_outer_size are stored as inner_pos, outer_pos, inner_size, outer_pos and Now every (i32, i32) is stored as egui::Pos2 Addes some documentation
I see this as finished! The only problem that i see that, for every sync viewport the fps is cut in half, because if a sync viewport needs to be redraw his parent needs to, the only fixes that i see is to set vsync to off or shadow update the parent! |
I think this is ready to be merged (finally!) I've created an issue for follow-up work in #3556 |
Amazing! I was very confused why the examples in this Repo did not compile for me, despite being on the latest release of egui/eframe. Then I noticed that this was only merged (at the time of surprise) 4h ago! In case other people stumble here, you need to switch your eframe = { git = "https://github.com/emilk/egui/", rev = "83aa3109d31eb7ab09c40530ef4b7d5f3e370fd4" , features = ["persistence"]}
# other egui crates can be used like this too:
egui_plot = { git = "https://github.com/emilk/egui/", rev = "83aa3109d31eb7ab09c40530ef4b7d5f3e370fd4"} (or any commit after this one, so that the multiple windows code is included) |
Added by @konkitoman in #3172 I'm not sure what the hack is supposed to solve, but calling it every frame is a bad idea, as @ItsEthra reported in #3628 (comment) * Closes #3620 * Closes #3628
This was caused by a hack added by @konkitoman in #3172 The solution was reported by @ItsEthra in #3628 (comment) * Closes #3620 * Closes #3628
Addition for <#3847> In previous one i only fixed crash occurring with Wgpu backend. This fixes crash with Glow backend as well. I only tested this change with android so most things i changed are behind ```#[cfg(target_os = "android")]```. Both fixes are dirty thought. As <#3172> says that "The root viewport is the original viewport, and cannot be closed without closing the application.". So they break rules i guess? But i can't think about better solution for now. Closes <#3861>.
(new PR description written by @emilk)
Overview
This PR introduces the concept of
Viewports
, which on the native eframe backend corresponds to native OS windows.You can spawn a new viewport using
Context::show_viewport
andCotext::show_viewport_immediate
.These needs to be called every frame the viewport should be visible.
This is implemented by the native
eframe
backend, but not the web one.Viewport classes
The viewports form a tree of parent-child relationships.
There are different classes of viewports.
Root vieport
The root viewport is the original viewport, and cannot be closed without closing the application.
Deferred viewports
These are created with
Context::show_viewport
.Deferred viewports take a closure that is called by the integration at a later time, perhaps multiple times.
Deferred viewports are repainted independenantly of the parent viewport.
This means communication with them need to done via channels, or
Arc/Mutex
.This is the most performant type of child viewport, though a bit more cumbersome to work with compared to immediate viewports.
Immediate viewports
These are created with
Context::show_viewport_immediate
.Immediate viewports take a
FnOnce
closure, similar to other egui functions, and is called immediately. This makes communication with them much simpler than with deferred viewports, but this simplicity comes at a cost: whenever tha parent viewports needs to be repainted, so will the child viewport, and vice versa. This means that if you haveN
viewports you are poentially doingN
times as much CPU work. However, if all your viewports are showing animations, and thus are repainting constantly anyway, this doesn't matter.In short: immediate viewports are simpler to use, but can waste a lot of CPU time.
Embedded viewports
These are not real, independenant viewports, but is a fallback mode for when the integration does not support real viewports. In your callback is called with
ViewportClass::Embedded
it means you need to create anegui::Window
to wrap your ui in, which will then be embedded in the parent viewport, unable to escape it.Using the viewports
Only one viewport is active at any one time, identified wth
Context::viewport_id
.You can send commands to other viewports using
Context::send_viewport_command_to
.There is an example in https://github.com/emilk/egui/tree/master/examples/multiple_viewports/src/main.rs.
For integrations
There are several changes relevant to integrations.
crate::RawInput::viewport
] with information about the current viewport.Context::set_request_repaint_callback
now points to which viewport should be repainted.Context::run
now returns a list of viewports inFullOutput
which should result in their own independant windowsContext::set_immediate_viewport_renderer
for setting up the immediate viewport integrationContext::set_embed_viewports(false)
, or all new viewports will be embedded (the default behavior).Future work
egui::Window
egui::Window
ViewportBuilder
ineframe::NativeOptions
Context
method for listing all existing viewportsFind more at #3556
Outdated PR description by @konkitoman
Inspiration
What is a Viewport
A Viewport is a egui isolated component!
Can be used by the egui integration to create native windows!
When you create a Viewport is possible that the backend do not supports that!
So you need to check if the Viewport was created or you are in the normal egui context!
This is how you can do that:
This PR do not support for drag and drop between Viewports!
After this PR is accepted i will begin work to intregrate the Viewport system in
egui::Window
!The
egui::Window
i want to behave the same on desktop and webThe
egui::Window
will be like Godot WindowChanges and new
These are only public structs and functions!
New
egui::ViewportId
egui::ViewportBuilder
This is like winit WindowBuilder
egui::ViewportCommand
With this you can set any winit property on a viewport, when is a native window!
egui::Context::new
egui::Context::create_viewport
egui::Context::create_viewport_sync
egui::Context::viewport_id
egui::Context::parent_viewport_id
egui::Context::viewport_id_pair
egui::Context::set_render_sync_callback
egui::Context::is_desktop
egui::Context::force_embedding
egui::Context::set_force_embedding
egui::Context::viewport_command
egui::Context::send_viewport_command_to
egui::Context::input_for
egui::Context::input_mut_for
egui::Context::frame_nr_for
egui::Context::request_repaint_for
egui::Context::request_repaint_after_for
egui::Context::requested_repaint_last_frame
egui::Context::requested_repaint_last_frame_for
egui::Context::requested_repaint
egui::Context::requested_repaint_for
egui::Context::inner_rect
egui::Context::outer_rect
egui::InputState::inner_rect
egui::InputState::outer_rect
egui::WindowEvent
Changes
egui::Context::run
Now needs the viewport that we want to render!
egui::Context::begin_frame
Now needs the viewport that we want to render!
egui::Context::tessellate
Now needs the viewport that we want to render!
egui::FullOutput
egui::RawInput
egui::Event
+ WindowEvent
Async Viewport
Async means that is independent from other viewports!
Is created by
egui::Context::create_viewport
To be used you will need to wrap your state in
Arc<RwLock<T>>
Look at viewports example to understand how to use it!
Sync Viewport
Sync means that is dependent on his parent!
Is created by
egui::Context::create_viewport_sync
This will pause the parent then render itself the resumes his parent!
Common
You will need to do this when you render your content
What you need to know as egui user
If you are using eframe
You don't need to change anything!
If you have a manual implementation
Now
egui::run
oregui::begin
andegui::tessellate
will need the current viewport id!You cannot create a
ViewportId
onlyViewportId::MAIN
If you make a single window app you will set the viewport id to be
egui::ViewportId::MAIN
or see theexamples/pure_glow
If you want to have multiples window support look at
crates/eframe
glow or wgpu implementations!If you want to try this
This before was wanted to change
This will probably be in feature PR's
egui::Window
To create a native window when embedded was set to false
You can try that in viewports example before: 78a0ae8
egui popups, context_menu, tooltip
To be a native window