mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 05:10:03 -04:00
Merge branch 'master' of https://github.com/emilk/egui into multiples_viewports
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ecolor"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = [
|
||||
"Emil Ernerfeldt <emil.ernerfeldt@gmail.com>",
|
||||
"Andreas Reich <reichandreas@gmx.de>",
|
||||
|
||||
@@ -6,6 +6,39 @@ NOTE: [`egui-winit`](../egui-winit/CHANGELOG.md), [`egui_glium`](../egui_glium/C
|
||||
This file is updated upon each release.
|
||||
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.
|
||||
|
||||
## 0.23.0 - 2023-09-27
|
||||
* Update MSRV to Rust 1.70.0 [#3310](https://github.com/emilk/egui/pull/3310)
|
||||
* Update to puffin 0.16 [#3144](https://github.com/emilk/egui/pull/3144)
|
||||
* Update to `wgpu` 0.17.0 [#3170](https://github.com/emilk/egui/pull/3170) (thanks [@Aaron1011](https://github.com/Aaron1011)!)
|
||||
* Improved wgpu callbacks [#3253](https://github.com/emilk/egui/pull/3253) (thanks [@Wumpf](https://github.com/Wumpf)!)
|
||||
* Improve documentation of `eframe`, especially for wasm32 [#3295](https://github.com/emilk/egui/pull/3295)
|
||||
* `eframe::Frame::info` returns a reference [#3301](https://github.com/emilk/egui/pull/3301) (thanks [@Barugon](https://github.com/Barugon)!)
|
||||
* Move `App::persist_window` to `NativeOptions` and `App::max_size_points` to `WebOptions` [#3397](https://github.com/emilk/egui/pull/3397)
|
||||
|
||||
#### Desktop/Native:
|
||||
* Only show on-screen-keyboard and IME when editing text [#3362](https://github.com/emilk/egui/pull/3362) (thanks [@Barugon](https://github.com/Barugon)!)
|
||||
* Add `eframe::storage_dir` [#3286](https://github.com/emilk/egui/pull/3286)
|
||||
* Add `NativeOptions::window_builder` for more customization [#3390](https://github.com/emilk/egui/pull/3390) (thanks [@twop](https://github.com/twop)!)
|
||||
* Better restore Window position on Mac when on secondary monitor [#3239](https://github.com/emilk/egui/pull/3239)
|
||||
* Fix iOS support in `eframe` [#3241](https://github.com/emilk/egui/pull/3241) (thanks [@lucasmerlin](https://github.com/lucasmerlin)!)
|
||||
* Speed up `eframe` state storage [#3353](https://github.com/emilk/egui/pull/3353) (thanks [@sebbert](https://github.com/sebbert)!)
|
||||
* Allow users to opt-out of default `winit` features [#3228](https://github.com/emilk/egui/pull/3228)
|
||||
* Expose Raw Window and Display Handles [#3073](https://github.com/emilk/egui/pull/3073) (thanks [@bash](https://github.com/bash)!)
|
||||
* Use window title as fallback when app_id is not set [#3107](https://github.com/emilk/egui/pull/3107) (thanks [@jacekpoz](https://github.com/jacekpoz)!)
|
||||
* Sleep a bit only when minimized [#3139](https://github.com/emilk/egui/pull/3139) (thanks [@icedrocket](https://github.com/icedrocket)!)
|
||||
* Prevent text from being cleared when selected due to winit IME [#3376](https://github.com/emilk/egui/pull/3376) (thanks [@YgorSouza](https://github.com/YgorSouza)!)
|
||||
* Fix android app quit on resume with glow backend [#3080](https://github.com/emilk/egui/pull/3080) (thanks [@tkkcc](https://github.com/tkkcc)!)
|
||||
* Fix panic with persistence without window [#3167](https://github.com/emilk/egui/pull/3167) (thanks [@sagebind](https://github.com/sagebind)!)
|
||||
* Only call `run_return` twice on Windows [#3053](https://github.com/emilk/egui/pull/3053) (thanks [@pan93412](https://github.com/pan93412)!)
|
||||
* Gracefully catch error saving state to disk [#3230](https://github.com/emilk/egui/pull/3230)
|
||||
* Recognize numpad enter/plus/minus [#3285](https://github.com/emilk/egui/pull/3285)
|
||||
* Add more puffin profile scopes to `eframe` [#3330](https://github.com/emilk/egui/pull/3330) [#3332](https://github.com/emilk/egui/pull/3332)
|
||||
|
||||
#### Web:
|
||||
* Update to wasm-bindgen 0.2.87 [#3237](https://github.com/emilk/egui/pull/3237)
|
||||
* Remove `Function()` invocation from eframe text_agent to bypass "unsafe-eval" restrictions in Chrome browser extensions. [#3349](https://github.com/emilk/egui/pull/3349) (thanks [@aspect](https://github.com/aspect)!)
|
||||
* Fix docs about web [#3026](https://github.com/emilk/egui/pull/3026) (thanks [@kerryeon](https://github.com/kerryeon)!)
|
||||
|
||||
|
||||
## 0.22.0 - 2023-05-23
|
||||
* Fix: `request_repaint_after` works even when called from background thread [#2939](https://github.com/emilk/egui/pull/2939)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "eframe"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "egui framework - write GUI apps that compiles to web and/or natively"
|
||||
edition = "2021"
|
||||
@@ -39,6 +39,16 @@ default = [
|
||||
## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/).
|
||||
accesskit = ["egui/accesskit", "egui-winit/accesskit"]
|
||||
|
||||
# Allow crates to choose an android-activity backend via Winit
|
||||
# - It's important that most applications should not have to depend on android-activity directly, and can
|
||||
# rely on Winit to pull in a suitable version (unlike most Rust crates, any version conflicts won't link)
|
||||
# - It's also important that we don't impose an android-activity backend by taking this choice away from applications.
|
||||
|
||||
## Enable the `game-activity` backend via `egui-winit` on Android
|
||||
android-game-activity = ["egui-winit/android-game-activity"]
|
||||
## Enable the `native-activity` backend via `egui-winit` on Android
|
||||
android-native-activity = ["egui-winit/android-native-activity"]
|
||||
|
||||
## If set, egui will use `include_bytes!` to bundle some fonts.
|
||||
## If you plan on specifying your own fonts you may disable this feature.
|
||||
default_fonts = ["egui/default_fonts"]
|
||||
@@ -46,12 +56,6 @@ default_fonts = ["egui/default_fonts"]
|
||||
## Use [`glow`](https://github.com/grovesNL/glow) for painting, via [`egui_glow`](https://github.com/emilk/egui/tree/master/crates/egui_glow).
|
||||
glow = ["dep:glow", "dep:egui_glow", "dep:glutin", "dep:glutin-winit"]
|
||||
|
||||
## Enables wayland support and fixes clipboard issue.
|
||||
wayland = ["egui-winit/wayland"]
|
||||
|
||||
## Enables compiling for x11.
|
||||
x11 = ["egui-winit/x11"]
|
||||
|
||||
## Enable saving app state to disk.
|
||||
persistence = [
|
||||
"directories-next",
|
||||
@@ -63,35 +67,32 @@ persistence = [
|
||||
|
||||
## Enable profiling with the [`puffin`](https://docs.rs/puffin) crate.
|
||||
##
|
||||
## Only enabled on native, because of the low resolution (1ms) of clocks in browsers.
|
||||
## `eframe` will call `puffin::GlobalProfiler::lock().new_frame()` for you
|
||||
##
|
||||
## Only enabled on native, because of the low resolution (1ms) of clocks in browsers.
|
||||
puffin = ["dep:puffin", "egui/puffin", "egui_glow?/puffin", "egui-wgpu?/puffin"]
|
||||
|
||||
## Enables wayland support and fixes clipboard issue.
|
||||
wayland = ["egui-winit/wayland"]
|
||||
|
||||
## Enable screen reader support (requires `ctx.options_mut(|o| o.screen_reader = true);`) on web.
|
||||
##
|
||||
## For other platforms, use the "accesskit" feature instead.
|
||||
## For other platforms, use the `accesskit` feature instead.
|
||||
web_screen_reader = ["tts"]
|
||||
|
||||
## If set, eframe will look for the env-var `EFRAME_SCREENSHOT_TO` and write a screenshot to that location, and then quit.
|
||||
## This is used to generate images for the examples.
|
||||
__screenshot = []
|
||||
|
||||
## Use [`wgpu`](https://docs.rs/wgpu) for painting (via [`egui-wgpu`](https://github.com/emilk/egui/tree/master/crates/egui-wgpu)).
|
||||
## This overrides the `glow` feature.
|
||||
wgpu = ["dep:wgpu", "dep:egui-wgpu", "dep:pollster", "dep:raw-window-handle"]
|
||||
|
||||
# Allow crates to choose an android-activity backend via Winit
|
||||
# - It's important that most applications should not have to depend on android-activity directly, and can
|
||||
# rely on Winit to pull in a suitable version (unlike most Rust crates, any version conflicts won't link)
|
||||
# - It's also important that we don't impose an android-activity backend by taking this choice away from applications.
|
||||
## Enables compiling for x11.
|
||||
x11 = ["egui-winit/x11"]
|
||||
|
||||
## Enable the `native-activity` backend via `egui-winit` on Android
|
||||
android-native-activity = ["egui-winit/android-native-activity"]
|
||||
## Enable the `game-activity` backend via `egui-winit` on Android
|
||||
android-game-activity = ["egui-winit/android-game-activity"]
|
||||
## If set, eframe will look for the env-var `EFRAME_SCREENSHOT_TO` and write a screenshot to that location, and then quit.
|
||||
## This is used to generate images for examples.
|
||||
__screenshot = []
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false, features = [
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false, features = [
|
||||
"bytemuck",
|
||||
"log",
|
||||
] }
|
||||
@@ -104,7 +105,7 @@ thiserror.workspace = true
|
||||
## Enable this when generating docs.
|
||||
document-features = { version = "0.2", optional = true }
|
||||
|
||||
egui_glow = { version = "0.22.0", path = "../egui_glow", optional = true, default-features = false }
|
||||
egui_glow = { version = "0.23.0", path = "../egui_glow", optional = true, default-features = false }
|
||||
glow = { version = "0.12", optional = true }
|
||||
ron = { version = "0.8", optional = true, features = ["integer128"] }
|
||||
serde = { version = "1", optional = true, features = ["derive"] }
|
||||
@@ -112,7 +113,7 @@ serde = { version = "1", optional = true, features = ["derive"] }
|
||||
# -------------------------------------------
|
||||
# native:
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
egui-winit = { version = "0.22.0", path = "../egui-winit", default-features = false, features = [
|
||||
egui-winit = { version = "0.23.0", path = "../egui-winit", default-features = false, features = [
|
||||
"clipboard",
|
||||
"links",
|
||||
] }
|
||||
@@ -124,7 +125,7 @@ winit = { version = "0.28.1", default-features = false }
|
||||
|
||||
# optional native:
|
||||
directories-next = { version = "2", optional = true }
|
||||
egui-wgpu = { version = "0.22.0", path = "../egui-wgpu", optional = true, features = [
|
||||
egui-wgpu = { version = "0.23.0", path = "../egui-wgpu", optional = true, features = [
|
||||
"winit",
|
||||
] } # if wgpu is used, use it with winit
|
||||
pollster = { version = "0.3", optional = true } # needed for wgpu
|
||||
@@ -138,7 +139,7 @@ wgpu = { workspace = true, optional = true }
|
||||
|
||||
# mac:
|
||||
[target.'cfg(any(target_os = "macos"))'.dependencies]
|
||||
cocoa = "0.24.1"
|
||||
cocoa = "0.24.1" # Stuck on old version until we update to winit 0.29
|
||||
objc = "0.2.7"
|
||||
|
||||
# windows:
|
||||
@@ -198,7 +199,7 @@ web-sys = { version = "0.3.58", features = [
|
||||
] }
|
||||
|
||||
# optional web:
|
||||
egui-wgpu = { version = "0.22.0", path = "../egui-wgpu", optional = true } # if wgpu is used, use it without (!) winit
|
||||
egui-wgpu = { version = "0.23.0", path = "../egui-wgpu", optional = true } # if wgpu is used, use it without (!) winit
|
||||
raw-window-handle = { version = "0.5.2", optional = true }
|
||||
tts = { version = "0.25", optional = true, default-features = false }
|
||||
wgpu = { workspace = true, optional = true }
|
||||
|
||||
@@ -28,6 +28,7 @@ You need to either use `edition = "2021"`, or set `resolver = "2"` in the `[work
|
||||
|
||||
You can opt-in to the using [`egui_wgpu`](https://github.com/emilk/egui/tree/master/crates/egui_wgpu) for rendering by enabling the `wgpu` feature and setting `NativeOptions::renderer` to `Renderer::Wgpu`.
|
||||
|
||||
To get copy-paste working on web, you need to compile with `export RUSTFLAGS=--cfg=web_sys_unstable_apis`.
|
||||
|
||||
## Alternatives
|
||||
`eframe` is not the only way to write an app using `egui`! You can also try [`egui-miniquad`](https://github.com/not-fl3/egui-miniquad), [`bevy_egui`](https://github.com/mvlabat/bevy_egui), [`egui_sdl2_gl`](https://github.com/ArjunNair/egui_sdl2_gl), and others.
|
||||
|
||||
@@ -14,6 +14,15 @@ pub struct IconData {
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for IconData {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("IconData")
|
||||
.field("width", &self.width)
|
||||
.field("height", &self.height)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl IconData {
|
||||
/// Convert into [`image::RgbaImage`]
|
||||
///
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod icon_data;
|
||||
|
||||
use egui::ViewportBuilder;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use icon_data::IconData;
|
||||
|
||||
@@ -28,7 +29,7 @@ use static_assertions::assert_not_impl_any;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
pub use winit::event_loop::EventLoopBuilder;
|
||||
pub use winit::{event_loop::EventLoopBuilder, window::WindowBuilder};
|
||||
|
||||
/// Hook into the building of an event loop before it is run
|
||||
///
|
||||
@@ -38,6 +39,14 @@ pub use winit::event_loop::EventLoopBuilder;
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
pub type EventLoopBuilderHook = Box<dyn FnOnce(&mut EventLoopBuilder<UserEvent>)>;
|
||||
|
||||
/// Hook into the building of a the native window.
|
||||
///
|
||||
/// You can configure any platform specific details required on top of the default configuration
|
||||
/// done by `eframe`.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
pub type WindowBuilderHook = Box<dyn FnOnce(ViewportBuilder) -> ViewportBuilder>;
|
||||
|
||||
/// This is how your app is created.
|
||||
///
|
||||
/// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc.
|
||||
@@ -182,13 +191,6 @@ pub trait App {
|
||||
std::time::Duration::from_secs(30)
|
||||
}
|
||||
|
||||
/// The size limit of the web app canvas.
|
||||
///
|
||||
/// By default the max size is [`egui::Vec2::INFINITY`], i.e. unlimited.
|
||||
fn max_size_points(&self) -> egui::Vec2 {
|
||||
egui::Vec2::INFINITY
|
||||
}
|
||||
|
||||
/// Background color values for the app, e.g. what is sent to `gl.clearColor`.
|
||||
///
|
||||
/// This is the background of your windows if you don't set a central panel.
|
||||
@@ -208,12 +210,6 @@ pub trait App {
|
||||
// _visuals.window_fill() would also be a natural choice
|
||||
}
|
||||
|
||||
/// Controls whether or not the native window position and size will be
|
||||
/// persisted (only if the "persistence" feature is enabled).
|
||||
fn persist_native_window(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Controls whether or not the egui memory (window positions etc) will be
|
||||
/// persisted (only if the "persistence" feature is enabled).
|
||||
fn persist_egui_memory(&self) -> bool {
|
||||
@@ -313,6 +309,7 @@ pub struct NativeOptions {
|
||||
pub resizable: bool,
|
||||
|
||||
/// On desktop: make the window transparent.
|
||||
///
|
||||
/// You control the transparency with [`App::clear_color()`].
|
||||
/// You should avoid having a [`egui::CentralPanel`], or make sure its frame is also transparent.
|
||||
pub transparent: bool,
|
||||
@@ -397,6 +394,15 @@ pub struct NativeOptions {
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
pub event_loop_builder: Option<EventLoopBuilderHook>,
|
||||
|
||||
/// Hook into the building of a window.
|
||||
///
|
||||
/// Specify a callback here in case you need to make platform specific changes to the
|
||||
/// window appearance.
|
||||
///
|
||||
/// Note: A [`NativeOptions`] clone will not include any `window_builder` hook.
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
pub window_builder: Option<WindowBuilderHook>,
|
||||
|
||||
#[cfg(feature = "glow")]
|
||||
/// Needed for cross compiling for VirtualBox VMSVGA driver with OpenGL ES 2.0 and OpenGL 2.1 which doesn't support SRGB texture.
|
||||
/// See <https://github.com/emilk/egui/pull/1993>.
|
||||
@@ -455,6 +461,10 @@ pub struct NativeOptions {
|
||||
/// }
|
||||
/// ```
|
||||
pub app_id: Option<String>,
|
||||
|
||||
/// Controls whether or not the native window position and size will be
|
||||
/// persisted (only if the "persistence" feature is enabled).
|
||||
pub persist_window: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -466,6 +476,9 @@ impl Clone for NativeOptions {
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
event_loop_builder: None, // Skip any builder callbacks if cloning
|
||||
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
window_builder: None, // Skip any builder callbacks if cloning
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
wgpu_options: self.wgpu_options.clone(),
|
||||
|
||||
@@ -520,6 +533,9 @@ impl Default for NativeOptions {
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
event_loop_builder: None,
|
||||
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
window_builder: None,
|
||||
|
||||
#[cfg(feature = "glow")]
|
||||
shader_version: None,
|
||||
|
||||
@@ -529,6 +545,8 @@ impl Default for NativeOptions {
|
||||
wgpu_options: egui_wgpu::WgpuConfiguration::default(),
|
||||
|
||||
app_id: None,
|
||||
|
||||
persist_window: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -566,6 +584,11 @@ pub struct WebOptions {
|
||||
/// Configures wgpu instance/device/adapter/surface creation and renderloop.
|
||||
#[cfg(feature = "wgpu")]
|
||||
pub wgpu_options: egui_wgpu::WgpuConfiguration,
|
||||
|
||||
/// The size limit of the web app canvas.
|
||||
///
|
||||
/// By default the max size is [`egui::Vec2::INFINITY`], i.e. unlimited.
|
||||
pub max_size_points: egui::Vec2,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@@ -581,6 +604,8 @@ impl Default for WebOptions {
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
wgpu_options: egui_wgpu::WgpuConfiguration::default(),
|
||||
|
||||
max_size_points: egui::Vec2::INFINITY,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1164,7 +1189,8 @@ pub fn get_value<T: serde::de::DeserializeOwned>(storage: &dyn Storage, key: &st
|
||||
.and_then(|value| match ron::from_str(&value) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
log::warn!("Failed to decode RON: {err}");
|
||||
// This happens on when we break the format, e.g. when updating egui.
|
||||
log::debug!("Failed to decode RON: {err}");
|
||||
None
|
||||
}
|
||||
})
|
||||
|
||||
@@ -280,7 +280,7 @@ pub fn run_simple_native(
|
||||
update_fun: U,
|
||||
}
|
||||
|
||||
impl<U: FnMut(&egui::Context, &mut Frame)> App for SimpleApp<U> {
|
||||
impl<U: FnMut(&egui::Context, &mut Frame) + 'static> App for SimpleApp<U> {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame) {
|
||||
(self.update_fun)(ctx, frame);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ pub fn read_window_info(
|
||||
pub fn window_builder<E>(
|
||||
event_loop: &EventLoopWindowTarget<E>,
|
||||
title: &str,
|
||||
native_options: &epi::NativeOptions,
|
||||
native_options: &mut epi::NativeOptions,
|
||||
window_settings: Option<WindowSettings>,
|
||||
) -> ViewportBuilder {
|
||||
let epi::NativeOptions {
|
||||
@@ -173,7 +173,10 @@ pub fn window_builder<E>(
|
||||
}
|
||||
}
|
||||
|
||||
window_builder
|
||||
match std::mem::take(&mut native_options.window_builder) {
|
||||
Some(hook) => hook(window_builder),
|
||||
None => window_builder,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_native_options_to_window(
|
||||
@@ -326,6 +329,8 @@ pub struct EpiIntegration {
|
||||
can_drag_window: bool,
|
||||
window_state: WindowState,
|
||||
follow_system_theme: bool,
|
||||
#[cfg(feature = "persistence")]
|
||||
persist_window: bool,
|
||||
app_icon_setter: super::app_icon::AppTitleIconSetter,
|
||||
}
|
||||
|
||||
@@ -388,6 +393,8 @@ impl EpiIntegration {
|
||||
can_drag_window: false,
|
||||
window_state,
|
||||
follow_system_theme: native_options.follow_system_theme,
|
||||
#[cfg(feature = "persistence")]
|
||||
persist_window: native_options.persist_window,
|
||||
app_icon_setter,
|
||||
beginning: Instant::now(),
|
||||
}
|
||||
@@ -578,7 +585,7 @@ impl EpiIntegration {
|
||||
crate::profile_function!();
|
||||
|
||||
if let Some(window) = _window {
|
||||
if _app.persist_native_window() {
|
||||
if self.persist_window {
|
||||
crate::profile_scope!("native_window");
|
||||
epi::set_value(
|
||||
storage,
|
||||
|
||||
@@ -130,6 +130,7 @@ fn save_to_disk(file_path: &PathBuf, kv: &HashMap<String, String>) {
|
||||
let mut writer = std::io::BufWriter::new(file);
|
||||
let config = Default::default();
|
||||
|
||||
crate::profile_scope!("ron::serialize");
|
||||
if let Err(err) = ron::ser::to_writer_pretty(&mut writer, &kv, config)
|
||||
.and_then(|_| writer.flush().map_err(|err| err.into()))
|
||||
{
|
||||
|
||||
@@ -895,7 +895,7 @@ mod glow_integration {
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
storage: Option<&dyn epi::Storage>,
|
||||
title: &str,
|
||||
native_options: &NativeOptions,
|
||||
native_options: &mut NativeOptions,
|
||||
) -> Result<(GlutinWindowContext, glow::Context)> {
|
||||
crate::profile_function!();
|
||||
|
||||
@@ -945,7 +945,7 @@ mod glow_integration {
|
||||
event_loop,
|
||||
storage.as_deref(),
|
||||
&self.app_name,
|
||||
&self.native_options,
|
||||
&mut self.native_options,
|
||||
)?;
|
||||
let gl = Arc::new(gl);
|
||||
|
||||
@@ -1944,7 +1944,7 @@ mod wgpu_integration {
|
||||
event_loop: &EventLoopWindowTarget<UserEvent>,
|
||||
storage: Option<&dyn epi::Storage>,
|
||||
title: &str,
|
||||
native_options: &NativeOptions,
|
||||
native_options: &mut NativeOptions,
|
||||
) -> std::result::Result<(winit::window::Window, ViewportBuilder), winit::error::OsError>
|
||||
{
|
||||
crate::profile_function!();
|
||||
@@ -2556,7 +2556,7 @@ mod wgpu_integration {
|
||||
event_loop,
|
||||
running.integration.read().frame.storage(),
|
||||
&self.app_name,
|
||||
&self.native_options,
|
||||
&mut self.native_options,
|
||||
)?;
|
||||
self.set_window(ViewportId::MAIN)?;
|
||||
}
|
||||
@@ -2571,7 +2571,7 @@ mod wgpu_integration {
|
||||
event_loop,
|
||||
storage.as_deref(),
|
||||
&self.app_name,
|
||||
&self.native_options,
|
||||
&mut self.native_options,
|
||||
)?;
|
||||
self.init_run_state(event_loop, storage, window, builder)?;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::{epi, App};
|
||||
use super::{now_sec, web_painter::WebPainter, NeedRepaint};
|
||||
|
||||
pub struct AppRunner {
|
||||
web_options: crate::WebOptions,
|
||||
pub(crate) frame: epi::Frame,
|
||||
egui_ctx: egui::Context,
|
||||
painter: super::ActiveWebPainter,
|
||||
@@ -99,6 +100,7 @@ impl AppRunner {
|
||||
}
|
||||
|
||||
let mut runner = Self {
|
||||
web_options,
|
||||
frame,
|
||||
egui_ctx,
|
||||
painter,
|
||||
@@ -175,7 +177,7 @@ impl AppRunner {
|
||||
pub fn logic(&mut self) -> (std::time::Duration, Vec<egui::ClippedPrimitive>) {
|
||||
let frame_start = now_sec();
|
||||
|
||||
super::resize_canvas_to_screen_size(self.canvas_id(), self.app.max_size_points());
|
||||
super::resize_canvas_to_screen_size(self.canvas_id(), self.web_options.max_size_points);
|
||||
let canvas_size = super::canvas_size_in_points(self.canvas_id());
|
||||
let raw_input = self.input.new_frame(canvas_size);
|
||||
|
||||
|
||||
@@ -6,6 +6,13 @@ This file is updated upon each release.
|
||||
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.
|
||||
|
||||
|
||||
## 0.23.0 - 2023-09-27
|
||||
* Update to `wgpu` 0.17.0 [#3170](https://github.com/emilk/egui/pull/3170) (thanks [@Aaron1011](https://github.com/Aaron1011)!)
|
||||
* Improved wgpu callbacks [#3253](https://github.com/emilk/egui/pull/3253) (thanks [@Wumpf](https://github.com/Wumpf)!)
|
||||
* Fix depth texture init with multisampling [#3207](https://github.com/emilk/egui/pull/3207) (thanks [@mauliu](https://github.com/mauliu)!)
|
||||
* Fix panic on wgpu GL backend due to new screenshot capability [#3078](https://github.com/emilk/egui/pull/3078) (thanks [@amfaber](https://github.com/amfaber)!)
|
||||
|
||||
|
||||
## 0.22.0 - 2023-05-23
|
||||
* Update to wgpu 0.16 [#2884](https://github.com/emilk/egui/pull/2884) (thanks [@niklaskorz](https://github.com/niklaskorz)!)
|
||||
* Device configuration is now dependent on adapter [#2951](https://github.com/emilk/egui/pull/2951) (thanks [@Wumpf](https://github.com/Wumpf)!)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui-wgpu"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
description = "Bindings for using egui natively using the wgpu library"
|
||||
authors = [
|
||||
"Nils Hasenbanck <nils@hasenbanck.de>",
|
||||
@@ -36,8 +36,8 @@ winit = ["dep:winit"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false }
|
||||
epaint = { version = "0.22.0", path = "../epaint", default-features = false, features = [
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false }
|
||||
epaint = { version = "0.23.0", path = "../epaint", default-features = false, features = [
|
||||
"bytemuck",
|
||||
] }
|
||||
|
||||
|
||||
@@ -123,6 +123,16 @@ pub struct WgpuConfiguration {
|
||||
pub on_surface_error: Arc<dyn Fn(wgpu::SurfaceError) -> SurfaceErrorAction>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for WgpuConfiguration {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("WgpuConfiguration")
|
||||
.field("supported_backends", &self.supported_backends)
|
||||
.field("present_mode", &self.present_mode)
|
||||
.field("power_preference", &self.power_preference)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WgpuConfiguration {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
||||
@@ -5,6 +5,13 @@ This file is updated upon each release.
|
||||
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.
|
||||
|
||||
|
||||
## 0.23.0 - 2023-09-27
|
||||
* Only show on-screen-keyboard and IME when editing text [#3362](https://github.com/emilk/egui/pull/3362) (thanks [@Barugon](https://github.com/Barugon)!)
|
||||
* Replace `instant` with `web_time` [#3296](https://github.com/emilk/egui/pull/3296)
|
||||
* Allow users to opt-out of default `winit` features [#3228](https://github.com/emilk/egui/pull/3228)
|
||||
* Recognize numpad enter/plus/minus [#3285](https://github.com/emilk/egui/pull/3285)
|
||||
|
||||
|
||||
## 0.22.0 - 2023-05-23
|
||||
* Only use `wasm-bindgen` feature for `instant` when building for wasm32 [#2808](https://github.com/emilk/egui/pull/2808) (thanks [@gferon](https://github.com/gferon)!)
|
||||
* Fix unsafe API of `Clipboard::new` [#2765](https://github.com/emilk/egui/pull/2765) (thanks [@dhardy](https://github.com/dhardy)!)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui-winit"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Bindings for using egui with winit"
|
||||
edition = "2021"
|
||||
@@ -23,6 +23,15 @@ default = ["clipboard", "links", "wayland", "winit/default", "x11"]
|
||||
## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/).
|
||||
accesskit = ["accesskit_winit", "egui/accesskit"]
|
||||
|
||||
# Allow crates to choose an android-activity backend via Winit
|
||||
# - It's important that most applications should not have to depend on android-activity directly, and can
|
||||
# rely on Winit to pull in a suitable version (unlike most Rust crates, any version conflicts won't link)
|
||||
# - It's also important that we don't impose an android-activity backend by taking this choice away from applications.
|
||||
## Enable the `game-activity` backend via Winit on Android
|
||||
android-game-activity = ["winit/android-game-activity"]
|
||||
## Enable the `native-activity` backend via Winit on Android
|
||||
android-native-activity = ["winit/android-native-activity"]
|
||||
|
||||
## [`bytemuck`](https://docs.rs/bytemuck) enables you to cast [`egui::epaint::Vertex`], [`egui::Vec2`] etc to `&[u8]`.
|
||||
bytemuck = ["egui/bytemuck"]
|
||||
|
||||
@@ -45,18 +54,8 @@ wayland = ["winit/wayland"]
|
||||
## Enables compiling for x11.
|
||||
x11 = ["winit/x11"]
|
||||
|
||||
# Allow crates to choose an android-activity backend via Winit
|
||||
# - It's important that most applications should not have to depend on android-activity directly, and can
|
||||
# rely on Winit to pull in a suitable version (unlike most Rust crates, any version conflicts won't link)
|
||||
# - It's also important that we don't impose an android-activity backend by taking this choice away from applications.
|
||||
|
||||
## Enable the `native-activity` backend via Winit on Android
|
||||
android-native-activity = ["winit/android-native-activity"]
|
||||
## Enable the `game-activity` backend via Winit on Android
|
||||
android-game-activity = ["winit/android-game-activity"]
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false, features = [
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false, features = [
|
||||
"log",
|
||||
] }
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "An easy-to-use immediate mode GUI that runs on both web and native"
|
||||
edition = "2021"
|
||||
@@ -22,9 +22,18 @@ all-features = true
|
||||
[features]
|
||||
default = ["default_fonts"]
|
||||
|
||||
## Exposes detailed accessibility implementation required by platform
|
||||
## accessibility APIs. Also requires support in the egui integration.
|
||||
accesskit = ["dep:accesskit"]
|
||||
|
||||
## [`bytemuck`](https://docs.rs/bytemuck) enables you to cast [`epaint::Vertex`], [`emath::Vec2`] etc to `&[u8]`.
|
||||
bytemuck = ["epaint/bytemuck"]
|
||||
|
||||
## Show a debug-ui on hover including the stacktrace to the hovered item.
|
||||
## This is very useful in finding the code that creates a part of the UI.
|
||||
## Does not work on web.
|
||||
callstack = ["dep:backtrace"]
|
||||
|
||||
## [`cint`](https://docs.rs/cint) enables interoperability with other color libraries.
|
||||
cint = ["epaint/cint"]
|
||||
|
||||
@@ -67,7 +76,7 @@ unity = ["epaint/unity"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
epaint = { version = "0.22.0", path = "../epaint", default-features = false }
|
||||
epaint = { version = "0.23.0", path = "../epaint", default-features = false }
|
||||
|
||||
ahash = { version = "0.8.1", default-features = false, features = [
|
||||
"no-rng", # we don't need DOS-protection, so we let users opt-in to it instead
|
||||
@@ -76,10 +85,10 @@ ahash = { version = "0.8.1", default-features = false, features = [
|
||||
nohash-hasher = "0.2"
|
||||
|
||||
#! ### Optional dependencies
|
||||
## Exposes detailed accessibility implementation required by platform
|
||||
## accessibility APIs. Also requires support in the egui integration.
|
||||
accesskit = { version = "0.11", optional = true }
|
||||
|
||||
backtrace = { version = "0.3", optional = true }
|
||||
|
||||
## Enable this when generating docs.
|
||||
document-features = { version = "0.2", optional = true }
|
||||
|
||||
|
||||
186
crates/egui/src/callstack.rs
Normal file
186
crates/egui/src/callstack.rs
Normal file
@@ -0,0 +1,186 @@
|
||||
#[derive(Clone)]
|
||||
struct Frame {
|
||||
/// `_main` is usually as the deepest depth.
|
||||
depth: usize,
|
||||
name: String,
|
||||
file_and_line: String,
|
||||
}
|
||||
|
||||
/// Capture a callstack, skipping the frames that are not interesting.
|
||||
///
|
||||
/// In particular: slips everything before `egui::Context::run`,
|
||||
/// and skipping all frames in the `egui::` namespace.
|
||||
pub fn capture() -> String {
|
||||
let mut frames = vec![];
|
||||
let mut depth = 0;
|
||||
|
||||
backtrace::trace(|frame| {
|
||||
// Resolve this instruction pointer to a symbol name
|
||||
backtrace::resolve_frame(frame, |symbol| {
|
||||
let mut file_and_line = symbol.filename().map(shorten_source_file_path);
|
||||
|
||||
if let Some(file_and_line) = &mut file_and_line {
|
||||
if let Some(line_nr) = symbol.lineno() {
|
||||
file_and_line.push_str(&format!(":{line_nr}"));
|
||||
}
|
||||
}
|
||||
let file_and_line = file_and_line.unwrap_or_default();
|
||||
|
||||
let name = symbol
|
||||
.name()
|
||||
.map(|name| name.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
frames.push(Frame {
|
||||
depth,
|
||||
name,
|
||||
file_and_line,
|
||||
});
|
||||
});
|
||||
|
||||
depth += 1; // note: we can resolve multiple symbols on the same frame.
|
||||
|
||||
true // keep going to the next frame
|
||||
});
|
||||
|
||||
if frames.is_empty() {
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
// Inclusive:
|
||||
let mut min_depth = 0;
|
||||
let mut max_depth = frames.len() - 1;
|
||||
|
||||
for frame in &frames {
|
||||
if frame.name.starts_with("egui::callstack::capture") {
|
||||
min_depth = frame.depth + 1;
|
||||
}
|
||||
if frame.name.starts_with("egui::context::Context::run") {
|
||||
max_depth = frame.depth;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove frames that are uninteresting:
|
||||
frames.retain(|frame| {
|
||||
// Keep some special frames to give the user a sense of chronology:
|
||||
if frame.name == "main"
|
||||
|| frame.name == "_main"
|
||||
|| frame.name.starts_with("egui::context::Context::run")
|
||||
|| frame.name.starts_with("eframe::run_native")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if frame.depth < min_depth || max_depth < frame.depth {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove stuff that isn't user calls:
|
||||
let skip_prefixes = [
|
||||
// "backtrace::", // not needed, since we cut at at egui::callstack::capture
|
||||
"egui::",
|
||||
"<egui::",
|
||||
"<F as egui::widgets::Widget>",
|
||||
"egui_plot::",
|
||||
"egui_extras::",
|
||||
"core::ptr::drop_in_place<egui::ui::Ui>::",
|
||||
"eframe::",
|
||||
"core::ops::function::FnOnce::call_once",
|
||||
"<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once",
|
||||
];
|
||||
for prefix in skip_prefixes {
|
||||
if frame.name.starts_with(prefix) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
frames.reverse(); // main on top, i.e. chronological order. Same as Python.
|
||||
|
||||
let mut deepest_depth = 0;
|
||||
let mut widest_file_line = 0;
|
||||
for frame in &frames {
|
||||
deepest_depth = frame.depth.max(deepest_depth);
|
||||
widest_file_line = frame.file_and_line.len().max(widest_file_line);
|
||||
}
|
||||
|
||||
let widest_depth = deepest_depth.to_string().len();
|
||||
|
||||
let mut formatted = String::new();
|
||||
|
||||
if !frames.is_empty() {
|
||||
let mut last_depth = frames[0].depth;
|
||||
|
||||
for frame in &frames {
|
||||
let Frame {
|
||||
depth,
|
||||
name,
|
||||
file_and_line,
|
||||
} = frame;
|
||||
|
||||
if frame.depth + 1 < last_depth || last_depth + 1 < frame.depth {
|
||||
// Show that some frames were elided
|
||||
formatted.push_str(&format!("{:widest_depth$} …\n", ""));
|
||||
}
|
||||
|
||||
formatted.push_str(&format!(
|
||||
"{depth:widest_depth$}: {file_and_line:widest_file_line$} {name}\n"
|
||||
));
|
||||
|
||||
last_depth = frame.depth;
|
||||
}
|
||||
}
|
||||
|
||||
formatted
|
||||
}
|
||||
|
||||
/// Shorten a path to a Rust source file from a callstack.
|
||||
///
|
||||
/// Example input:
|
||||
/// * `/Users/emilk/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.24.1/src/runtime/runtime.rs`
|
||||
/// * `crates/rerun/src/main.rs`
|
||||
/// * `/rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/ops/function.rs`
|
||||
fn shorten_source_file_path(path: &std::path::Path) -> String {
|
||||
// Look for `src` and strip everything up to it.
|
||||
|
||||
let components: Vec<_> = path.iter().map(|path| path.to_string_lossy()).collect();
|
||||
|
||||
let mut src_idx = None;
|
||||
for (i, c) in components.iter().enumerate() {
|
||||
if c == "src" {
|
||||
src_idx = Some(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the last `src`:
|
||||
if let Some(src_idx) = src_idx {
|
||||
// Before `src` comes the name of the crate - let's include that:
|
||||
let first_index = src_idx.saturating_sub(1);
|
||||
|
||||
let mut output = components[first_index].to_string();
|
||||
for component in &components[first_index + 1..] {
|
||||
output.push('/');
|
||||
output.push_str(component);
|
||||
}
|
||||
output
|
||||
} else {
|
||||
// No `src` directory found - weird!
|
||||
path.display().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shorten_path() {
|
||||
for (before, after) in [
|
||||
("/Users/emilk/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.24.1/src/runtime/runtime.rs", "tokio-1.24.1/src/runtime/runtime.rs"),
|
||||
("crates/rerun/src/main.rs", "rerun/src/main.rs"),
|
||||
("/rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/ops/function.rs", "core/src/ops/function.rs"),
|
||||
("/weird/path/file.rs", "/weird/path/file.rs"),
|
||||
]
|
||||
{
|
||||
use std::str::FromStr as _;
|
||||
let before = std::path::PathBuf::from_str(before).unwrap();
|
||||
assert_eq!(shorten_source_file_path(&before), after);
|
||||
}
|
||||
}
|
||||
@@ -65,12 +65,12 @@ pub struct Area {
|
||||
interactable: bool,
|
||||
enabled: bool,
|
||||
constrain: bool,
|
||||
constrain_rect: Option<Rect>,
|
||||
order: Order,
|
||||
default_pos: Option<Pos2>,
|
||||
pivot: Align2,
|
||||
anchor: Option<(Align2, Vec2)>,
|
||||
new_pos: Option<Pos2>,
|
||||
drag_bounds: Option<Rect>,
|
||||
}
|
||||
|
||||
impl Area {
|
||||
@@ -80,13 +80,13 @@ impl Area {
|
||||
movable: true,
|
||||
interactable: true,
|
||||
constrain: false,
|
||||
constrain_rect: None,
|
||||
enabled: true,
|
||||
order: Order::Middle,
|
||||
default_pos: None,
|
||||
new_pos: None,
|
||||
pivot: Align2::LEFT_TOP,
|
||||
anchor: None,
|
||||
drag_bounds: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,21 @@ impl Area {
|
||||
self
|
||||
}
|
||||
|
||||
/// Constraint the movement of the window to the given rectangle.
|
||||
///
|
||||
/// For instance: `.constrain_to(ctx.screen_rect())`.
|
||||
pub fn constrain_to(mut self, constrain_rect: Rect) -> Self {
|
||||
self.constrain = true;
|
||||
self.constrain_rect = Some(constrain_rect);
|
||||
self
|
||||
}
|
||||
|
||||
#[deprecated = "Use `constrain_to` instead"]
|
||||
pub fn drag_bounds(mut self, constrain_rect: Rect) -> Self {
|
||||
self.constrain_rect = Some(constrain_rect);
|
||||
self
|
||||
}
|
||||
|
||||
/// Where the "root" of the area is.
|
||||
///
|
||||
/// For instance, if you set this to [`Align2::RIGHT_TOP`]
|
||||
@@ -189,12 +204,6 @@ impl Area {
|
||||
self.movable(false)
|
||||
}
|
||||
|
||||
/// Constrain the area up to which the window can be dragged.
|
||||
pub fn drag_bounds(mut self, bounds: Rect) -> Self {
|
||||
self.drag_bounds = Some(bounds);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn get_pivot(&self) -> Align2 {
|
||||
if let Some((pivot, _)) = self.anchor {
|
||||
pivot
|
||||
@@ -209,7 +218,8 @@ pub(crate) struct Prepared {
|
||||
state: State,
|
||||
move_response: Response,
|
||||
enabled: bool,
|
||||
drag_bounds: Option<Rect>,
|
||||
constrain: bool,
|
||||
constrain_rect: Option<Rect>,
|
||||
|
||||
/// We always make windows invisible the first frame to hide "first-frame-jitters".
|
||||
///
|
||||
@@ -243,8 +253,8 @@ impl Area {
|
||||
new_pos,
|
||||
pivot,
|
||||
anchor,
|
||||
drag_bounds,
|
||||
constrain,
|
||||
constrain_rect,
|
||||
} = self;
|
||||
|
||||
let layer_id = LayerId::new(order, id);
|
||||
@@ -271,7 +281,7 @@ impl Area {
|
||||
}
|
||||
|
||||
// interact right away to prevent frame-delay
|
||||
let move_response = {
|
||||
let mut move_response = {
|
||||
let interact_id = layer_id.id.with("move");
|
||||
let sense = if movable {
|
||||
Sense::click_and_drag()
|
||||
@@ -291,16 +301,8 @@ impl Area {
|
||||
enabled,
|
||||
);
|
||||
|
||||
// Important check - don't try to move e.g. a combobox popup!
|
||||
if movable {
|
||||
if move_response.dragged() {
|
||||
state.pivot_pos += ctx.input(|i| i.pointer.delta());
|
||||
}
|
||||
|
||||
state.set_left_top_pos(
|
||||
ctx.constrain_window_rect_to_area(state.rect(), drag_bounds)
|
||||
.min,
|
||||
);
|
||||
if movable && move_response.dragged() {
|
||||
state.pivot_pos += ctx.input(|i| i.pointer.delta());
|
||||
}
|
||||
|
||||
if (move_response.dragged() || move_response.clicked())
|
||||
@@ -314,21 +316,25 @@ impl Area {
|
||||
move_response
|
||||
};
|
||||
|
||||
state.set_left_top_pos(ctx.round_pos_to_pixels(state.left_top_pos()));
|
||||
|
||||
if constrain {
|
||||
state.set_left_top_pos(
|
||||
ctx.constrain_window_rect_to_area(state.rect(), drag_bounds)
|
||||
.left_top(),
|
||||
ctx.constrain_window_rect_to_area(state.rect(), constrain_rect)
|
||||
.min,
|
||||
);
|
||||
}
|
||||
|
||||
state.set_left_top_pos(ctx.round_pos_to_pixels(state.left_top_pos()));
|
||||
|
||||
// Update responsbe with posisbly moved/constrained rect:
|
||||
move_response = move_response.with_new_rect(state.rect());
|
||||
|
||||
Prepared {
|
||||
layer_id,
|
||||
state,
|
||||
move_response,
|
||||
enabled,
|
||||
drag_bounds,
|
||||
constrain,
|
||||
constrain_rect,
|
||||
temporarily_invisible: is_new,
|
||||
}
|
||||
}
|
||||
@@ -371,15 +377,19 @@ impl Prepared {
|
||||
&mut self.state
|
||||
}
|
||||
|
||||
pub(crate) fn drag_bounds(&self) -> Option<Rect> {
|
||||
self.drag_bounds
|
||||
pub(crate) fn constrain(&self) -> bool {
|
||||
self.constrain
|
||||
}
|
||||
|
||||
pub(crate) fn constrain_rect(&self) -> Option<Rect> {
|
||||
self.constrain_rect
|
||||
}
|
||||
|
||||
pub(crate) fn content_ui(&self, ctx: &Context) -> Ui {
|
||||
let screen_rect = ctx.screen_rect();
|
||||
|
||||
let bounds = if let Some(bounds) = self.drag_bounds {
|
||||
bounds.intersect(screen_rect) // protect against infinite bounds
|
||||
let constrain_rect = if let Some(constrain_rect) = self.constrain_rect {
|
||||
constrain_rect.intersect(screen_rect) // protect against infinite bounds
|
||||
} else {
|
||||
let central_area = ctx.available_rect();
|
||||
|
||||
@@ -393,7 +403,7 @@ impl Prepared {
|
||||
|
||||
let max_rect = Rect::from_min_max(
|
||||
self.state.left_top_pos(),
|
||||
bounds
|
||||
constrain_rect
|
||||
.max
|
||||
.at_least(self.state.left_top_pos() + Vec2::splat(32.0)),
|
||||
);
|
||||
@@ -401,9 +411,9 @@ impl Prepared {
|
||||
let shadow_radius = ctx.style().visuals.window_shadow.extrusion; // hacky
|
||||
let clip_rect_margin = ctx.style().visuals.clip_rect_margin.max(shadow_radius);
|
||||
|
||||
let clip_rect = Rect::from_min_max(self.state.left_top_pos(), bounds.max)
|
||||
let clip_rect = Rect::from_min_max(self.state.left_top_pos(), constrain_rect.max)
|
||||
.expand(clip_rect_margin)
|
||||
.intersect(bounds);
|
||||
.intersect(constrain_rect);
|
||||
|
||||
let mut ui = Ui::new(
|
||||
ctx.clone(),
|
||||
@@ -424,7 +434,8 @@ impl Prepared {
|
||||
mut state,
|
||||
move_response,
|
||||
enabled: _,
|
||||
drag_bounds: _,
|
||||
constrain: _,
|
||||
constrain_rect: _,
|
||||
temporarily_invisible: _,
|
||||
} = self;
|
||||
|
||||
|
||||
@@ -260,9 +260,8 @@ fn show_tooltip_area_dyn<'c, R>(
|
||||
Area::new(area_id)
|
||||
.order(Order::Tooltip)
|
||||
.fixed_pos(window_pos)
|
||||
.constrain(true)
|
||||
.constrain_to(ctx.screen_rect())
|
||||
.interactable(false)
|
||||
.drag_bounds(ctx.screen_rect())
|
||||
.show(ctx, |ui| {
|
||||
Frame::popup(&ctx.style())
|
||||
.show(ui, |ui| {
|
||||
|
||||
@@ -314,6 +314,7 @@ impl Resize {
|
||||
|
||||
state.store(ui.ctx(), id);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if ui.ctx().style().debug.show_resize {
|
||||
ui.ctx().debug_painter().debug_rect(
|
||||
Rect::from_min_size(content_ui.min_rect().left_top(), state.desired_size),
|
||||
|
||||
@@ -43,7 +43,7 @@ impl<'open> Window<'open> {
|
||||
/// If you need a changing title, you must call `window.id(…)` with a fixed id.
|
||||
pub fn new(title: impl Into<WidgetText>) -> Self {
|
||||
let title = title.into().fallback_text_style(TextStyle::Heading);
|
||||
let area = Area::new(Id::new(title.text()));
|
||||
let area = Area::new(Id::new(title.text())).constrain(true);
|
||||
Self {
|
||||
title,
|
||||
open: None,
|
||||
@@ -146,11 +146,31 @@ impl<'open> Window<'open> {
|
||||
}
|
||||
|
||||
/// Constrains this window to the screen bounds.
|
||||
///
|
||||
/// To change the area to constrain to, use [`Self::constraint_to`].
|
||||
///
|
||||
/// Default: `true`.
|
||||
pub fn constrain(mut self, constrain: bool) -> Self {
|
||||
self.area = self.area.constrain(constrain);
|
||||
self
|
||||
}
|
||||
|
||||
/// Constraint the movement of the window to the given rectangle.
|
||||
///
|
||||
/// For instance: `.constrain_to(ctx.screen_rect())`.
|
||||
pub fn constraint_to(mut self, constrain_rect: Rect) -> Self {
|
||||
self.area = self.area.constrain_to(constrain_rect);
|
||||
self
|
||||
}
|
||||
|
||||
#[deprecated = "Use `constrain_to` instead"]
|
||||
pub fn drag_bounds(mut self, constrain_rect: Rect) -> Self {
|
||||
#![allow(deprecated)]
|
||||
|
||||
self.area = self.area.drag_bounds(constrain_rect);
|
||||
self
|
||||
}
|
||||
|
||||
/// Where the "root" of the window is.
|
||||
///
|
||||
/// For instance, if you set this to [`Align2::RIGHT_TOP`]
|
||||
@@ -276,12 +296,6 @@ impl<'open> Window<'open> {
|
||||
self.scroll = self.scroll.drag_to_scroll(drag_to_scroll);
|
||||
self
|
||||
}
|
||||
|
||||
/// Constrain the area up to which the window can be dragged.
|
||||
pub fn drag_bounds(mut self, bounds: Rect) -> Self {
|
||||
self.area = self.area.drag_bounds(bounds);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'open> Window<'open> {
|
||||
@@ -452,13 +466,6 @@ impl<'open> Window<'open> {
|
||||
content_inner
|
||||
};
|
||||
|
||||
{
|
||||
let pos = ctx
|
||||
.constrain_window_rect_to_area(area.state().rect(), area.drag_bounds())
|
||||
.left_top();
|
||||
area.state_mut().set_left_top_pos(pos);
|
||||
}
|
||||
|
||||
let full_response = area.end(ctx, area_content_ui);
|
||||
|
||||
let inner_response = InnerResponse {
|
||||
@@ -562,9 +569,11 @@ fn interact(
|
||||
resize_id: Id,
|
||||
) -> Option<WindowInteraction> {
|
||||
let new_rect = move_and_resize_window(ctx, &window_interaction)?;
|
||||
let new_rect = ctx.round_rect_to_pixels(new_rect);
|
||||
let mut new_rect = ctx.round_rect_to_pixels(new_rect);
|
||||
|
||||
let new_rect = ctx.constrain_window_rect_to_area(new_rect, area.drag_bounds());
|
||||
if area.constrain() {
|
||||
new_rect = ctx.constrain_window_rect_to_area(new_rect, area.constrain_rect());
|
||||
}
|
||||
|
||||
// TODO(emilk): add this to a Window state instead as a command "move here next frame"
|
||||
area.state_mut().set_left_top_pos(new_rect.left_top());
|
||||
|
||||
@@ -830,6 +830,7 @@ impl Context {
|
||||
// This solves the problem of overlapping widgets.
|
||||
// Whichever widget is added LAST (=on top) gets the input:
|
||||
if interact_rect.is_positive() && sense.interactive() {
|
||||
#[cfg(debug_assertions)]
|
||||
if self.style().debug.show_interactive_widgets {
|
||||
Self::layer_painter(self, LayerId::debug()).rect(
|
||||
interact_rect,
|
||||
@@ -838,6 +839,8 @@ impl Context {
|
||||
Stroke::new(1.0, Color32::YELLOW.additive().linear_multiply(0.05)),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let mut show_blocking_widget = None;
|
||||
|
||||
self.write(|ctx| {
|
||||
@@ -858,6 +861,7 @@ impl Context {
|
||||
// Another interactive widget is covering us at the pointer position,
|
||||
// so we aren't hovered.
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if ctx.memory.options.style.debug.show_blocking_widget {
|
||||
// Store the rects to use them outside the write() call to
|
||||
// avoid deadlock
|
||||
@@ -873,6 +877,7 @@ impl Context {
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if let Some((interact_rect, prev_rect)) = show_blocking_widget {
|
||||
Self::layer_painter(self, LayerId::debug()).debug_rect(
|
||||
interact_rect,
|
||||
@@ -1892,15 +1897,15 @@ impl Context {
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/// Whether or not to debug widget layout on hover.
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn debug_on_hover(&self) -> bool {
|
||||
self.options(|opt| opt.style.debug.debug_on_hover)
|
||||
}
|
||||
|
||||
/// Turn on/off whether or not to debug widget layout on hover.
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn set_debug_on_hover(&self, debug_on_hover: bool) {
|
||||
let mut style = self.options(|opt| (*opt.style).clone());
|
||||
style.debug.debug_on_hover = debug_on_hover;
|
||||
self.set_style(style);
|
||||
self.style_mut(|style| style.debug.debug_on_hover = debug_on_hover);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1991,7 +1996,6 @@ impl Context {
|
||||
/// Show the state of egui, including its input and output.
|
||||
pub fn inspection_ui(&self, ui: &mut Ui) {
|
||||
use crate::containers::*;
|
||||
crate::trace!(ui);
|
||||
|
||||
ui.label(format!("Is using pointer: {}", self.is_using_pointer()))
|
||||
.on_hover_text(
|
||||
|
||||
@@ -479,6 +479,11 @@ impl Modifiers {
|
||||
!self.is_none()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn all(&self) -> bool {
|
||||
self.alt && self.ctrl && self.shift && self.command
|
||||
}
|
||||
|
||||
/// Is shift the only pressed button?
|
||||
#[inline]
|
||||
pub fn shift_only(&self) -> bool {
|
||||
|
||||
@@ -54,6 +54,9 @@ pub(crate) struct FrameState {
|
||||
|
||||
/// Highlight these widgets the next frame. Write to this.
|
||||
pub(crate) highlight_next_frame: IdSet,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) has_debug_viewed_this_frame: bool,
|
||||
}
|
||||
|
||||
impl Default for FrameState {
|
||||
@@ -70,6 +73,9 @@ impl Default for FrameState {
|
||||
accesskit_state: None,
|
||||
highlight_this_frame: Default::default(),
|
||||
highlight_next_frame: Default::default(),
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
has_debug_viewed_this_frame: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +95,9 @@ impl FrameState {
|
||||
accesskit_state,
|
||||
highlight_this_frame,
|
||||
highlight_next_frame,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
has_debug_viewed_this_frame,
|
||||
} = self;
|
||||
|
||||
used_ids.clear();
|
||||
@@ -99,6 +108,11 @@ impl FrameState {
|
||||
*scroll_delta = input.scroll_delta;
|
||||
*scroll_target = [None, None];
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
*has_debug_viewed_this_frame = false;
|
||||
}
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
{
|
||||
*accesskit_state = None;
|
||||
|
||||
@@ -187,24 +187,27 @@ impl GridLayout {
|
||||
}
|
||||
|
||||
pub(crate) fn advance(&mut self, cursor: &mut Rect, _frame_rect: Rect, widget_rect: Rect) {
|
||||
let debug_expand_width = self.style.debug.show_expand_width;
|
||||
let debug_expand_height = self.style.debug.show_expand_height;
|
||||
if debug_expand_width || debug_expand_height {
|
||||
let rect = widget_rect;
|
||||
let too_wide = rect.width() > self.prev_col_width(self.col);
|
||||
let too_high = rect.height() > self.prev_row_height(self.row);
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let debug_expand_width = self.style.debug.show_expand_width;
|
||||
let debug_expand_height = self.style.debug.show_expand_height;
|
||||
if debug_expand_width || debug_expand_height {
|
||||
let rect = widget_rect;
|
||||
let too_wide = rect.width() > self.prev_col_width(self.col);
|
||||
let too_high = rect.height() > self.prev_row_height(self.row);
|
||||
|
||||
if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
|
||||
let painter = self.ctx.debug_painter();
|
||||
painter.rect_stroke(rect, 0.0, (1.0, Color32::LIGHT_BLUE));
|
||||
if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
|
||||
let painter = self.ctx.debug_painter();
|
||||
painter.rect_stroke(rect, 0.0, (1.0, Color32::LIGHT_BLUE));
|
||||
|
||||
let stroke = Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
|
||||
let paint_line_seg = |a, b| painter.line_segment([a, b], stroke);
|
||||
let stroke = Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
|
||||
let paint_line_seg = |a, b| painter.line_segment([a, b], stroke);
|
||||
|
||||
if debug_expand_width && too_wide {
|
||||
paint_line_seg(rect.left_top(), rect.left_bottom());
|
||||
paint_line_seg(rect.left_center(), rect.right_center());
|
||||
paint_line_seg(rect.right_top(), rect.right_bottom());
|
||||
if debug_expand_width && too_wide {
|
||||
paint_line_seg(rect.left_top(), rect.left_bottom());
|
||||
paint_line_seg(rect.left_center(), rect.right_center());
|
||||
paint_line_seg(rect.right_top(), rect.right_bottom());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,6 +801,7 @@ impl Layout {
|
||||
/// ## Debug stuff
|
||||
impl Layout {
|
||||
/// Shows where the next widget is going to be placed
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn paint_text_at_cursor(
|
||||
&self,
|
||||
painter: &crate::Painter,
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
//! Then you add a [`Window`] or a [`SidePanel`] to get a [`Ui`], which is what you'll be using to add all the buttons and labels that you need.
|
||||
//!
|
||||
//!
|
||||
//! ## Feature flags
|
||||
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
|
||||
//!
|
||||
//!
|
||||
//! # Using egui
|
||||
//!
|
||||
//! To see what is possible to build with egui you can check out the online demo at <https://www.egui.rs/#demo>.
|
||||
@@ -163,7 +167,14 @@
|
||||
//!
|
||||
//! # Understanding immediate mode
|
||||
//!
|
||||
//! `egui` is an immediate mode GUI library. It is useful to fully grok what "immediate mode" implies.
|
||||
//! `egui` is an immediate mode GUI library.
|
||||
//!
|
||||
//! Immediate mode has its roots in gaming, where everything on the screen is painted at the
|
||||
//! display refresh rate, i.e. at 60+ frames per second.
|
||||
//! In immediate mode GUIs, the entire interface is laid out and painted at the same high rate.
|
||||
//! This makes immediate mode GUIs especially well suited for highly interactive applications.
|
||||
//!
|
||||
//! It is useful to fully grok what "immediate mode" implies.
|
||||
//!
|
||||
//! Here is an example to illustrate it:
|
||||
//!
|
||||
@@ -198,7 +209,7 @@
|
||||
//! # });
|
||||
//! ```
|
||||
//!
|
||||
//! Here egui will read `value` to display the slider, then look if the mouse is dragging the slider and if so change the `value`.
|
||||
//! Here egui will read `value` (an `f32`) to display the slider, then look if the mouse is dragging the slider and if so change the `value`.
|
||||
//! Note that `egui` does not store the slider value for you - it only displays the current value, and changes it
|
||||
//! by how much the slider has been dragged in the previous few milliseconds.
|
||||
//! This means it is responsibility of the egui user to store the state (`value`) so that it persists between frames.
|
||||
@@ -318,10 +329,6 @@
|
||||
//! }); // the temporary settings are reverted here
|
||||
//! # });
|
||||
//! ```
|
||||
//!
|
||||
//! ## Feature flags
|
||||
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
|
||||
//!
|
||||
|
||||
#![allow(clippy::float_cmp)]
|
||||
#![allow(clippy::manual_range_contains)]
|
||||
@@ -354,6 +361,10 @@ pub mod viewport;
|
||||
pub mod widget_text;
|
||||
pub mod widgets;
|
||||
|
||||
#[cfg(feature = "callstack")]
|
||||
#[cfg(debug_assertions)]
|
||||
mod callstack;
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
pub use accesskit;
|
||||
|
||||
@@ -439,7 +450,8 @@ pub fn warn_if_debug_build(ui: &mut crate::Ui) {
|
||||
/// ui.image(egui::include_image!("../assets/ferris.png"));
|
||||
/// ui.add(
|
||||
/// egui::Image::new(egui::include_image!("../assets/ferris.png"))
|
||||
/// .rounding(egui::Rounding::same(6.0))
|
||||
/// .max_width(200.0)
|
||||
/// .rounding(10.0),
|
||||
/// );
|
||||
///
|
||||
/// let image_source: egui::ImageSource = egui::include_image!("../assets/ferris.png");
|
||||
@@ -449,10 +461,10 @@ pub fn warn_if_debug_build(ui: &mut crate::Ui) {
|
||||
#[macro_export]
|
||||
macro_rules! include_image {
|
||||
($path: literal) => {
|
||||
$crate::ImageSource::Bytes(
|
||||
::std::borrow::Cow::Borrowed(concat!("bytes://", $path)), // uri
|
||||
$crate::load::Bytes::Static(include_bytes!($path)),
|
||||
)
|
||||
$crate::ImageSource::Bytes {
|
||||
uri: ::std::borrow::Cow::Borrowed(concat!("bytes://", $path)),
|
||||
bytes: $crate::load::Bytes::Static(include_bytes!($path)),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -488,32 +500,6 @@ macro_rules! github_link_file {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Show debug info on hover when [`Context::set_debug_on_hover`] has been turned on.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// // Turn on tracing of widgets
|
||||
/// ui.ctx().set_debug_on_hover(true);
|
||||
///
|
||||
/// /// Show [`std::file`], [`std::line`] and argument on hover
|
||||
/// egui::trace!(ui, "MyWindow");
|
||||
///
|
||||
/// /// Show [`std::file`] and [`std::line`] on hover
|
||||
/// egui::trace!(ui);
|
||||
/// # });
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! trace {
|
||||
($ui: expr) => {{
|
||||
$ui.trace_location(format!("{}:{}", file!(), line!()))
|
||||
}};
|
||||
($ui: expr, $label: expr) => {{
|
||||
$ui.trace_location(format!("{} - {}:{}", $label, file!(), line!()))
|
||||
}};
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// An assert that is only active when `egui` is compiled with the `extra_asserts` feature
|
||||
/// or with the `extra_debug_asserts` feature in debug builds.
|
||||
#[macro_export]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! will get you up and running quickly with its reasonable default implementations of the traits described below.
|
||||
//!
|
||||
//! 1. Add [`egui_extras`](https://crates.io/crates/egui_extras/) as a dependency with the `all_loaders` feature.
|
||||
//! 2. Add a call to [`egui_extras::install_image_loaders`](https://docs.rs/egui_extras/latest/egui_extras/loaders/fn.install.html)
|
||||
//! 2. Add a call to [`egui_extras::install_image_loaders`](https://docs.rs/egui_extras/latest/egui_extras/fn.install_image_loaders.html)
|
||||
//! in your app's setup code.
|
||||
//! 3. Use [`Ui::image`][`crate::ui::Ui::image`] with some [`ImageSource`][`crate::ImageSource`].
|
||||
//!
|
||||
@@ -55,17 +55,20 @@
|
||||
mod bytes_loader;
|
||||
mod texture_loader;
|
||||
|
||||
use crate::Context;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use std::{error::Error as StdError, fmt::Display, sync::Arc};
|
||||
|
||||
use ahash::HashMap;
|
||||
|
||||
use epaint::mutex::Mutex;
|
||||
use epaint::util::FloatOrd;
|
||||
use epaint::util::OrderedFloat;
|
||||
use epaint::TextureHandle;
|
||||
use epaint::{textures::TextureOptions, ColorImage, TextureId, Vec2};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use std::{error::Error as StdError, fmt::Display, sync::Arc};
|
||||
|
||||
use crate::Context;
|
||||
|
||||
pub use self::bytes_loader::DefaultBytesLoader;
|
||||
pub use self::texture_loader::DefaultTextureLoader;
|
||||
@@ -76,15 +79,15 @@ pub enum LoadError {
|
||||
/// Programmer error: There are no image loaders installed.
|
||||
NoImageLoaders,
|
||||
|
||||
/// A specific loader does not support this schema, protocol or image format.
|
||||
/// A specific loader does not support this scheme, protocol or image format.
|
||||
NotSupported,
|
||||
|
||||
/// Programmer error: Failed to find the bytes for this image because
|
||||
/// there was no [`BytesLoader`] supporting the schema.
|
||||
/// there was no [`BytesLoader`] supporting the scheme.
|
||||
NoMatchingBytesLoader,
|
||||
|
||||
/// Programmer error: Failed to parse the bytes as an image because
|
||||
/// there was no [`ImageLoader`] supporting the schema.
|
||||
/// there was no [`ImageLoader`] supporting the scheme.
|
||||
NoMatchingImageLoader,
|
||||
|
||||
/// Programmer error: no matching [`TextureLoader`].
|
||||
@@ -108,7 +111,7 @@ impl Display for LoadError {
|
||||
|
||||
Self::NoMatchingTextureLoader => f.write_str("No matching TextureLoader. Did you remove the default one?"),
|
||||
|
||||
Self::NotSupported => f.write_str("Iagge schema or URI not supported by this loader"),
|
||||
Self::NotSupported => f.write_str("Image scheme or URI not supported by this loader"),
|
||||
|
||||
Self::Loading(message) => f.write_str(message),
|
||||
}
|
||||
|
||||
@@ -146,10 +146,9 @@ pub(crate) fn menu_ui<'c, R>(
|
||||
|
||||
let area = Area::new(menu_id)
|
||||
.order(Order::Foreground)
|
||||
.constrain(true)
|
||||
.fixed_pos(pos)
|
||||
.interactable(true)
|
||||
.drag_bounds(ctx.screen_rect());
|
||||
.constrain_to(ctx.screen_rect())
|
||||
.interactable(true);
|
||||
|
||||
area.show(ctx, |ui| {
|
||||
set_menu_style(ui.style_mut());
|
||||
@@ -348,8 +347,7 @@ impl MenuRoot {
|
||||
if let Some(root) = root.inner.as_mut() {
|
||||
if root.id == id {
|
||||
// pressed somewhere while this menu is open
|
||||
let menu_state = root.menu_state.read();
|
||||
let in_menu = menu_state.area_contains(pos);
|
||||
let in_menu = root.menu_state.read().area_contains(pos);
|
||||
if !in_menu {
|
||||
return MenuResponse::Close;
|
||||
}
|
||||
@@ -374,8 +372,7 @@ impl MenuRoot {
|
||||
let mut destroy = false;
|
||||
let mut in_old_menu = false;
|
||||
if let Some(root) = root {
|
||||
let menu_state = root.menu_state.read();
|
||||
in_old_menu = menu_state.area_contains(pos);
|
||||
in_old_menu = root.menu_state.read().area_contains(pos);
|
||||
destroy = root.id == response.id;
|
||||
}
|
||||
if !in_old_menu {
|
||||
|
||||
@@ -263,6 +263,7 @@ impl Placer {
|
||||
}
|
||||
|
||||
impl Placer {
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn debug_paint_cursor(&self, painter: &crate::Painter, text: impl ToString) {
|
||||
let stroke = Stroke::new(1.0, Color32::DEBUG_COLOR);
|
||||
|
||||
|
||||
@@ -201,6 +201,9 @@ pub struct Style {
|
||||
pub animation_time: f32,
|
||||
|
||||
/// Options to help debug why egui behaves strangely.
|
||||
///
|
||||
/// Only available in debug builds.
|
||||
#[cfg(debug_assertions)]
|
||||
pub debug: DebugOptions,
|
||||
|
||||
/// Show tooltips explaining [`DragValue`]:s etc when hovered.
|
||||
@@ -690,12 +693,36 @@ impl WidgetVisuals {
|
||||
}
|
||||
|
||||
/// Options for help debug egui by adding extra visualization
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg(debug_assertions)]
|
||||
pub struct DebugOptions {
|
||||
/// However over widgets to see their rectangles
|
||||
/// Always show callstack to ui on hover.
|
||||
///
|
||||
/// Useful for figuring out where in the code some UI is being created.
|
||||
///
|
||||
/// Only works in debug builds.
|
||||
/// Requires the `callstack` feature.
|
||||
/// Does not work on web.
|
||||
#[cfg(debug_assertions)]
|
||||
pub debug_on_hover: bool,
|
||||
|
||||
/// Show callstack for the current widget on hover if all modifier keys are pressed down.
|
||||
///
|
||||
/// Useful for figuring out where in the code some UI is being created.
|
||||
///
|
||||
/// Only works in debug builds.
|
||||
/// Requires the `callstack` feature.
|
||||
/// Does not work on web.
|
||||
///
|
||||
/// Default is `true` in debug builds, on native, if the `callstack` feature is enabled.
|
||||
#[cfg(debug_assertions)]
|
||||
pub debug_on_hover_with_all_modifiers: bool,
|
||||
|
||||
/// If we show the hover ui, include where the next widget is placed.
|
||||
#[cfg(debug_assertions)]
|
||||
pub hover_shows_next: bool,
|
||||
|
||||
/// Show which widgets make their parent wider
|
||||
pub show_expand_width: bool,
|
||||
|
||||
@@ -711,6 +738,23 @@ pub struct DebugOptions {
|
||||
pub show_blocking_widget: bool,
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl Default for DebugOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
debug_on_hover: false,
|
||||
debug_on_hover_with_all_modifiers: cfg!(feature = "callstack")
|
||||
&& !cfg!(target_arch = "wasm32"),
|
||||
hover_shows_next: false,
|
||||
show_expand_width: false,
|
||||
show_expand_height: false,
|
||||
show_resize: false,
|
||||
show_interactive_widgets: false,
|
||||
show_blocking_widget: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// The default text styles of the default egui theme.
|
||||
@@ -739,6 +783,7 @@ impl Default for Style {
|
||||
interaction: Interaction::default(),
|
||||
visuals: Visuals::default(),
|
||||
animation_time: 1.0 / 12.0,
|
||||
#[cfg(debug_assertions)]
|
||||
debug: Default::default(),
|
||||
explanation_tooltips: false,
|
||||
}
|
||||
@@ -993,6 +1038,7 @@ impl Style {
|
||||
interaction,
|
||||
visuals,
|
||||
animation_time,
|
||||
#[cfg(debug_assertions)]
|
||||
debug,
|
||||
explanation_tooltips,
|
||||
} = self;
|
||||
@@ -1055,6 +1101,8 @@ impl Style {
|
||||
ui.collapsing("📏 Spacing", |ui| spacing.ui(ui));
|
||||
ui.collapsing("☝ Interaction", |ui| interaction.ui(ui));
|
||||
ui.collapsing("🎨 Visuals", |ui| visuals.ui(ui));
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
ui.collapsing("🐛 Debug", |ui| debug.ui(ui));
|
||||
|
||||
ui.checkbox(explanation_tooltips, "Explanation tooltips")
|
||||
@@ -1477,10 +1525,13 @@ impl Visuals {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl DebugOptions {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
let Self {
|
||||
debug_on_hover,
|
||||
debug_on_hover_with_all_modifiers,
|
||||
hover_shows_next,
|
||||
show_expand_width,
|
||||
show_expand_height,
|
||||
show_resize,
|
||||
@@ -1488,7 +1539,16 @@ impl DebugOptions {
|
||||
show_blocking_widget,
|
||||
} = self;
|
||||
|
||||
ui.checkbox(debug_on_hover, "Show debug info on hover");
|
||||
{
|
||||
ui.checkbox(debug_on_hover, "Show widget info on hover.");
|
||||
ui.checkbox(
|
||||
debug_on_hover_with_all_modifiers,
|
||||
"Show widget info on hover if holding all modifier keys",
|
||||
);
|
||||
|
||||
ui.checkbox(hover_shows_next, "Show next widget placement on hover");
|
||||
}
|
||||
|
||||
ui.checkbox(
|
||||
show_expand_width,
|
||||
"Show which widgets make their parent wider",
|
||||
|
||||
@@ -738,43 +738,41 @@ impl Ui {
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn allocate_space(&mut self, desired_size: Vec2) -> (Id, Rect) {
|
||||
// For debug rendering
|
||||
#[cfg(debug_assertions)]
|
||||
let original_available = self.available_size_before_wrap();
|
||||
let too_wide = desired_size.x > original_available.x;
|
||||
let too_high = desired_size.y > original_available.y;
|
||||
|
||||
let rect = self.allocate_space_impl(desired_size);
|
||||
|
||||
if self.style().debug.debug_on_hover && self.rect_contains_pointer(rect) {
|
||||
let painter = self.ctx().debug_painter();
|
||||
painter.rect_stroke(rect, 4.0, (1.0, Color32::LIGHT_BLUE));
|
||||
self.placer.debug_paint_cursor(&painter, "next");
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let too_wide = desired_size.x > original_available.x;
|
||||
let too_high = desired_size.y > original_available.y;
|
||||
|
||||
let debug_expand_width = self.style().debug.show_expand_width;
|
||||
let debug_expand_height = self.style().debug.show_expand_height;
|
||||
let debug_expand_width = self.style().debug.show_expand_width;
|
||||
let debug_expand_height = self.style().debug.show_expand_height;
|
||||
|
||||
if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
|
||||
self.painter
|
||||
.rect_stroke(rect, 0.0, (1.0, Color32::LIGHT_BLUE));
|
||||
if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
|
||||
self.painter
|
||||
.rect_stroke(rect, 0.0, (1.0, Color32::LIGHT_BLUE));
|
||||
|
||||
let stroke = Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
|
||||
let paint_line_seg = |a, b| self.painter().line_segment([a, b], stroke);
|
||||
let stroke = Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
|
||||
let paint_line_seg = |a, b| self.painter().line_segment([a, b], stroke);
|
||||
|
||||
if debug_expand_width && too_wide {
|
||||
paint_line_seg(rect.left_top(), rect.left_bottom());
|
||||
paint_line_seg(rect.left_center(), rect.right_center());
|
||||
paint_line_seg(
|
||||
pos2(rect.left() + original_available.x, rect.top()),
|
||||
pos2(rect.left() + original_available.x, rect.bottom()),
|
||||
);
|
||||
paint_line_seg(rect.right_top(), rect.right_bottom());
|
||||
}
|
||||
if debug_expand_width && too_wide {
|
||||
paint_line_seg(rect.left_top(), rect.left_bottom());
|
||||
paint_line_seg(rect.left_center(), rect.right_center());
|
||||
paint_line_seg(
|
||||
pos2(rect.left() + original_available.x, rect.top()),
|
||||
pos2(rect.left() + original_available.x, rect.bottom()),
|
||||
);
|
||||
paint_line_seg(rect.right_top(), rect.right_bottom());
|
||||
}
|
||||
|
||||
if debug_expand_height && too_high {
|
||||
paint_line_seg(rect.left_top(), rect.right_top());
|
||||
paint_line_seg(rect.center_top(), rect.center_bottom());
|
||||
paint_line_seg(rect.left_bottom(), rect.right_bottom());
|
||||
if debug_expand_height && too_high {
|
||||
paint_line_seg(rect.left_top(), rect.right_top());
|
||||
paint_line_seg(rect.center_top(), rect.center_bottom());
|
||||
paint_line_seg(rect.left_bottom(), rect.right_bottom());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,6 +793,8 @@ impl Ui {
|
||||
self.placer
|
||||
.advance_after_rects(frame_rect, widget_rect, item_spacing);
|
||||
|
||||
register_rect(self, widget_rect);
|
||||
|
||||
widget_rect
|
||||
}
|
||||
|
||||
@@ -803,6 +803,7 @@ impl Ui {
|
||||
/// Ignore the layout of the [`Ui`]: just put my widget here!
|
||||
/// The layout cursor will advance to past this `rect`.
|
||||
pub fn allocate_rect(&mut self, rect: Rect, sense: Sense) -> Response {
|
||||
register_rect(self, rect);
|
||||
let id = self.advance_cursor_after_rect(rect);
|
||||
self.interact(rect, id, sense)
|
||||
}
|
||||
@@ -813,12 +814,6 @@ impl Ui {
|
||||
let item_spacing = self.spacing().item_spacing;
|
||||
self.placer.advance_after_rects(rect, rect, item_spacing);
|
||||
|
||||
if self.style().debug.debug_on_hover && self.rect_contains_pointer(rect) {
|
||||
let painter = self.ctx().debug_painter();
|
||||
painter.rect_stroke(rect, 4.0, (1.0, Color32::LIGHT_BLUE));
|
||||
self.placer.debug_paint_cursor(&painter, "next");
|
||||
}
|
||||
|
||||
let id = Id::new(self.next_auto_id_source);
|
||||
self.next_auto_id_source = self.next_auto_id_source.wrapping_add(1);
|
||||
id
|
||||
@@ -896,13 +891,6 @@ impl Ui {
|
||||
self.placer
|
||||
.advance_after_rects(final_child_rect, final_child_rect, item_spacing);
|
||||
|
||||
if self.style().debug.debug_on_hover && self.rect_contains_pointer(final_child_rect) {
|
||||
let painter = self.ctx().debug_painter();
|
||||
painter.rect_stroke(frame_rect, 4.0, (1.0, Color32::LIGHT_BLUE));
|
||||
painter.rect_stroke(final_child_rect, 4.0, (1.0, Color32::LIGHT_BLUE));
|
||||
self.placer.debug_paint_cursor(&painter, "next");
|
||||
}
|
||||
|
||||
let response = self.interact(final_child_rect, child_ui.id, Sense::hover());
|
||||
InnerResponse::new(ret, response)
|
||||
}
|
||||
@@ -1561,7 +1549,7 @@ impl Ui {
|
||||
/// Show an image available at the given `uri`.
|
||||
///
|
||||
/// ⚠ This will do nothing unless you install some image loaders first!
|
||||
/// The easiest way to do this is via [`egui_extras::install_image_loaders`](https://docs.rs/egui_extras/latest/egui_extras/loaders/fn.install.html).
|
||||
/// The easiest way to do this is via [`egui_extras::install_image_loaders`](https://docs.rs/egui_extras/latest/egui_extras/fn.install_image_loaders.html).
|
||||
///
|
||||
/// The loaders handle caching image data, sampled textures, etc. across frames, so calling this is immediate-mode safe.
|
||||
///
|
||||
@@ -1572,7 +1560,8 @@ impl Ui {
|
||||
/// ui.image(egui::include_image!("../assets/ferris.png"));
|
||||
/// ui.add(
|
||||
/// egui::Image::new(egui::include_image!("../assets/ferris.png"))
|
||||
/// .rounding(egui::Rounding::same(6.0))
|
||||
/// .max_width(200.0)
|
||||
/// .rounding(10.0),
|
||||
/// );
|
||||
/// # });
|
||||
/// ```
|
||||
@@ -1793,10 +1782,7 @@ impl Ui {
|
||||
let mut child_rect = self.placer.available_rect_before_wrap();
|
||||
child_rect.min.x += indent;
|
||||
|
||||
let mut child_ui = Self {
|
||||
id: self.id.with(id_source),
|
||||
..self.child_ui(child_rect, *self.layout())
|
||||
};
|
||||
let mut child_ui = self.child_ui_with_id_source(child_rect, *self.layout(), id_source);
|
||||
let ret = add_contents(&mut child_ui);
|
||||
|
||||
let left_vline = self.visuals().indent_has_left_vline;
|
||||
@@ -2024,12 +2010,6 @@ impl Ui {
|
||||
let item_spacing = self.spacing().item_spacing;
|
||||
self.placer.advance_after_rects(rect, rect, item_spacing);
|
||||
|
||||
if self.style().debug.debug_on_hover && self.rect_contains_pointer(rect) {
|
||||
let painter = self.ctx().debug_painter();
|
||||
painter.rect_stroke(rect, 4.0, (1.0, Color32::LIGHT_BLUE));
|
||||
self.placer.debug_paint_cursor(&painter, "next");
|
||||
}
|
||||
|
||||
InnerResponse::new(inner, self.interact(rect, child_ui.id, Sense::hover()))
|
||||
}
|
||||
|
||||
@@ -2215,21 +2195,121 @@ impl Ui {
|
||||
/// # Debug stuff
|
||||
impl Ui {
|
||||
/// Shows where the next widget is going to be placed
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn debug_paint_cursor(&self) {
|
||||
self.placer.debug_paint_cursor(&self.painter, "next");
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows the given text where the next widget is to be placed
|
||||
/// if when [`Context::set_debug_on_hover`] has been turned on and the mouse is hovering the Ui.
|
||||
pub fn trace_location(&self, text: impl ToString) {
|
||||
let rect = self.max_rect();
|
||||
if self.style().debug.debug_on_hover && self.rect_contains_pointer(rect) {
|
||||
self.placer
|
||||
.debug_paint_cursor(&self.ctx().debug_painter(), text);
|
||||
#[cfg(debug_assertions)]
|
||||
impl Drop for Ui {
|
||||
fn drop(&mut self) {
|
||||
register_rect(self, self.min_rect());
|
||||
}
|
||||
}
|
||||
|
||||
/// Show this rectangle to the user if certain debug options are set.
|
||||
#[cfg(debug_assertions)]
|
||||
fn register_rect(ui: &Ui, rect: Rect) {
|
||||
let debug = ui.style().debug;
|
||||
|
||||
let show_callstacks = debug.debug_on_hover
|
||||
|| debug.debug_on_hover_with_all_modifiers && ui.input(|i| i.modifiers.all());
|
||||
|
||||
if !show_callstacks {
|
||||
return;
|
||||
}
|
||||
|
||||
if ui.ctx().frame_state(|o| o.has_debug_viewed_this_frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !ui.rect_contains_pointer(rect) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only show one debug rectangle, or things get confusing:
|
||||
ui.ctx()
|
||||
.frame_state_mut(|o| o.has_debug_viewed_this_frame = true);
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
let is_clicking = ui.input(|i| i.pointer.could_any_button_be_click());
|
||||
|
||||
// Use the debug-painter to avoid clip rect,
|
||||
// otherwise the content of the widget may cover what we paint here!
|
||||
let painter = ui.ctx().debug_painter();
|
||||
|
||||
// Paint rectangle around widget:
|
||||
{
|
||||
let rect_fg_color = if is_clicking {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
Color32::LIGHT_BLUE
|
||||
};
|
||||
let rect_bg_color = Color32::BLUE.gamma_multiply(0.5);
|
||||
|
||||
painter.rect(rect, 0.0, rect_bg_color, (1.0, rect_fg_color));
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
if debug.hover_shows_next {
|
||||
ui.placer.debug_paint_cursor(&painter, "next");
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
#[cfg(feature = "callstack")]
|
||||
let callstack = crate::callstack::capture();
|
||||
|
||||
#[cfg(not(feature = "callstack"))]
|
||||
let callstack = String::default();
|
||||
|
||||
if !callstack.is_empty() {
|
||||
let font_id = FontId::monospace(12.0);
|
||||
let text = format!("{callstack}\n\n(click to copy)");
|
||||
let galley = painter.layout_no_wrap(text, font_id, Color32::WHITE);
|
||||
|
||||
// Position the text either under or above:
|
||||
let screen_rect = ui.ctx().screen_rect();
|
||||
let y = if galley.size().y <= rect.top() {
|
||||
// Above
|
||||
rect.top() - galley.size().y
|
||||
} else {
|
||||
// Below
|
||||
rect.bottom()
|
||||
};
|
||||
|
||||
let y = y
|
||||
.at_most(screen_rect.bottom() - galley.size().y)
|
||||
.at_least(0.0);
|
||||
|
||||
let x = rect
|
||||
.left()
|
||||
.at_most(screen_rect.right() - galley.size().x)
|
||||
.at_least(0.0);
|
||||
let text_pos = pos2(x, y);
|
||||
|
||||
let text_bg_color = Color32::from_black_alpha(180);
|
||||
let text_rect_stroke_color = if is_clicking {
|
||||
Color32::WHITE
|
||||
} else {
|
||||
text_bg_color
|
||||
};
|
||||
let text_rect = Rect::from_min_size(text_pos, galley.size());
|
||||
painter.rect(text_rect, 0.0, text_bg_color, (1.0, text_rect_stroke_color));
|
||||
painter.galley(text_pos, galley);
|
||||
|
||||
if ui.input(|i| i.pointer.any_click()) {
|
||||
ui.ctx().copy_text(callstack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn register_rect(_ui: &Ui, _rect: Rect) {}
|
||||
|
||||
#[test]
|
||||
fn ui_impl_send_sync() {
|
||||
fn assert_send_sync<T: Send + Sync>() {}
|
||||
|
||||
@@ -588,10 +588,9 @@ impl PersistedMap {
|
||||
crate::profile_scope!("gather");
|
||||
for (hash, element) in &map.map {
|
||||
if let Some(element) = element.to_serialize() {
|
||||
let mut stats = types_map.entry(element.type_id).or_default();
|
||||
let stats = types_map.entry(element.type_id).or_default();
|
||||
stats.num_bytes += element.ron.len();
|
||||
let mut generation_stats =
|
||||
stats.generations.entry(element.generation).or_default();
|
||||
let generation_stats = stats.generations.entry(element.generation).or_default();
|
||||
generation_stats.num_bytes += element.ron.len();
|
||||
generation_stats.elements.push((*hash, element));
|
||||
} else {
|
||||
|
||||
@@ -100,7 +100,10 @@ impl<'a> Image<'a> {
|
||||
///
|
||||
/// See [`ImageSource::Bytes`].
|
||||
pub fn from_bytes(uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) -> Self {
|
||||
Self::new(ImageSource::Bytes(uri.into(), bytes.into()))
|
||||
Self::new(ImageSource::Bytes {
|
||||
uri: uri.into(),
|
||||
bytes: bytes.into(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Texture options used when creating the texture.
|
||||
@@ -275,7 +278,7 @@ impl<'a> Image<'a> {
|
||||
pub fn size(&self) -> Option<Vec2> {
|
||||
match &self.source {
|
||||
ImageSource::Texture(texture) => Some(texture.size),
|
||||
ImageSource::Uri(_) | ImageSource::Bytes(_, _) => None,
|
||||
ImageSource::Uri(_) | ImageSource::Bytes { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,9 +481,10 @@ impl Default for ImageSize {
|
||||
/// This is used by [`Image::new`] and [`Ui::image`].
|
||||
#[derive(Clone)]
|
||||
pub enum ImageSource<'a> {
|
||||
/// Load the image from a URI.
|
||||
/// Load the image from a URI, e.g. `https://example.com/image.png`.
|
||||
///
|
||||
/// This could be a `file://` path, `https://` url, `bytes://` identifier, or some other scheme.
|
||||
///
|
||||
/// This could be a `file://` url, `http(s)?://` url, or a `bare` identifier.
|
||||
/// How the URI will be turned into a texture for rendering purposes is
|
||||
/// up to the registered loaders to handle.
|
||||
///
|
||||
@@ -495,8 +499,6 @@ pub enum ImageSource<'a> {
|
||||
|
||||
/// Load the image from some raw bytes.
|
||||
///
|
||||
/// For better error messages, use the `bytes://` prefix for the URI.
|
||||
///
|
||||
/// The [`Bytes`] may be:
|
||||
/// - `'static`, obtained from `include_bytes!` or similar
|
||||
/// - Anything that can be converted to `Arc<[u8]>`
|
||||
@@ -506,13 +508,22 @@ pub enum ImageSource<'a> {
|
||||
/// See also [`include_image`] for an easy way to load and display static images.
|
||||
///
|
||||
/// See [`crate::load`] for more information.
|
||||
Bytes(Cow<'static, str>, Bytes),
|
||||
Bytes {
|
||||
/// The unique identifier for this image, e.g. `bytes://my_logo.png`.
|
||||
///
|
||||
/// You should use a proper extension (`.jpg`, `.png`, `.svg`, etc) for the image to load properly.
|
||||
///
|
||||
/// Use the `bytes://` scheme for the URI for better error messages.
|
||||
uri: Cow<'static, str>,
|
||||
|
||||
bytes: Bytes,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Debug for ImageSource<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ImageSource::Bytes(uri, _) | ImageSource::Uri(uri) => uri.as_ref().fmt(f),
|
||||
ImageSource::Bytes { uri, .. } | ImageSource::Uri(uri) => uri.as_ref().fmt(f),
|
||||
ImageSource::Texture(st) => st.id.fmt(f),
|
||||
}
|
||||
}
|
||||
@@ -524,7 +535,7 @@ impl<'a> ImageSource<'a> {
|
||||
pub fn texture_size(&self) -> Option<Vec2> {
|
||||
match self {
|
||||
ImageSource::Texture(texture) => Some(texture.size),
|
||||
ImageSource::Uri(_) | ImageSource::Bytes(_, _) => None,
|
||||
ImageSource::Uri(_) | ImageSource::Bytes { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +550,7 @@ impl<'a> ImageSource<'a> {
|
||||
match self {
|
||||
Self::Texture(texture) => Ok(TexturePoll::Ready { texture }),
|
||||
Self::Uri(uri) => ctx.try_load_texture(uri.as_ref(), texture_options, size_hint),
|
||||
Self::Bytes(uri, bytes) => {
|
||||
Self::Bytes { uri, bytes } => {
|
||||
ctx.include_bytes(uri.clone(), bytes);
|
||||
ctx.try_load_texture(uri.as_ref(), texture_options, size_hint)
|
||||
}
|
||||
@@ -551,7 +562,7 @@ impl<'a> ImageSource<'a> {
|
||||
/// This will return `None` for [`Self::Texture`].
|
||||
pub fn uri(&self) -> Option<&str> {
|
||||
match self {
|
||||
ImageSource::Bytes(uri, _) | ImageSource::Uri(uri) => Some(uri),
|
||||
ImageSource::Bytes { uri, .. } | ImageSource::Uri(uri) => Some(uri),
|
||||
ImageSource::Texture(_) => None,
|
||||
}
|
||||
}
|
||||
@@ -644,21 +655,30 @@ impl<'a> From<Cow<'a, str>> for ImageSource<'a> {
|
||||
impl<T: Into<Bytes>> From<(&'static str, T)> for ImageSource<'static> {
|
||||
#[inline]
|
||||
fn from((uri, bytes): (&'static str, T)) -> Self {
|
||||
Self::Bytes(uri.into(), bytes.into())
|
||||
Self::Bytes {
|
||||
uri: uri.into(),
|
||||
bytes: bytes.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Bytes>> From<(Cow<'static, str>, T)> for ImageSource<'static> {
|
||||
#[inline]
|
||||
fn from((uri, bytes): (Cow<'static, str>, T)) -> Self {
|
||||
Self::Bytes(uri, bytes.into())
|
||||
Self::Bytes {
|
||||
uri,
|
||||
bytes: bytes.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Bytes>> From<(String, T)> for ImageSource<'static> {
|
||||
#[inline]
|
||||
fn from((uri, bytes): (String, T)) -> Self {
|
||||
Self::Bytes(uri.into(), bytes.into())
|
||||
Self::Bytes {
|
||||
uri: uri.into(),
|
||||
bytes: bytes.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui_demo_app"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
@@ -18,6 +18,9 @@ crate-type = ["cdylib", "rlib"]
|
||||
[features]
|
||||
default = ["glow", "persistence"]
|
||||
|
||||
# image_viewer adds about 0.9 MB of WASM
|
||||
web_app = ["http", "persistence", "web_screen_reader"]
|
||||
|
||||
http = ["ehttp", "image", "poll-promise", "egui_extras/image"]
|
||||
image_viewer = ["image", "egui_extras/all_loaders", "rfd"]
|
||||
persistence = ["eframe/persistence", "egui/persistence", "serde"]
|
||||
@@ -33,12 +36,13 @@ chrono = { version = "0.4", default-features = false, features = [
|
||||
"js-sys",
|
||||
"wasmbind",
|
||||
] }
|
||||
eframe = { version = "0.22.0", path = "../eframe", default-features = false }
|
||||
egui = { version = "0.22.0", path = "../egui", features = [
|
||||
eframe = { version = "0.23.0", path = "../eframe", default-features = false }
|
||||
egui = { version = "0.23.0", path = "../egui", features = [
|
||||
"callstack",
|
||||
"extra_debug_asserts",
|
||||
"log",
|
||||
] }
|
||||
egui_demo_lib = { version = "0.22.0", path = "../egui_demo_lib", features = [
|
||||
egui_demo_lib = { version = "0.23.0", path = "../egui_demo_lib", features = [
|
||||
"chrono",
|
||||
] }
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
@@ -46,18 +50,17 @@ log = { version = "0.4", features = ["std"] }
|
||||
# Optional dependencies:
|
||||
|
||||
bytemuck = { version = "1.7.1", optional = true }
|
||||
egui_extras = { version = "0.22.0", path = "../egui_extras", features = [
|
||||
egui_extras = { version = "0.23.0", path = "../egui_extras", features = [
|
||||
"image",
|
||||
] }
|
||||
rfd = { version = "0.11", optional = true }
|
||||
|
||||
# feature "http":
|
||||
ehttp = { version = "0.3.0", optional = true }
|
||||
ehttp = { version = "0.3.1", optional = true }
|
||||
image = { version = "0.24", optional = true, default-features = false, features = [
|
||||
"jpeg",
|
||||
"png",
|
||||
] }
|
||||
poll-promise = { version = "0.2", optional = true, default-features = false }
|
||||
poll-promise = { version = "0.3", optional = true, default-features = false }
|
||||
|
||||
# feature "persistence":
|
||||
serde = { version = "1", optional = true, features = ["derive"] }
|
||||
@@ -66,6 +69,7 @@ serde = { version = "1", optional = true, features = ["derive"] }
|
||||
# native:
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
env_logger = "0.10"
|
||||
rfd = { version = "0.11", optional = true }
|
||||
|
||||
# web:
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
|
||||
@@ -82,8 +82,6 @@ impl BackendPanel {
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||
egui::trace!(ui);
|
||||
|
||||
self.integration_ui(ui, frame);
|
||||
|
||||
ui.separator();
|
||||
@@ -101,11 +99,9 @@ impl BackendPanel {
|
||||
|
||||
ui.separator();
|
||||
|
||||
{
|
||||
let mut debug_on_hover = ui.ctx().debug_on_hover();
|
||||
ui.checkbox(&mut debug_on_hover, "🐛 Debug on hover")
|
||||
.on_hover_text("Show structure of the ui when you hover with the mouse");
|
||||
ui.ctx().set_debug_on_hover(debug_on_hover);
|
||||
#[cfg(debug_assertions)]
|
||||
if ui.ctx().style().debug.debug_on_hover_with_all_modifiers {
|
||||
ui.label("Press down all modifiers and hover a widget to see a callstack for it");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
||||
@@ -164,21 +164,22 @@ pub struct WrapApp {
|
||||
}
|
||||
|
||||
impl WrapApp {
|
||||
pub fn new(_cc: &eframe::CreationContext<'_>) -> Self {
|
||||
egui_extras::install_image_loaders(&_cc.egui_ctx);
|
||||
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
// This gives us image support:
|
||||
egui_extras::install_image_loaders(&cc.egui_ctx);
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut slf = Self {
|
||||
state: State::default(),
|
||||
|
||||
#[cfg(any(feature = "glow", feature = "wgpu"))]
|
||||
custom3d: crate::apps::Custom3d::new(_cc),
|
||||
custom3d: crate::apps::Custom3d::new(cc),
|
||||
|
||||
dropped_files: Default::default(),
|
||||
};
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
if let Some(storage) = _cc.storage {
|
||||
if let Some(storage) = cc.storage {
|
||||
if let Some(state) = eframe::get_value(storage, eframe::APP_KEY) {
|
||||
slf.state = state;
|
||||
}
|
||||
@@ -263,7 +264,6 @@ impl eframe::App for WrapApp {
|
||||
|
||||
let mut cmd = Command::Nothing;
|
||||
egui::TopBottomPanel::top("wrap_app_top_bar").show(ctx, |ui| {
|
||||
egui::trace!(ui);
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.visuals_mut().button_frame = false;
|
||||
self.bar_contents(ui, frame, &mut cmd);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui_demo_lib"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Example library for egui"
|
||||
edition = "2021"
|
||||
@@ -11,7 +11,13 @@ readme = "README.md"
|
||||
repository = "https://github.com/emilk/egui/tree/master/crates/egui_demo_lib"
|
||||
categories = ["gui", "graphics"]
|
||||
keywords = ["glium", "egui", "gui", "gamedev"]
|
||||
include = ["../LICENSE-APACHE", "../LICENSE-MIT", "**/*.rs", "Cargo.toml"]
|
||||
include = [
|
||||
"../LICENSE-APACHE",
|
||||
"../LICENSE-MIT",
|
||||
"**/*.rs",
|
||||
"Cargo.toml",
|
||||
"data/icon.png",
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
@@ -32,9 +38,9 @@ syntect = ["egui_extras/syntect"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false }
|
||||
egui_extras = { version = "0.22.0", path = "../egui_extras" }
|
||||
egui_plot = { version = "0.22.0", path = "../egui_plot" }
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false }
|
||||
egui_extras = { version = "0.23.0", path = "../egui_extras" }
|
||||
egui_plot = { version = "0.23.0", path = "../egui_plot" }
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
unicode_names2 = { version = "0.6.0", default-features = false }
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -11,6 +11,7 @@ impl super::Demo for About {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.default_width(320.0)
|
||||
.default_height(480.0)
|
||||
.open(open)
|
||||
.show(ctx, |ui| {
|
||||
use super::View as _;
|
||||
@@ -41,6 +42,15 @@ impl super::View for About {
|
||||
ui.add_space(12.0); // ui.separator();
|
||||
ui.heading("Links");
|
||||
links(ui);
|
||||
|
||||
ui.add_space(12.0);
|
||||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("egui development is sponsored by ");
|
||||
ui.hyperlink_to("Rerun.io", "https://www.rerun.io/");
|
||||
ui.label(", a startup building an SDK for visualizing streams of multimodal data");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,15 +75,10 @@ fn about_immediate_mode(ui: &mut egui::Ui) {
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
|
||||
ui.label("Note how there are no callbacks or messages, and no button state to store.");
|
||||
|
||||
ui.label("Immediate mode has its roots in gaming, where everything on the screen is painted at the display refresh rate, i.e. at 60+ frames per second. \
|
||||
In immediate mode GUIs, the entire interface is laid out and painted at the same high rate. \
|
||||
This makes immediate mode GUIs especially well suited for highly interactive applications.");
|
||||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("More about immediate mode ");
|
||||
ui.label("There are no callbacks or messages, and no button state to store. ");
|
||||
ui.label("Read more about immediate mode ");
|
||||
ui.hyperlink_to("here", "https://github.com/emilk/egui#why-immediate-mode");
|
||||
ui.label(".");
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use egui::{Context, Modifiers, ScrollArea, Ui};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use egui::{Context, Modifiers, NumExt as _, ScrollArea, Ui};
|
||||
|
||||
use super::About;
|
||||
use super::Demo;
|
||||
use super::View;
|
||||
@@ -180,7 +181,7 @@ impl DemoWindows {
|
||||
fn mobile_ui(&mut self, ctx: &Context) {
|
||||
if self.about_is_open {
|
||||
let screen_size = ctx.input(|i| i.screen_rect.size());
|
||||
let default_width = (screen_size.x - 20.0).min(400.0);
|
||||
let default_width = (screen_size.x - 32.0).at_most(400.0);
|
||||
|
||||
let mut close = false;
|
||||
egui::Window::new(self.about.name())
|
||||
@@ -243,7 +244,6 @@ impl DemoWindows {
|
||||
.resizable(false)
|
||||
.default_width(150.0)
|
||||
.show(ctx, |ui| {
|
||||
egui::trace!(ui);
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.heading("✒ egui demos");
|
||||
});
|
||||
|
||||
@@ -197,7 +197,7 @@ impl WidgetGallery {
|
||||
ui.end_row();
|
||||
|
||||
ui.add(doc_link_label("Image", "Image"));
|
||||
let egui_icon = egui::include_image!("../../assets/icon.png");
|
||||
let egui_icon = egui::include_image!("../../data/icon.png");
|
||||
ui.add(egui::Image::new(egui_icon.clone()));
|
||||
ui.end_row();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ pub struct WindowOptions {
|
||||
closable: bool,
|
||||
collapsible: bool,
|
||||
resizable: bool,
|
||||
constrain: bool,
|
||||
scroll2: [bool; 2],
|
||||
disabled_time: f64,
|
||||
|
||||
@@ -22,6 +23,7 @@ impl Default for WindowOptions {
|
||||
closable: true,
|
||||
collapsible: true,
|
||||
resizable: true,
|
||||
constrain: true,
|
||||
scroll2: [true; 2],
|
||||
disabled_time: f64::NEG_INFINITY,
|
||||
anchored: false,
|
||||
@@ -43,6 +45,7 @@ impl super::Demo for WindowOptions {
|
||||
closable,
|
||||
collapsible,
|
||||
resizable,
|
||||
constrain,
|
||||
scroll2,
|
||||
disabled_time,
|
||||
anchored,
|
||||
@@ -59,6 +62,7 @@ impl super::Demo for WindowOptions {
|
||||
let mut window = egui::Window::new(title)
|
||||
.id(egui::Id::new("demo_window_options")) // required since we change the title
|
||||
.resizable(resizable)
|
||||
.constrain(constrain)
|
||||
.collapsible(collapsible)
|
||||
.title_bar(title_bar)
|
||||
.scroll2(scroll2)
|
||||
@@ -81,6 +85,7 @@ impl super::View for WindowOptions {
|
||||
closable,
|
||||
collapsible,
|
||||
resizable,
|
||||
constrain,
|
||||
scroll2,
|
||||
disabled_time: _,
|
||||
anchored,
|
||||
@@ -99,6 +104,8 @@ impl super::View for WindowOptions {
|
||||
ui.checkbox(closable, "closable");
|
||||
ui.checkbox(collapsible, "collapsible");
|
||||
ui.checkbox(resizable, "resizable");
|
||||
ui.checkbox(constrain, "constrain")
|
||||
.on_hover_text("Constrain window to the screen");
|
||||
ui.checkbox(&mut scroll2[0], "hscroll");
|
||||
ui.checkbox(&mut scroll2[1], "vscroll");
|
||||
});
|
||||
|
||||
@@ -5,6 +5,14 @@ This file is updated upon each release.
|
||||
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.
|
||||
|
||||
|
||||
## 0.23.0 - 2023-09-27
|
||||
* `egui_extras::install_image_loaders` [#3297](https://github.com/emilk/egui/pull/3297) [#3315](https://github.com/emilk/egui/pull/3315) [#3328](https://github.com/emilk/egui/pull/3328) (thanks [@jprochazk](https://github.com/jprochazk)!)
|
||||
* Add syntax highlighting feature to `egui_extras` [#3333](https://github.com/emilk/egui/pull/3333) [#3388](https://github.com/emilk/egui/pull/3388)
|
||||
* Add `TableBuilder::drag_to_scroll` [#3100](https://github.com/emilk/egui/pull/3100) (thanks [@KYovchevski](https://github.com/KYovchevski)!)
|
||||
* Add opt-in `puffin` feature to `egui-extras` [#3307](https://github.com/emilk/egui/pull/3307)
|
||||
* Always depend on `log` crate [#3336](https://github.com/emilk/egui/pull/3336)
|
||||
* Fix not taking clipping into account when calculating column remainder [#3357](https://github.com/emilk/egui/pull/3357) (thanks [@daxpedda](https://github.com/daxpedda)!)
|
||||
|
||||
## 0.22.0 - 2023-05-23
|
||||
- Add option to hide datepicker button calendar icon [#2910](https://github.com/emilk/egui/pull/2910) (thanks [@Barugon](https://github.com/Barugon)!)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui_extras"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = [
|
||||
"Dominik Rössler <dominik@freshx.de>",
|
||||
"Emil Ernerfeldt <emil.ernerfeldt@gmail.com>",
|
||||
@@ -42,7 +42,8 @@ http = ["dep:ehttp"]
|
||||
##
|
||||
## You also need to ALSO opt-in to the image formats you want to support, like so:
|
||||
## ```toml
|
||||
## image = { version = "0.24", features = ["jpeg", "png"] }
|
||||
## image = { version = "0.24", features = ["jpeg", "png"] } # Add the types you want support for
|
||||
|
||||
## ```
|
||||
image = ["dep:image"]
|
||||
|
||||
@@ -59,7 +60,7 @@ syntect = ["dep:syntect"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false, features = [
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
enum-map = { version = "2", features = ["serde"] }
|
||||
@@ -96,4 +97,4 @@ tiny-skia = { version = "0.8", optional = true, default-features = false } # mus
|
||||
usvg = { version = "0.28", optional = true, default-features = false }
|
||||
|
||||
# http feature
|
||||
ehttp = { version = "0.3.0", optional = true, default-features = false }
|
||||
ehttp = { version = "0.3.1", optional = true, default-features = false }
|
||||
|
||||
@@ -13,7 +13,7 @@ One thing `egui_extras` is commonly used for is to install image loaders for `eg
|
||||
|
||||
```toml
|
||||
egui_extras = { version = "*", features = ["all_loaders"] }
|
||||
image = { version = "0.24", features = ["jpeg", "png"] }
|
||||
image = { version = "0.24", features = ["jpeg", "png"] } # Add the types you want support for
|
||||
```
|
||||
|
||||
```rs
|
||||
|
||||
@@ -117,6 +117,7 @@ impl<'a> Widget for DatePickerButton<'a> {
|
||||
} = Area::new(ui.make_persistent_id(self.id_source))
|
||||
.order(Order::Foreground)
|
||||
.fixed_pos(pos)
|
||||
.constrain_to(ui.ctx().screen_rect())
|
||||
.show(ui.ctx(), |ui| {
|
||||
let frame = Frame::popup(ui.style());
|
||||
frame
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
///
|
||||
/// ```toml,ignore
|
||||
/// egui_extras = { version = "*", features = ["all_loaders"] }
|
||||
/// image = { version = "0.24", features = ["jpeg", "png"] }
|
||||
/// image = { version = "0.24", features = ["jpeg", "png"] } # Add the types you want support for
|
||||
/// ```
|
||||
///
|
||||
/// ⚠ You have to configure both the supported loaders in `egui_extras` _and_ the supported image formats
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui_glium"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Bindings for using egui natively using the glium library"
|
||||
edition = "2021"
|
||||
@@ -36,10 +36,10 @@ links = ["egui-winit/links"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false, features = [
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false, features = [
|
||||
"bytemuck",
|
||||
] }
|
||||
egui-winit = { version = "0.22.0", path = "../egui-winit", default-features = false }
|
||||
egui-winit = { version = "0.23.0", path = "../egui-winit", default-features = false }
|
||||
|
||||
ahash = { version = "0.8.1", default-features = false, features = [
|
||||
"no-rng", # we don't need DOS-protection, so we let users opt-in to it instead
|
||||
@@ -54,5 +54,5 @@ document-features = { version = "0.2", optional = true }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
egui_demo_lib = { version = "0.22.0", path = "../egui_demo_lib", default-features = false }
|
||||
egui_demo_lib = { version = "0.23.0", path = "../egui_demo_lib", default-features = false }
|
||||
image = { version = "0.24", default-features = false, features = ["png"] }
|
||||
|
||||
@@ -5,7 +5,12 @@ This file is updated upon each release.
|
||||
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.
|
||||
|
||||
|
||||
## 0.23.0 - 2023-09-27
|
||||
* Update `egui`
|
||||
|
||||
|
||||
## 0.22.0 - 2023-05-23
|
||||
* Update `egui`
|
||||
|
||||
|
||||
## 0.21.0 - 2023-02-08
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "egui_glow"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Bindings for using egui natively using the glow library"
|
||||
edition = "2021"
|
||||
@@ -44,7 +44,7 @@ winit = ["egui-winit"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false, features = [
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false, features = [
|
||||
"bytemuck",
|
||||
] }
|
||||
|
||||
@@ -59,7 +59,7 @@ document-features = { version = "0.2", optional = true }
|
||||
|
||||
# Native:
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
egui-winit = { version = "0.22.0", path = "../egui-winit", optional = true, default-features = false }
|
||||
egui-winit = { version = "0.23.0", path = "../egui-winit", optional = true, default-features = false }
|
||||
puffin = { version = "0.16", optional = true }
|
||||
|
||||
# Web:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! [`egui`] bindings for [`glow`](https://github.com/grovesNL/glow).
|
||||
//!
|
||||
//! The main types you want to look are are [`Painter`].
|
||||
//! The main type you want to look at is [`Painter`].
|
||||
//!
|
||||
//! If you are writing an app, you may want to look at [`eframe`](https://docs.rs/eframe) instead.
|
||||
//!
|
||||
|
||||
@@ -3,3 +3,14 @@ All notable changes to the `egui_plot` integration will be noted in this file.
|
||||
|
||||
This file is updated upon each release.
|
||||
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.
|
||||
|
||||
|
||||
## 0.23.0 - 2023-09-27 - Initial release, after being forked out from `egui`
|
||||
* Draw axis labels and ticks outside of plotting window [#2284](https://github.com/emilk/egui/pull/2284) (thanks [@JohannesProgrammiert](https://github.com/JohannesProgrammiert)!)
|
||||
* Add `PlotUi::response()` to replace `plot_clicked()` etc [#3223](https://github.com/emilk/egui/pull/3223)
|
||||
* Add rotation feature to plot images [#3121](https://github.com/emilk/egui/pull/3121) (thanks [@ThundR67](https://github.com/ThundR67)!)
|
||||
* Plot items: Image rotation and size in plot coordinates, polygon fill color [#3182](https://github.com/emilk/egui/pull/3182) (thanks [@s-nie](https://github.com/s-nie)!)
|
||||
* Add method to specify `tip_size` of plot arrows [#3138](https://github.com/emilk/egui/pull/3138) (thanks [@nagua](https://github.com/nagua)!)
|
||||
* Better handle additive colors in plots [#3387](https://github.com/emilk/egui/pull/3387)
|
||||
* Fix auto_bounds when only one axis has restricted navigation [#3171](https://github.com/emilk/egui/pull/3171) (thanks [@KoffeinFlummi](https://github.com/KoffeinFlummi)!)
|
||||
* Fix plot formatter not taking closures [#3260](https://github.com/emilk/egui/pull/3260) (thanks [@Wumpf](https://github.com/Wumpf)!)
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
[package]
|
||||
name = "egui_plot"
|
||||
version = "0.22.0"
|
||||
authors = [
|
||||
"Dominik Rössler <dominik@freshx.de>",
|
||||
"Emil Ernerfeldt <emil.ernerfeldt@gmail.com>",
|
||||
"René Rössler <rene@freshx.de>",
|
||||
]
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Immediate mode plotting for the egui GUI library"
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
@@ -32,7 +28,7 @@ serde = ["dep:serde", "egui/serde"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.22.0", path = "../egui", default-features = false }
|
||||
egui = { version = "0.23.0", path = "../egui", default-features = false }
|
||||
|
||||
|
||||
#! ### Optional dependencies
|
||||
|
||||
@@ -47,6 +47,7 @@ impl PlotPoint {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Solid, dotted, dashed, etc.
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum LineStyle {
|
||||
Solid,
|
||||
@@ -319,6 +320,7 @@ impl PlotPoints {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Circle, Diamond, Square, Cross, …
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum MarkerShape {
|
||||
Circle,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Simple plotting library.
|
||||
//! Simple plotting library for [`egui`](https://github.com/emilk/egui).
|
||||
//!
|
||||
//! ## Feature flags
|
||||
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
|
||||
@@ -77,6 +77,7 @@ impl Default for CoordinatesFormatter {
|
||||
|
||||
const MIN_LINE_SPACING_IN_POINTS: f64 = 6.0; // TODO(emilk): large enough for a wide label
|
||||
|
||||
/// Two bools, one for each axis (X and Y).
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct AxisBools {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "emath"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Minimal 2D math library for GUI work"
|
||||
edition = "2021"
|
||||
|
||||
@@ -5,6 +5,17 @@ This file is updated upon each release.
|
||||
Changes since the last release can be found by running the `scripts/generate_changelog.py` script.
|
||||
|
||||
|
||||
## 0.23.0 - 2023-09-27
|
||||
* Update MSRV to Rust 1.70.0 [#3310](https://github.com/emilk/egui/pull/3310)
|
||||
* Add option to truncate text at wrap width [#3244](https://github.com/emilk/egui/pull/3244) [#3366](https://github.com/emilk/egui/pull/3366)
|
||||
* Add control of line height and letter spacing [#3302](https://github.com/emilk/egui/pull/3302)
|
||||
* Support images with rounded corners [#3257](https://github.com/emilk/egui/pull/3257)
|
||||
* Add `ColorImage::from_gray` [#3166](https://github.com/emilk/egui/pull/3166) (thanks [@thomaseliot](https://github.com/thomaseliot)!)
|
||||
* Provide `into_inner()` for `egui::mutex::{Mutex, RwLock}` [#3110](https://github.com/emilk/egui/pull/3110) (thanks [@KmolYuan](https://github.com/KmolYuan)!)
|
||||
* Fix problems with tabs in text [#3355](https://github.com/emilk/egui/pull/3355)
|
||||
* Refactor: change `ClippedShape` from struct-enum to a normal struct [#3225](https://github.com/emilk/egui/pull/3225)
|
||||
* Document when `Galley`s get invalidated [#3024](https://github.com/emilk/egui/pull/3024) (thanks [@e00E](https://github.com/e00E)!)
|
||||
|
||||
|
||||
## 0.22.0 - 2023-05-23
|
||||
* Fix compiling `epaint` without `bytemuck` dependency [#2913](https://github.com/emilk/egui/pull/2913) (thanks [@lunixbochs](https://github.com/lunixbochs)!)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "epaint"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Minimal 2D graphics library for GUI work"
|
||||
edition = "2021"
|
||||
@@ -70,8 +70,8 @@ serde = ["dep:serde", "ahash/serde", "emath/serde", "ecolor/serde"]
|
||||
unity = []
|
||||
|
||||
[dependencies]
|
||||
emath = { version = "0.22.0", path = "../emath" }
|
||||
ecolor = { version = "0.22.0", path = "../ecolor" }
|
||||
emath = { version = "0.23.0", path = "../emath" }
|
||||
ecolor = { version = "0.23.0", path = "../ecolor" }
|
||||
|
||||
ab_glyph = "0.2.11"
|
||||
ahash = { version = "0.8.1", default-features = false, features = [
|
||||
|
||||
@@ -498,6 +498,8 @@ pub struct RectShape {
|
||||
///
|
||||
/// To display a texture, set [`Self::fill_texture_id`],
|
||||
/// and set this to `Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0))`.
|
||||
///
|
||||
/// Use [`Rect::ZERO`] to turn off texturing.
|
||||
pub uv: Rect,
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ pub struct FontImpl {
|
||||
height_in_points: f32,
|
||||
|
||||
// move each character by this much (hack)
|
||||
y_offset: f32,
|
||||
y_offset_in_points: f32,
|
||||
|
||||
ascent: f32,
|
||||
pixels_per_point: f32,
|
||||
@@ -111,22 +111,23 @@ impl FontImpl {
|
||||
scale_in_points * tweak.y_offset_factor
|
||||
} + tweak.y_offset;
|
||||
|
||||
// center scaled glyphs properly
|
||||
let y_offset_points = y_offset_points + (tweak.scale - 1.0) * 0.5 * (ascent + descent);
|
||||
// Center scaled glyphs properly:
|
||||
let height = ascent + descent;
|
||||
let y_offset_points = y_offset_points - (1.0 - tweak.scale) * 0.5 * height;
|
||||
|
||||
// Round to an even number of physical pixels to get even kerning.
|
||||
// See https://github.com/emilk/egui/issues/382
|
||||
let scale_in_pixels = scale_in_pixels.round() as u32;
|
||||
|
||||
// Round to closest pixel:
|
||||
let y_offset = (y_offset_points * pixels_per_point).round() / pixels_per_point;
|
||||
let y_offset_in_points = (y_offset_points * pixels_per_point).round() / pixels_per_point;
|
||||
|
||||
Self {
|
||||
name,
|
||||
ab_glyph_font,
|
||||
scale_in_pixels,
|
||||
height_in_points: ascent - descent + line_gap,
|
||||
y_offset,
|
||||
y_offset_in_points,
|
||||
ascent: ascent + baseline_offset,
|
||||
pixels_per_point,
|
||||
glyph_info_cache: Default::default(),
|
||||
@@ -283,7 +284,8 @@ impl FontImpl {
|
||||
});
|
||||
|
||||
let offset_in_pixels = vec2(bb.min.x, bb.min.y);
|
||||
let offset = offset_in_pixels / self.pixels_per_point + self.y_offset * Vec2::Y;
|
||||
let offset =
|
||||
offset_in_pixels / self.pixels_per_point + self.y_offset_in_points * Vec2::Y;
|
||||
UvRect {
|
||||
offset,
|
||||
size: vec2(glyph_width as f32, glyph_height as f32) / self.pixels_per_point,
|
||||
|
||||
Reference in New Issue
Block a user