* Closes https://github.com/emilk/egui/issues/3602
You can now zoom any egui app by pressing Cmd+Plus, Cmd+Minus or Cmd+0,
just like in a browser. This will change the current `zoom_factor`
(default 1.0) which is persisted in the egui memory, and is the same for
all viewports.
You can turn off the keyboard shortcuts with `ctx.options_mut(|o|
o.zoom_with_keyboard = false);`
`zoom_factor` can also be explicitly read/written with
`ctx.zoom_factor()` and `ctx.set_zoom_factor()`.
This redefines `pixels_per_point` as `zoom_factor *
native_pixels_per_point`, where `native_pixels_per_point` is whatever is
the native scale factor for the monitor that the current viewport is in.
This adds some complexity to the interaction with winit, since we need
to know the current `zoom_factor` in a lot of places, because all egui
IO is done in ui points. I'm pretty sure this PR fixes a bunch of subtle
bugs though that used to be in this code.
`egui::gui_zoom::zoom_with_keyboard_shortcuts` is now gone, and is no
longer needed, as this is now the default behavior.
`Context::set_pixels_per_point` is still there, but it is recommended
you use `Context::set_zoom_factor` instead.
* 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.
* Closes#1044
---
(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` and
`Cotext::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 have `N`
viewports you are poentially doing `N` 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 an
`egui::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.
* There is a [`crate::RawInput::viewport`] with information about the
current viewport.
* The repaint callback set by `Context::set_request_repaint_callback`
now points to which viewport should be repainted.
* `Context::run` now returns a list of viewports in `FullOutput` which
should result in their own independant windows
* There is a new `Context::set_immediate_viewport_renderer` for setting
up the immediate viewport integration
* If you support viewports, you need to call
`Context::set_embed_viewports(false)`, or all new viewports will be
embedded (the default behavior).
## Future work
* Make it easy to wrap child viewports in the same chrome as
`egui::Window`
* Automatically show embedded viewports using `egui::Window`
* Use the new `ViewportBuilder` in `eframe::NativeOptions`
* Automatically position new viewport windows (they currently cover each
other)
* Add a `Context` method for listing all existing viewports
Find more at https://github.com/emilk/egui/issues/3556
---
<details>
<summary>
Outdated PR description by @konkitoman
</summary>
## Inspiration
- Godot because the app always work desktop or single_window because of
embedding
- Dear ImGui viewport system
## 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:
```rust
if ctx.viewport_id() != ctx.parent_viewport_id() {
// In here you add the code for the viewport context, like
egui::CentralPanel::default().show(ctx, |ui|{
ui.label("This is in a native window!");
});
}else{
// In here you add the code for when viewport cannot be created!
// You cannot use CentralPanel in here because you will override the app CentralPanel
egui::Window::new("Virtual Viewport").show(ctx, |ui|{
ui.label("This is without a native window!\nThis is in a embedded viewport");
});
}
```
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 web
The `egui::Window` will be like Godot Window
## Changes and new
These are only public structs and functions!
<details>
<summary>
## New
</summary>
- `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`
</details>
<details>
<summary>
## Changes
</summary>
- `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`
```diff
- repaint_after
+ viewports
+ viewport_commands
```
- `egui::RawInput`
```diff
+ inner_rect
+ outer_rect
```
- `egui::Event`
```diff
+ WindowEvent
```
</details>
### 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!
#### ⚠️ This currently will make the fps/2 for every sync
viewport
### Common
#### ⚠️ Attention
You will need to do this when you render your content
```rust
ctx.create_viewport(ViewportBuilder::new("Simple Viewport"), | ctx | {
let content = |ui: &mut egui::Ui|{
ui.label("Content");
};
// This will make the content a popup if cannot create a native window
if ctx.viewport_id() != ctx.parent_viewport_id() {
egui::CentralPanel::default().show(ctx, content);
} else {
egui::Area::new("Simple Viewport").show(ctx, |ui| {
egui::Frame::popup(ui.style()).show(ui, 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` or `egui::begin` and `egui::tessellate` will need the
current viewport id!
You cannot create a `ViewportId` only `ViewportId::MAIN`
If you make a single window app you will set the viewport id to be
`egui::ViewportId::MAIN` or see the `examples/pure_glow`
If you want to have multiples window support look at `crates/eframe`
glow or wgpu implementations!
## If you want to try this
- cargo run -p viewports
## 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](78a0ae879e)
### egui popups, context_menu, tooltip
To be a native window
</details>
---------
Co-authored-by: Konkitoman <konkitoman@users.noreply.github.com>
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Co-authored-by: Pablo Sichert <mail@pablosichert.com>
* Deprecate egui_glium - looking for new maintainer
egui_glium was the first backend of egui, and it served us well for
a long time, but we have long since moved on to glow and wgpu.
Not egui_glium is holding back an update to latest winit.
Since development on glium has long since been discontinued I will
therefore deprecate egui_glium with this PR.
The code is still there in the repository for a while longer,
but is no longer compiled.
If there is any interest in maintaining egui_glium, then fork it and
make a PR to remove the last egui_glium from this repository.
I will give you publish rights on crates.io.
* update glutin 0.30.2 -> 0.30.3
* cargo update -p backtrace
Updating crates.io index
Updating addr2line v0.17.0 -> v0.19.0
Updating backtrace v0.3.66 -> v0.3.67
Updating gimli v0.26.2 -> v0.27.1
Removing miniz_oxide v0.5.4
Updating object v0.29.0 -> v0.30.3
* cargo deny: allow duplicates of windows-sys, wayland-sys, and nix
* cargo-deny whitelist tiny-skia
* egui_demo_app: remove wgpu and pollster as direct dependencies
* eframe: use same web-sys version as wgpu crate
* Make note that web_sys_unstable_apis is required by the wgpu crate
* Rename the glow web painter in eframe
* Remove trait DummyWebGLConstructor from web_glow_painter.rs
* cargo fmt
* Fix check.sh
Based on https://github.com/hasenbanck/egui_wgpu_backend
`egui-wgpu` is now an official backend for `eframe` (opt-in).
Use the `wgpu` feature flag on `eframe` and the `NativeOptions::renderer` settings to pick it.
Co-authored-by: Nils Hasenbanck <nils@hasenbanck.de>
Co-authored-by: Sven Niederberger <niederberger@embotech.com>
Co-authored-by: Sven Niederberger <73159570+s-nie@users.noreply.github.com>
* Remove integration name (it is always eframe)
* Remove egui_web crate
* Move egui_web/CHANGELOG.md into eframe/CHANGELOG.md
* Remove all mentions of egui_web
* Remove epi crate and absorb into eframe
* egui_glow: only use puffin on native
* Remove WASM doc from CI (we don't generate it anyways!)
* Remove eframe::epi and improve eframe docs
* Move all epi-related code from egui_glow into eframe
* Move epi stuff from egui-winit into eframe
* Remove mention of epi in egui
* Remove mention of epi in egui_glium
* Remove trait epi::NativeTexture
* Remove confusing mentions of epi
* Refactor egui_web: break up into smaller files
* Clean up feature flags further, and update changelogs
* Clean up check.sh
* Small cleanup of egui_web/Cargo.toml
* Fix dependencies for pure_glow example
* Fix clippy false positive
* egui_web: always use the glow painter, and remove the old WebGL code.
* Clean up the WebPainter trait
* Clarify WebGL1 warning text in color test
The glow painter became standard in egui 0.17, and I've heard no complaints! So let's simplify and go all in on glow.
Part of https://github.com/emilk/egui/issues/1198
* Switch to using glow as the default renderer both on native and the web
* Simplify code to find WebGL context for glow
* egui_web: make webgl an opt-in feature
* Stop using deprecated WEBGL_debug_renderer_info
* Move window building to egui-winit
* Move icon loading to egui-winit
* `use glow::HasContext;` -> `use glow::HasContext as _;`
* Move FileStorage into epi behind a feature flag
* De-duplicate screen_size_in_pixels and native_pixels_per_point
* Move creation of FileStorage to epi
* Handle epi app output (window size changes etc) in egui-winit
* Move app and memory persistence and autosave logic to egui-winit
* fix check.sh
* Make the epi backend opt-in for egui_glium and egui_glow
* Fix persistence
* Add integration name to epi::IntegrationInfo and the demo
* Clean up Cargo.toml files and fix making egui_glium optional
* fix typo
* Make egui_glium compile without the `epi` feature
* Make egui_glow and opt-in backend for eframe
* Add egui_glow to Cargo.toml and to CI
* Reference egui_glow where egui_glium is mentioned
* Remove path-patches from root Cargo.toml
* Add instructions on how to enable the glow backend of eframe
* Deny doc errors
* Add intentional bad intradoc link to test CI
* Add cargo doc to CI
* Fix carg doc web (add wasm32 target)
* Fix intentionally broken doc-link