1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-27 23:13:13 -04:00

Introduce ViewportInfo

This commit is contained in:
Konkitoman
2023-11-08 07:29:00 +02:00
parent 0d7c87836c
commit 12f3782721
12 changed files with 102 additions and 106 deletions

View File

@@ -492,11 +492,11 @@ impl EpiIntegration {
self.frame.info.window_info =
read_window_info(window, self.egui_ctx.pixels_per_point(), &self.window_state);
let mut raw_input = egui_winit.take_egui_input(window);
let mut raw_input = egui_winit.take_egui_input(window, id_pair);
raw_input.time = Some(self.beginning.elapsed().as_secs_f64());
// Run user code:
let full_output = self.egui_ctx.run(raw_input, id_pair, |egui_ctx| {
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
crate::profile_scope!("App::update");
if let Some(viewport_ui_cb) = viewport_ui_cb {
// Child viewport

View File

@@ -1196,9 +1196,9 @@ mod glow_integration {
return;
};
let win = win.borrow();
let mut input = winit_state.take_egui_input(&win);
let mut input = winit_state.take_egui_input(&win, id_pair);
input.time = Some(beginning.elapsed().as_secs_f64());
let output = egui_ctx.run(input, id_pair, |ctx| {
let output = egui_ctx.run(input, |ctx| {
viewport_ui_cb(ctx);
});
@@ -2323,9 +2323,9 @@ mod wgpu_integration {
return;
};
let win = window.borrow();
let mut input = winit_state.take_egui_input(&win);
let mut input = winit_state.take_egui_input(&win, id_pair);
input.time = Some(beginning.elapsed().as_secs_f64());
let output = egui_ctx.run(input, id_pair, |ctx| {
let output = egui_ctx.run(input, |ctx| {
viewport_ui_cb(ctx);
});

View File

@@ -14,7 +14,7 @@ pub use accesskit_winit;
pub use egui;
#[cfg(feature = "accesskit")]
use egui::accesskit;
use egui::{Pos2, Rect, Vec2, ViewportBuilder, ViewportCommand, ViewportId};
use egui::{Pos2, Rect, Vec2, ViewportBuilder, ViewportCommand, ViewportId, ViewportIdPair};
pub use winit;
pub mod clipboard;
@@ -177,7 +177,11 @@ impl State {
/// Prepare for a new frame by extracting the accumulated input,
/// as well as setting [the time](egui::RawInput::time) and [screen rectangle](egui::RawInput::screen_rect).
pub fn take_egui_input(&mut self, window: &winit::window::Window) -> egui::RawInput {
pub fn take_egui_input(
&mut self,
window: &winit::window::Window,
id_pair: ViewportIdPair,
) -> egui::RawInput {
let pixels_per_point = self.pixels_per_point();
self.egui_input.time = Some(self.start_time.elapsed().as_secs_f64());
@@ -237,17 +241,20 @@ impl State {
None
};
self.egui_input.inner_rect = if let (Some(pos), Some(size)) = (inner_pos, inner_size) {
Some(Rect::from_min_size(pos, size))
} else {
None
};
self.egui_input.viewport.id_pair = id_pair;
self.egui_input.viewport.inner_rect =
if let (Some(pos), Some(size)) = (inner_pos, inner_size) {
Some(Rect::from_min_size(pos, size))
} else {
None
};
self.egui_input.outer_rect = if let (Some(pos), Some(size)) = (outer_pos, outer_size) {
Some(Rect::from_min_size(pos, size))
} else {
None
};
self.egui_input.viewport.outer_rect =
if let (Some(pos), Some(size)) = (outer_pos, outer_size) {
Some(Rect::from_min_size(pos, size))
} else {
None
};
self.egui_input.take()
}

View File

@@ -190,7 +190,9 @@ struct ContextImpl {
}
impl ContextImpl {
fn begin_frame_mut(&mut self, mut new_raw_input: RawInput, id_pair: ViewportIdPair) {
fn begin_frame_mut(&mut self, mut new_raw_input: RawInput) {
let id_pair = new_raw_input.viewport.id_pair;
let viewport_id = id_pair.this;
self.viewport_stack.push(id_pair);
self.output.entry(self.viewport_id()).or_default();
@@ -461,15 +463,10 @@ impl Context {
/// // handle full_output
/// ```
#[must_use]
pub fn run(
&self,
new_input: RawInput,
id_pair: ViewportIdPair,
run_ui: impl FnOnce(&Context),
) -> FullOutput {
pub fn run(&self, new_input: RawInput, run_ui: impl FnOnce(&Context)) -> FullOutput {
crate::profile_function!();
self.begin_frame(new_input, id_pair);
self.begin_frame(new_input);
run_ui(self);
self.end_frame()
}
@@ -491,10 +488,10 @@ impl Context {
/// let full_output = ctx.end_frame();
/// // handle full_output
/// ```
pub fn begin_frame(&self, new_input: RawInput, id_pair: ViewportIdPair) {
pub fn begin_frame(&self, new_input: RawInput) {
crate::profile_function!();
self.write(|ctx| ctx.begin_frame_mut(new_input, id_pair));
self.write(|ctx| ctx.begin_frame_mut(new_input));
}
}
@@ -1676,18 +1673,6 @@ impl Context {
self.input(|i| i.screen_rect())
}
/// Viewport inner position and size, only the drowable area
/// unit = physical pixels
pub fn inner_rect(&self) -> Rect {
self.input(|i| i.inner_rect)
}
/// Viewport outer position and size, drowable area + decorations
/// unit = physical pixels
pub fn outer_rect(&self) -> Rect {
self.input(|i| i.outer_rect)
}
/// How much space is still available after panels has been added.
///
/// This is the "background" area, what egui doesn't cover with panels (but may cover with windows).

View File

@@ -1,6 +1,6 @@
//! The input needed by egui.
use crate::emath::*;
use crate::{emath::*, ViewportIdPair};
/// What the integrations provides to egui at the start of each frame.
///
@@ -13,6 +13,8 @@ use crate::emath::*;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct RawInput {
pub viewport: ViewportInfo,
/// Position and size of the area that egui should use, in points.
/// Usually you would set this to
///
@@ -23,14 +25,6 @@ pub struct RawInput {
/// `None` will be treated as "same as last frame", with the default being a very big area.
pub screen_rect: Option<Rect>,
/// Viewport inner position and size, only the drowable area
/// unit = physical pixels
pub inner_rect: Option<Rect>,
/// Viewport outer position and size, drowable area + decorations
/// unit = physical pixels
pub outer_rect: Option<Rect>,
/// Also known as device pixel ratio, > 1 for high resolution screens.
/// If text looks blurry you probably forgot to set this.
/// Set this the first frame, whenever it changes, or just on every frame.
@@ -81,8 +75,6 @@ impl Default for RawInput {
fn default() -> Self {
Self {
screen_rect: None,
inner_rect: None,
outer_rect: None,
pixels_per_point: None,
max_texture_side: None,
time: None,
@@ -91,7 +83,8 @@ impl Default for RawInput {
events: vec![],
hovered_files: Default::default(),
dropped_files: Default::default(),
focused: true, // integrations opt into global focus tracking
focused: true,
viewport: ViewportInfo::default(), // integrations opt into global focus tracking
}
}
}
@@ -104,8 +97,6 @@ impl RawInput {
pub fn take(&mut self) -> RawInput {
RawInput {
screen_rect: self.screen_rect.take(),
inner_rect: self.inner_rect.take(),
outer_rect: self.outer_rect.take(),
pixels_per_point: self.pixels_per_point.take(),
max_texture_side: self.max_texture_side.take(),
time: self.time.take(),
@@ -115,6 +106,7 @@ impl RawInput {
hovered_files: self.hovered_files.clone(),
dropped_files: std::mem::take(&mut self.dropped_files),
focused: self.focused,
viewport: self.viewport.take(),
}
}
@@ -122,8 +114,6 @@ impl RawInput {
pub fn append(&mut self, newer: Self) {
let Self {
screen_rect,
inner_rect,
outer_rect,
pixels_per_point,
max_texture_side,
time,
@@ -133,13 +123,13 @@ impl RawInput {
mut hovered_files,
mut dropped_files,
focused,
viewport,
} = newer;
self.screen_rect = screen_rect.or(self.screen_rect);
self.inner_rect = inner_rect.or(self.inner_rect);
self.outer_rect = outer_rect.or(self.outer_rect);
self.pixels_per_point = pixels_per_point.or(self.pixels_per_point);
self.max_texture_side = max_texture_side.or(self.max_texture_side);
self.viewport = viewport;
self.time = time; // use latest time
self.predicted_dt = predicted_dt; // use latest dt
self.modifiers = modifiers; // use latest
@@ -150,6 +140,26 @@ impl RawInput {
}
}
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ViewportInfo {
pub id_pair: ViewportIdPair,
/// Viewport inner position and size, only the drowable area
/// unit = physical pixels
pub inner_rect: Option<Rect>,
/// Viewport outer position and size, drowable area + decorations
/// unit = physical pixels
pub outer_rect: Option<Rect>,
}
impl ViewportInfo {
pub fn take(&mut self) -> Self {
core::mem::take(self)
}
}
/// A file about to be dropped into egui.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
@@ -958,8 +968,6 @@ impl RawInput {
pub fn ui(&self, ui: &mut crate::Ui) {
let Self {
screen_rect,
inner_rect,
outer_rect,
pixels_per_point,
max_texture_side,
time,
@@ -969,11 +977,11 @@ impl RawInput {
hovered_files,
dropped_files,
focused,
viewport,
} = self;
viewport.ui(ui);
ui.label(format!("screen_rect: {screen_rect:?} points"));
ui.label(format!("inner_rect: {inner_rect:?} pixels"));
ui.label(format!("outer_rect: {outer_rect:?} pixels"));
ui.label(format!("pixels_per_point: {pixels_per_point:?}"))
.on_hover_text(
"Also called HDPI factor.\nNumber of physical pixels per each logical pixel.",
@@ -997,6 +1005,14 @@ impl RawInput {
}
}
impl ViewportInfo {
pub fn ui(&self, ui: &mut crate::Ui) {
ui.label(format!("id_pair: {:?}", self.id_pair));
ui.label(format!("inner_rect: {:?}", self.inner_rect));
ui.label(format!("outer_rect: {:?}", self.outer_rect));
}
}
/// this is a `u64` as values of this kind can always be obtained by hashing
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]

View File

@@ -54,14 +54,6 @@ pub struct InputState {
/// Position and size of the egui area.
pub screen_rect: Rect,
/// Viewport inner position and size, only the drowable area
/// unit = physical pixels
pub inner_rect: Rect,
/// Viewport outer position and size, drowable area + decorations
/// unit = physical pixels
pub outer_rect: Rect,
/// Also known as device pixel ratio, > 1 for high resolution screens.
pub pixels_per_point: f32,
@@ -146,8 +138,6 @@ impl Default for InputState {
modifiers: Default::default(),
keys_down: Default::default(),
events: Default::default(),
inner_rect: Rect::ZERO,
outer_rect: Rect::ZERO,
}
}
}
@@ -172,8 +162,6 @@ impl InputState {
};
let screen_rect = new.screen_rect.unwrap_or(self.screen_rect);
let inner_rect = new.inner_rect.unwrap_or(self.inner_rect);
let outer_rect = new.outer_rect.unwrap_or(self.outer_rect);
self.create_touch_states_for_new_devices(&new.events);
for touch_state in self.touch_states.values_mut() {
@@ -229,8 +217,6 @@ impl InputState {
scroll_delta,
zoom_factor_delta,
screen_rect,
inner_rect,
outer_rect,
pixels_per_point: new.pixels_per_point.unwrap_or(self.pixels_per_point),
max_texture_side: new.max_texture_side.unwrap_or(self.max_texture_side),
time,
@@ -997,8 +983,6 @@ impl InputState {
scroll_delta,
zoom_factor_delta,
screen_rect,
inner_rect,
outer_rect,
pixels_per_point,
max_texture_side,
time,
@@ -1034,8 +1018,6 @@ impl InputState {
ui.label(format!("scroll_delta: {scroll_delta:?} points"));
ui.label(format!("zoom_factor_delta: {zoom_factor_delta:4.2}x"));
ui.label(format!("screen_rect: {screen_rect:?} points"));
ui.label(format!("inner_rect: {inner_rect:?} pixels"));
ui.label(format!("outer_rect: {outer_rect:?} pixels"));
ui.label(format!(
"{pixels_per_point} physical pixels for each logical point"
));

View File

@@ -606,7 +606,7 @@ pub enum WidgetType {
pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), ViewportIdPair::ROOT, |ctx| {
let _ = ctx.run(Default::default(), |ctx| {
run_ui(ctx);
});
}
@@ -615,7 +615,7 @@ pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
pub fn __run_test_ui(mut add_contents: impl FnMut(&mut Ui)) {
let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), ViewportIdPair::ROOT, |ctx| {
let _ = ctx.run(Default::default(), |ctx| {
crate::CentralPanel::default().show(ctx, |ui| {
add_contents(ui);
});

View File

@@ -19,6 +19,7 @@ use crate::{Context, Id};
///
/// This is returned by [`Context::viewport_id`] and [`Context::parent_viewport_id`].
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ViewportId(pub Id);
impl Default for ViewportId {
@@ -63,6 +64,7 @@ pub type ViewportIdMap<T> = nohash_hasher::IntMap<ViewportId, T>;
/// A pair of [`ViewportId`], used to identify a viewport and its parent.
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ViewportIdPair {
pub this: ViewportId,
pub parent: ViewportId,

View File

@@ -1,6 +1,6 @@
use criterion::{criterion_group, criterion_main, Criterion};
use egui::{epaint::TextShape, ViewportId, ViewportIdPair};
use egui::{epaint::TextShape, ViewportId};
use egui_demo_lib::LOREM_IPSUM_LONG;
pub fn criterion_benchmark(c: &mut Criterion) {
@@ -13,7 +13,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
// The most end-to-end benchmark.
c.bench_function("demo_with_tessellate__realistic", |b| {
b.iter(|| {
let full_output = ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| {
let full_output = ctx.run(RawInput::default(), |ctx| {
demo_windows.ui(ctx);
});
ctx.tessellate(full_output.shapes, ViewportId::ROOT)
@@ -22,13 +22,13 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("demo_no_tessellate", |b| {
b.iter(|| {
ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| {
ctx.run(RawInput::default(), |ctx| {
demo_windows.ui(ctx);
})
});
});
let full_output = ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| {
let full_output = ctx.run(RawInput::default(), |ctx| {
demo_windows.ui(ctx);
});
c.bench_function("demo_only_tessellate", |b| {
@@ -42,7 +42,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let mut demo_windows = egui_demo_lib::DemoWindows::default();
c.bench_function("demo_full_no_tessellate", |b| {
b.iter(|| {
ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| {
ctx.run(RawInput::default(), |ctx| {
demo_windows.ui(ctx);
})
});
@@ -51,7 +51,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{
let ctx = egui::Context::default();
let _ = ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| {
let _ = ctx.run(RawInput::default(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
c.bench_function("label &str", |b| {
b.iter(|| {
@@ -69,7 +69,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{
let ctx = egui::Context::default();
ctx.begin_frame(RawInput::default(), ViewportIdPair::ROOT);
ctx.begin_frame(RawInput::default());
egui::CentralPanel::default().show(&ctx, |ui| {
c.bench_function("Painter::rect", |b| {

View File

@@ -19,7 +19,7 @@ pub mod easy_mark;
pub use color_test::ColorTest;
pub use demo::DemoWindows;
#[cfg(test)]
use egui::{ViewportId, ViewportIdPair};
use egui::ViewportId;
/// View some Rust code with syntax highlighting and selection.
pub(crate) fn rust_view_ui(ui: &mut egui::Ui, code: &str) {
@@ -76,7 +76,7 @@ fn test_egui_e2e() {
const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES {
let full_output = ctx.run(raw_input.clone(), ViewportIdPair::ROOT, |ctx| {
let full_output = ctx.run(raw_input.clone(), |ctx| {
demo_windows.ui(ctx);
});
let clipped_primitives = ctx.tessellate(full_output.shapes, ViewportId::ROOT);
@@ -95,7 +95,7 @@ fn test_egui_zero_window_size() {
const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES {
let full_output = ctx.run(raw_input.clone(), ViewportIdPair::ROOT, |ctx| {
let full_output = ctx.run(raw_input.clone(), |ctx| {
demo_windows.ui(ctx);
});
let clipped_primitives = ctx.tessellate(full_output.shapes, ViewportId::ROOT);

View File

@@ -47,13 +47,15 @@ impl EguiGlow {
/// Call [`Self::paint`] later to paint.
pub fn run(&mut self, window: &winit::window::Window, run_ui: impl FnMut(&egui::Context)) {
let raw_input = self.egui_winit.take_egui_input(window);
let raw_input = self
.egui_winit
.take_egui_input(window, ViewportIdPair::ROOT);
let egui::FullOutput {
platform_output,
textures_delta,
shapes,
..
} = self.egui_ctx.run(raw_input, ViewportIdPair::ROOT, run_ui);
} = self.egui_ctx.run(raw_input, run_ui);
self.egui_winit.handle_platform_output(
window,

View File

@@ -197,18 +197,20 @@ fn generic_ui(ui: &mut egui::Ui, children: &[Arc<RwLock<ViewportState>>]) {
ui.add_space(8.0);
let inner_rect = ctx.inner_rect();
ui.label(format!(
"Inner Rect: Pos: {:?}, Size: {:?}",
inner_rect.min,
inner_rect.size()
));
let outer_rect = ctx.outer_rect();
ui.label(format!(
"Outer Rect: Pos: {:?}, Size: {:?}",
outer_rect.min,
outer_rect.size()
));
if let Some(inner_rect) = ctx.input(|i| i.raw.viewport.inner_rect) {
ui.label(format!(
"Inner Rect: Pos: {:?}, Size: {:?}",
inner_rect.min,
inner_rect.size()
));
}
if let Some(outer_rect) = ctx.input(|i| i.raw.viewport.outer_rect) {
ui.label(format!(
"Outer Rect: Pos: {:?}, Size: {:?}",
outer_rect.min,
outer_rect.size()
));
}
let tmp_pixels_per_point = ctx.pixels_per_point();
let mut pixels_per_point = ui.data_mut(|data| {