mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 04:40:03 -04:00
Add Harness::new_ui, Harness::fit_contents (#5301)
This adds a `Harness::new_ui`, which accepts a Ui closure and shows the ui in a central panel. One big benefit is that this allows us to add a fit_contents method that can run the ui closure with a sizing pass and resize the "screen" based on the content size. I also used this to add a snapshot test for the rendering_test at different scales.
This commit is contained in:
@@ -11,6 +11,7 @@ mod snapshot;
|
||||
#[cfg(feature = "snapshot")]
|
||||
pub use snapshot::*;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
mod app_kind;
|
||||
#[cfg(feature = "wgpu")]
|
||||
mod texture_to_image;
|
||||
#[cfg(feature = "wgpu")]
|
||||
@@ -19,6 +20,7 @@ pub mod wgpu;
|
||||
pub use kittest;
|
||||
use std::mem;
|
||||
|
||||
use crate::app_kind::AppKind;
|
||||
use crate::event::EventState;
|
||||
pub use builder::*;
|
||||
use egui::{Pos2, Rect, TexturesDelta, Vec2, ViewportId};
|
||||
@@ -32,8 +34,9 @@ pub struct Harness<'a> {
|
||||
kittest: kittest::State,
|
||||
output: egui::FullOutput,
|
||||
texture_deltas: Vec<TexturesDelta>,
|
||||
update_fn: Box<dyn FnMut(&egui::Context) + 'a>,
|
||||
app: AppKind<'a>,
|
||||
event_state: EventState,
|
||||
response: Option<egui::Response>,
|
||||
}
|
||||
|
||||
impl<'a> Debug for Harness<'a> {
|
||||
@@ -43,10 +46,7 @@ impl<'a> Debug for Harness<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Harness<'a> {
|
||||
pub(crate) fn from_builder(
|
||||
builder: &HarnessBuilder,
|
||||
mut app: impl FnMut(&egui::Context) + 'a,
|
||||
) -> Self {
|
||||
pub(crate) fn from_builder(builder: &HarnessBuilder, mut app: AppKind<'a>) -> Self {
|
||||
let ctx = egui::Context::default();
|
||||
ctx.enable_accesskit();
|
||||
let mut input = egui::RawInput {
|
||||
@@ -54,14 +54,18 @@ impl<'a> Harness<'a> {
|
||||
..Default::default()
|
||||
};
|
||||
let viewport = input.viewports.get_mut(&ViewportId::ROOT).unwrap();
|
||||
viewport.native_pixels_per_point = Some(builder.dpi);
|
||||
viewport.native_pixels_per_point = Some(builder.pixels_per_point);
|
||||
|
||||
let mut response = None;
|
||||
|
||||
// We need to run egui for a single frame so that the AccessKit state can be initialized
|
||||
// and users can immediately start querying for widgets.
|
||||
let mut output = ctx.run(input.clone(), &mut app);
|
||||
let mut output = ctx.run(input.clone(), |ctx| {
|
||||
response = app.run(ctx);
|
||||
});
|
||||
|
||||
let mut harness = Self {
|
||||
update_fn: Box::new(app),
|
||||
app,
|
||||
ctx,
|
||||
input,
|
||||
kittest: kittest::State::new(
|
||||
@@ -73,6 +77,7 @@ impl<'a> Harness<'a> {
|
||||
),
|
||||
texture_deltas: vec![mem::take(&mut output.textures_delta)],
|
||||
output,
|
||||
response,
|
||||
event_state: EventState::default(),
|
||||
};
|
||||
// Run the harness until it is stable, ensuring that all Areas are shown and animations are done
|
||||
@@ -86,7 +91,9 @@ impl<'a> Harness<'a> {
|
||||
|
||||
/// Create a new Harness with the given app closure.
|
||||
///
|
||||
/// The ui closure will immediately be called once to create the initial ui.
|
||||
/// The app closure will immediately be called once to create the initial ui.
|
||||
///
|
||||
/// If you don't need to create Windows / Panels, you can use [`Harness::new_ui`] instead.
|
||||
///
|
||||
/// If you e.g. want to customize the size of the window, you can use [`Harness::builder`].
|
||||
///
|
||||
@@ -104,6 +111,25 @@ impl<'a> Harness<'a> {
|
||||
Self::builder().build(app)
|
||||
}
|
||||
|
||||
/// Create a new Harness with the given ui closure.
|
||||
///
|
||||
/// The ui closure will immediately be called once to create the initial ui.
|
||||
///
|
||||
/// If you need to create Windows / Panels, you can use [`Harness::new`] instead.
|
||||
///
|
||||
/// If you e.g. want to customize the size of the ui, you can use [`Harness::builder`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use egui_kittest::Harness;
|
||||
/// let mut harness = Harness::new_ui(|ui| {
|
||||
/// ui.label("Hello, world!");
|
||||
/// });
|
||||
/// ```
|
||||
pub fn new_ui(app: impl FnMut(&mut egui::Ui) + 'a) -> Self {
|
||||
Self::builder().build_ui(app)
|
||||
}
|
||||
|
||||
/// Set the size of the window.
|
||||
/// Note: If you only want to set the size once at the beginning,
|
||||
/// prefer using [`HarnessBuilder::with_size`].
|
||||
@@ -113,25 +139,35 @@ impl<'a> Harness<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the DPI of the window.
|
||||
/// Note: If you only want to set the DPI once at the beginning,
|
||||
/// prefer using [`HarnessBuilder::with_dpi`].
|
||||
/// Set the `pixels_per_point` of the window.
|
||||
/// Note: If you only want to set the `pixels_per_point` once at the beginning,
|
||||
/// prefer using [`HarnessBuilder::with_pixels_per_point`].
|
||||
#[inline]
|
||||
pub fn set_dpi(&mut self, dpi: f32) -> &mut Self {
|
||||
self.ctx.set_pixels_per_point(dpi);
|
||||
pub fn set_pixels_per_point(&mut self, pixels_per_point: f32) -> &mut Self {
|
||||
self.ctx.set_pixels_per_point(pixels_per_point);
|
||||
self
|
||||
}
|
||||
|
||||
/// Run a frame.
|
||||
/// This will call the app closure with the current context and update the Harness.
|
||||
pub fn step(&mut self) {
|
||||
self._step(false);
|
||||
}
|
||||
|
||||
fn _step(&mut self, sizing_pass: bool) {
|
||||
for event in self.kittest.take_events() {
|
||||
if let Some(event) = self.event_state.kittest_event_to_egui(event) {
|
||||
self.input.events.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = self.ctx.run(self.input.take(), self.update_fn.as_mut());
|
||||
let mut output = self.ctx.run(self.input.take(), |ctx| {
|
||||
if sizing_pass {
|
||||
self.response = self.app.run_sizing_pass(ctx);
|
||||
} else {
|
||||
self.response = self.app.run(ctx);
|
||||
}
|
||||
});
|
||||
self.kittest.update(
|
||||
output
|
||||
.platform_output
|
||||
@@ -144,6 +180,16 @@ impl<'a> Harness<'a> {
|
||||
self.output = output;
|
||||
}
|
||||
|
||||
/// Resize the test harness to fit the contents. This only works when creating the Harness via
|
||||
/// [`Harness::new_ui`] or [`HarnessBuilder::build_ui`].
|
||||
pub fn fit_contents(&mut self) {
|
||||
self._step(true);
|
||||
if let Some(response) = &self.response {
|
||||
self.set_size(response.rect.size());
|
||||
}
|
||||
self.run();
|
||||
}
|
||||
|
||||
/// Run a few frames.
|
||||
/// This will soon be changed to run the app until it is "stable", meaning
|
||||
/// - all animations are done
|
||||
|
||||
Reference in New Issue
Block a user