mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
Merge remote-tracking branch 'origin/master' into default_affects_opacity
This commit is contained in:
@@ -5,10 +5,10 @@ authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
description = "Example library for egui"
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
homepage = "https://github.com/emilk/egui/tree/master/crates/egui_demo_lib"
|
||||
homepage = "https://github.com/emilk/egui/tree/main/crates/egui_demo_lib"
|
||||
license.workspace = true
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/emilk/egui/tree/master/crates/egui_demo_lib"
|
||||
repository = "https://github.com/emilk/egui/tree/main/crates/egui_demo_lib"
|
||||
categories = ["gui", "graphics"]
|
||||
keywords = ["glow", "egui", "gui", "gamedev"]
|
||||
include = [
|
||||
@@ -16,7 +16,7 @@ include = [
|
||||
"../LICENSE-MIT",
|
||||
"**/*.rs",
|
||||
"Cargo.toml",
|
||||
"data/icon.png",
|
||||
"data/*",
|
||||
]
|
||||
|
||||
[lints]
|
||||
@@ -43,7 +43,7 @@ syntect = ["egui_extras/syntect"]
|
||||
|
||||
[dependencies]
|
||||
egui = { workspace = true, default-features = false, features = ["color-hex"] }
|
||||
egui_extras = { workspace = true, features = ["default"] }
|
||||
egui_extras = { workspace = true, features = ["image", "svg"] }
|
||||
|
||||
unicode_names2 = { version = "0.6.0", default-features = false } # this old version has fewer dependencies
|
||||
|
||||
@@ -56,8 +56,11 @@ serde = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion.workspace = true
|
||||
egui_kittest = { workspace = true, features = ["wgpu", "snapshot"] }
|
||||
egui = { workspace = true, features = ["default_fonts"] }
|
||||
egui_extras = { workspace = true, features = ["image", "svg"] }
|
||||
egui_kittest = { workspace = true, features = ["wgpu", "snapshot"] }
|
||||
image = { workspace = true, features = ["png"] }
|
||||
mimalloc.workspace = true # for benchmarks
|
||||
rand = "0.9"
|
||||
|
||||
[[bench]]
|
||||
|
||||
@@ -14,3 +14,19 @@ The demo library is a separate crate for three reasons:
|
||||
* To remove the amount of code in `egui` proper.
|
||||
* To make it easy for 3rd party egui integrations to use it for tests.
|
||||
- See for instance https://github.com/not-fl3/egui-miniquad/blob/master/examples/demo.rs
|
||||
|
||||
This crate also contains benchmarks for egui.
|
||||
Run them with
|
||||
```bash
|
||||
# Run all benchmarks
|
||||
cargo bench -p egui_demo_lib
|
||||
|
||||
# Run a single benchmark
|
||||
cargo bench -p egui_demo_lib "benchmark name"
|
||||
|
||||
# Profile benchmarks with cargo-flamegraph (--root flag is necessary for MacOS)
|
||||
CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --bench benchmark --root -p egui_demo_lib -- --bench "benchmark name"
|
||||
|
||||
# Profile with cargo-instruments
|
||||
CARGO_PROFILE_BENCH_DEBUG=true cargo instruments --profile bench --bench benchmark -p egui_demo_lib -t time -- --bench "benchmark name"
|
||||
```
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
||||
|
||||
use egui::epaint::TextShape;
|
||||
use egui::load::SizedTexture;
|
||||
use egui::{Button, Id, RichText, TextureId, Ui, UiBuilder, Vec2};
|
||||
use egui_demo_lib::LOREM_IPSUM_LONG;
|
||||
use rand::Rng as _;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; // Much faster allocator
|
||||
|
||||
/// Each iteration should be called in their own `Ui` with an intentional id clash,
|
||||
/// to prevent the Context from building a massive map of `WidgetRects` (which would slow the test,
|
||||
/// causing unreliable results).
|
||||
fn create_benchmark_ui(ctx: &egui::Context) -> Ui {
|
||||
Ui::new(ctx.clone(), Id::new("clashing_id"), UiBuilder::new())
|
||||
}
|
||||
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
use egui::RawInput;
|
||||
|
||||
@@ -55,17 +67,71 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
{
|
||||
let ctx = egui::Context::default();
|
||||
let _ = ctx.run(RawInput::default(), |ctx| {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
c.bench_function("label &str", |b| {
|
||||
b.iter(|| {
|
||||
c.bench_function("label &str", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| create_benchmark_ui(ctx),
|
||||
|ui| {
|
||||
ui.label("the quick brown fox jumps over the lazy dog");
|
||||
});
|
||||
});
|
||||
c.bench_function("label format!", |b| {
|
||||
b.iter(|| {
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
c.bench_function("label format!", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| create_benchmark_ui(ctx),
|
||||
|ui| {
|
||||
ui.label("the quick brown fox jumps over the lazy dog".to_owned());
|
||||
});
|
||||
});
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
let ctx = egui::Context::default();
|
||||
let _ = ctx.run(RawInput::default(), |ctx| {
|
||||
let mut group = c.benchmark_group("button");
|
||||
|
||||
// To ensure we have a valid image, let's use the font texture. The size
|
||||
// shouldn't be important for this benchmark.
|
||||
let image = SizedTexture::new(TextureId::default(), Vec2::splat(16.0));
|
||||
|
||||
group.bench_function("1_button_text", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| create_benchmark_ui(ctx),
|
||||
|ui| {
|
||||
ui.add(Button::new("Hello World"));
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
group.bench_function("2_button_text_image", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| create_benchmark_ui(ctx),
|
||||
|ui| {
|
||||
ui.add(Button::image_and_text(image, "Hello World"));
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
group.bench_function("3_button_text_image_right_text", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| create_benchmark_ui(ctx),
|
||||
|ui| {
|
||||
ui.add(Button::image_and_text(image, "Hello World").right_text("⏵"));
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
group.bench_function("4_button_italic", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| create_benchmark_ui(ctx),
|
||||
|ui| {
|
||||
ui.add(Button::new(RichText::new("Hello World").italics()));
|
||||
},
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
11
crates/egui_demo_lib/data/peace.svg
Normal file
11
crates/egui_demo_lib/data/peace.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 44 44" width="32" height="32">
|
||||
<g fill="none" stroke="white" stroke-width="3">
|
||||
<circle cx="22" cy="22" r="19"/>
|
||||
<path d="M 22,2 V 41"/>
|
||||
<path d="M 22,2 V 22" transform="rotate(135, 22, 22)"/>
|
||||
<path d="M 22,2 V 22" transform="rotate(225, 22, 22)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 437 B |
@@ -105,7 +105,7 @@ impl crate::Demo for CodeExample {
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
use crate::View;
|
||||
use crate::View as _;
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.min_width(375.0)
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::collections::BTreeSet;
|
||||
use super::About;
|
||||
use crate::is_mobile;
|
||||
use crate::Demo;
|
||||
use crate::View;
|
||||
use crate::View as _;
|
||||
use egui::containers::menu;
|
||||
use egui::style::StyleModifier;
|
||||
use egui::{Context, Modifiers, ScrollArea, Ui};
|
||||
@@ -13,6 +13,16 @@ struct DemoGroup {
|
||||
demos: Vec<Box<dyn Demo>>,
|
||||
}
|
||||
|
||||
impl std::ops::Add for DemoGroup {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
let mut demos = self.demos;
|
||||
demos.extend(other.demos);
|
||||
Self { demos }
|
||||
}
|
||||
}
|
||||
|
||||
impl DemoGroup {
|
||||
pub fn new(demos: Vec<Box<dyn Demo>>) -> Self {
|
||||
Self { demos }
|
||||
@@ -100,6 +110,7 @@ impl Default for DemoGroups {
|
||||
Box::<super::tests::InputTest>::default(),
|
||||
Box::<super::tests::LayoutTest>::default(),
|
||||
Box::<super::tests::ManualLayoutTest>::default(),
|
||||
Box::<super::tests::SvgTest>::default(),
|
||||
Box::<super::tests::TessellationTest>::default(),
|
||||
Box::<super::tests::WindowResizeTest>::default(),
|
||||
]),
|
||||
@@ -359,14 +370,19 @@ fn file_menu_button(ui: &mut Ui) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{demo::demo_app_windows::DemoGroups, Demo};
|
||||
use egui::Vec2;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
use crate::{demo::demo_app_windows::DemoGroups, Demo as _};
|
||||
|
||||
use egui_kittest::kittest::{NodeT as _, Queryable as _};
|
||||
use egui_kittest::{Harness, SnapshotOptions, SnapshotResults};
|
||||
|
||||
#[test]
|
||||
fn demos_should_match_snapshot() {
|
||||
let demos = DemoGroups::default().demos;
|
||||
let DemoGroups {
|
||||
demos,
|
||||
tests,
|
||||
about: _,
|
||||
} = DemoGroups::default();
|
||||
let demos = demos + tests;
|
||||
|
||||
let mut results = SnapshotResults::new();
|
||||
|
||||
@@ -376,22 +392,19 @@ mod tests {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the emoji from the demo name
|
||||
let name = demo
|
||||
.name()
|
||||
.split_once(' ')
|
||||
.map_or(demo.name(), |(_, name)| name);
|
||||
let name = remove_leading_emoji(demo.name());
|
||||
|
||||
let mut harness = Harness::new(|ctx| {
|
||||
egui_extras::install_image_loaders(ctx);
|
||||
demo.show(ctx, &mut true);
|
||||
});
|
||||
|
||||
let window = harness.node().children().next().unwrap();
|
||||
let window = harness.queryable_node().children().next().unwrap();
|
||||
// TODO(lucasmerlin): Windows should probably have a label?
|
||||
//let window = harness.get_by_label(name);
|
||||
|
||||
let size = window.raw_bounds().expect("window bounds").size();
|
||||
harness.set_size(Vec2::new(size.width as f32, size.height as f32));
|
||||
let size = window.rect().size();
|
||||
harness.set_size(size);
|
||||
|
||||
// Run the app for some more frames...
|
||||
harness.run_ok();
|
||||
@@ -405,4 +418,13 @@ mod tests {
|
||||
results.add(harness.try_snapshot_options(&format!("demos/{name}"), &options));
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_leading_emoji(full_name: &str) -> &str {
|
||||
if let Some((start, name)) = full_name.split_once(' ') {
|
||||
if start.len() <= 4 && start.bytes().next().is_some_and(|byte| byte >= 128) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
full_name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ fn char_name(chr: char) -> String {
|
||||
}
|
||||
|
||||
fn special_char_name(chr: char) -> Option<&'static str> {
|
||||
#[allow(clippy::match_same_arms)] // many "flag"
|
||||
#[expect(clippy::match_same_arms)] // many "flag"
|
||||
match chr {
|
||||
// Special private-use-area extensions found in `emoji-icon-font.ttf`:
|
||||
// Private use area extensions:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use egui::{Frame, Label, RichText, Sense, UiBuilder, Widget};
|
||||
use egui::{Frame, Label, RichText, Sense, UiBuilder, Widget as _};
|
||||
|
||||
/// Showcase [`egui::Ui::response`].
|
||||
#[derive(PartialEq, Eq, Default)]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::{Demo, View};
|
||||
|
||||
use egui::{
|
||||
vec2, Align, Checkbox, CollapsingHeader, Color32, Context, FontId, Resize, RichText, Sense,
|
||||
Slider, Stroke, TextFormat, TextStyle, Ui, Vec2, Window,
|
||||
vec2, Align, Align2, Checkbox, CollapsingHeader, Color32, ComboBox, Context, FontId, Resize,
|
||||
RichText, Sense, Slider, Stroke, TextFormat, TextStyle, Ui, Vec2, Window,
|
||||
};
|
||||
|
||||
/// Showcase some ui code
|
||||
@@ -16,6 +16,7 @@ pub struct MiscDemoWindow {
|
||||
custom_collapsing_header: CustomCollapsingHeader,
|
||||
tree: Tree,
|
||||
box_painting: BoxPainting,
|
||||
text_rotation: TextRotation,
|
||||
|
||||
dummy_bool: bool,
|
||||
dummy_usize: usize,
|
||||
@@ -32,6 +33,7 @@ impl Default for MiscDemoWindow {
|
||||
custom_collapsing_header: Default::default(),
|
||||
tree: Tree::demo(),
|
||||
box_painting: Default::default(),
|
||||
text_rotation: Default::default(),
|
||||
|
||||
dummy_bool: false,
|
||||
dummy_usize: 0,
|
||||
@@ -79,6 +81,10 @@ impl View for MiscDemoWindow {
|
||||
});
|
||||
});
|
||||
|
||||
CollapsingHeader::new("Text rotation")
|
||||
.default_open(false)
|
||||
.show(ui, |ui| self.text_rotation.ui(ui));
|
||||
|
||||
CollapsingHeader::new("Colors")
|
||||
.default_open(false)
|
||||
.show(ui, |ui| {
|
||||
@@ -729,3 +735,95 @@ fn text_layout_demo(ui: &mut Ui) {
|
||||
|
||||
ui.label(job);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
struct TextRotation {
|
||||
size: Vec2,
|
||||
angle: f32,
|
||||
align: egui::Align2,
|
||||
}
|
||||
|
||||
impl Default for TextRotation {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
size: vec2(200.0, 200.0),
|
||||
angle: 0.0,
|
||||
align: egui::Align2::LEFT_TOP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TextRotation {
|
||||
pub fn ui(&mut self, ui: &mut Ui) {
|
||||
ui.add(Slider::new(&mut self.angle, 0.0..=2.0 * std::f32::consts::PI).text("angle"));
|
||||
|
||||
let default_color = if ui.visuals().dark_mode {
|
||||
Color32::LIGHT_GRAY
|
||||
} else {
|
||||
Color32::DARK_GRAY
|
||||
};
|
||||
|
||||
let aligns = [
|
||||
(Align2::LEFT_TOP, "LEFT_TOP"),
|
||||
(Align2::LEFT_CENTER, "LEFT_CENTER"),
|
||||
(Align2::LEFT_BOTTOM, "LEFT_BOTTOM"),
|
||||
(Align2::CENTER_TOP, "CENTER_TOP"),
|
||||
(Align2::CENTER_CENTER, "CENTER_CENTER"),
|
||||
(Align2::CENTER_BOTTOM, "CENTER_BOTTOM"),
|
||||
(Align2::RIGHT_TOP, "RIGHT_TOP"),
|
||||
(Align2::RIGHT_CENTER, "RIGHT_CENTER"),
|
||||
(Align2::RIGHT_BOTTOM, "RIGHT_BOTTOM"),
|
||||
];
|
||||
|
||||
ComboBox::new("anchor", "Anchor")
|
||||
.selected_text(aligns.iter().find(|(a, _)| *a == self.align).unwrap().1)
|
||||
.show_ui(ui, |ui| {
|
||||
for (align2, name) in &aligns {
|
||||
ui.selectable_value(&mut self.align, *align2, *name);
|
||||
}
|
||||
});
|
||||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
let (response, painter) = ui.allocate_painter(self.size, Sense::empty());
|
||||
let rect = response.rect;
|
||||
|
||||
let start_pos = self.size / 2.0;
|
||||
|
||||
let s = ui.ctx().fonts(|f| {
|
||||
let mut t = egui::Shape::text(
|
||||
f,
|
||||
rect.min + start_pos,
|
||||
egui::Align2::LEFT_TOP,
|
||||
"sample_text",
|
||||
egui::FontId::new(12.0, egui::FontFamily::Proportional),
|
||||
default_color,
|
||||
);
|
||||
|
||||
if let egui::epaint::Shape::Text(ts) = &mut t {
|
||||
let new = ts.clone().with_angle_and_anchor(self.angle, self.align);
|
||||
*ts = new;
|
||||
};
|
||||
|
||||
t
|
||||
});
|
||||
|
||||
if let egui::epaint::Shape::Text(ts) = &s {
|
||||
let align_pt =
|
||||
rect.min + start_pos + self.align.pos_in_rect(&ts.galley.rect).to_vec2();
|
||||
painter.circle(align_pt, 2.0, Color32::RED, (0.0, Color32::RED));
|
||||
};
|
||||
|
||||
painter.rect(
|
||||
rect,
|
||||
0.0,
|
||||
default_color.gamma_multiply(0.3),
|
||||
(0.0, Color32::BLACK),
|
||||
egui::StrokeKind::Middle,
|
||||
);
|
||||
painter.add(s);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use egui::{ComboBox, Context, Id, Modal, ProgressBar, Ui, Widget, Window};
|
||||
use egui::{ComboBox, Context, Id, Modal, ProgressBar, Ui, Widget as _, Window};
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
@@ -163,10 +163,10 @@ impl crate::View for Modals {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::demo::modals::Modals;
|
||||
use crate::Demo;
|
||||
use crate::Demo as _;
|
||||
use egui::accesskit::Role;
|
||||
use egui::Key;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
use egui_kittest::kittest::Queryable as _;
|
||||
use egui_kittest::{Harness, SnapshotResults};
|
||||
|
||||
#[test]
|
||||
@@ -190,7 +190,7 @@ mod tests {
|
||||
assert!(harness.ctx.memory(|mem| mem.any_popup_open()));
|
||||
assert!(harness.state().user_modal_open);
|
||||
|
||||
harness.press_key(Key::Escape);
|
||||
harness.key_press(Key::Escape);
|
||||
harness.run_ok();
|
||||
assert!(!harness.ctx.memory(|mem| mem.any_popup_open()));
|
||||
assert!(harness.state().user_modal_open);
|
||||
@@ -214,7 +214,7 @@ mod tests {
|
||||
assert!(harness.state().user_modal_open);
|
||||
assert!(harness.state().save_modal_open);
|
||||
|
||||
harness.press_key(Key::Escape);
|
||||
harness.key_press(Key::Escape);
|
||||
harness.run();
|
||||
|
||||
assert!(harness.state().user_modal_open);
|
||||
@@ -267,7 +267,7 @@ mod tests {
|
||||
|
||||
harness.run_ok();
|
||||
|
||||
harness.get_by_label("Yes Please").simulate_click();
|
||||
harness.get_by_label("Yes Please").click();
|
||||
|
||||
harness.run_ok();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use egui::{
|
||||
emath,
|
||||
epaint::{self, CubicBezierShape, PathShape, QuadraticBezierShape},
|
||||
pos2, Color32, Context, Frame, Grid, Pos2, Rect, Sense, Shape, Stroke, StrokeKind, Ui, Vec2,
|
||||
Widget, Window,
|
||||
Widget as _, Window,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
/// ``` ignore
|
||||
/// password_ui(ui, &mut my_password);
|
||||
/// ```
|
||||
#[allow(clippy::ptr_arg)] // false positive
|
||||
pub fn password_ui(ui: &mut egui::Ui, password: &mut String) -> egui::Response {
|
||||
// This widget has its own state — show or hide password characters (`show_plaintext`).
|
||||
// In this case we use a simple `bool`, but you can also declare your own type.
|
||||
@@ -62,5 +61,5 @@ pub fn password(password: &mut String) -> impl egui::Widget + '_ {
|
||||
}
|
||||
|
||||
pub fn url_to_file_source_code() -> String {
|
||||
format!("https://github.com/emilk/egui/blob/master/{}", file!())
|
||||
format!("https://github.com/emilk/egui/blob/main/{}", file!())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use egui::{Image, UserData, ViewportCommand, Widget};
|
||||
use egui::{Image, UserData, ViewportCommand, Widget as _};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Showcase [`ViewportCommand::Screenshot`].
|
||||
@@ -58,7 +58,7 @@ impl crate::View for Screenshot {
|
||||
None
|
||||
}
|
||||
})
|
||||
.last()
|
||||
.next_back()
|
||||
});
|
||||
|
||||
if let Some(image) = image {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use egui::{
|
||||
pos2, scroll_area::ScrollBarVisibility, Align, Align2, Color32, DragValue, NumExt, Rect,
|
||||
ScrollArea, Sense, Slider, TextStyle, TextWrapMode, Ui, Vec2, Widget,
|
||||
pos2, scroll_area::ScrollBarVisibility, Align, Align2, Color32, DragValue, NumExt as _, Rect,
|
||||
ScrollArea, Sense, Slider, TextStyle, TextWrapMode, Ui, Vec2, Widget as _,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
|
||||
@@ -16,14 +16,6 @@ impl crate::Demo for CursorTest {
|
||||
|
||||
impl crate::View for CursorTest {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
if ui
|
||||
.button("Center pointer in window")
|
||||
.on_hover_text("The platform may not support this.")
|
||||
.clicked()
|
||||
{
|
||||
let position = ui.ctx().available_rect().center();
|
||||
ui.ctx().set_pointer_position(position);
|
||||
}
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
ui.heading("Hover to switch cursor icon:");
|
||||
for &cursor_icon in &egui::CursorIcon::ALL {
|
||||
|
||||
@@ -110,7 +110,7 @@ impl crate::View for GridTest {
|
||||
ui.end_row();
|
||||
|
||||
let mut dyn_text = String::from("O");
|
||||
dyn_text.extend(std::iter::repeat('h').take(self.text_length));
|
||||
dyn_text.extend(std::iter::repeat_n('h', self.text_length));
|
||||
ui.label(dyn_text);
|
||||
ui.label("Fifth row, second column");
|
||||
ui.end_row();
|
||||
|
||||
@@ -6,6 +6,7 @@ mod input_event_history;
|
||||
mod input_test;
|
||||
mod layout_test;
|
||||
mod manual_layout_test;
|
||||
mod svg_test;
|
||||
mod tessellation_test;
|
||||
mod window_resize_test;
|
||||
|
||||
@@ -17,5 +18,6 @@ pub use input_event_history::InputEventHistory;
|
||||
pub use input_test::InputTest;
|
||||
pub use layout_test::LayoutTest;
|
||||
pub use manual_layout_test::ManualLayoutTest;
|
||||
pub use svg_test::SvgTest;
|
||||
pub use tessellation_test::TessellationTest;
|
||||
pub use window_resize_test::WindowResizeTest;
|
||||
|
||||
42
crates/egui_demo_lib/src/demo/tests/svg_test.rs
Normal file
42
crates/egui_demo_lib/src/demo/tests/svg_test.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
pub struct SvgTest {
|
||||
color: egui::Color32,
|
||||
}
|
||||
|
||||
impl Default for SvgTest {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
color: egui::Color32::LIGHT_RED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Demo for SvgTest {
|
||||
fn name(&self) -> &'static str {
|
||||
"SVG Test"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
||||
use crate::View as _;
|
||||
self.ui(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::View for SvgTest {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
let Self { color } = self;
|
||||
ui.color_edit_button_srgba(color);
|
||||
let img_src = egui::include_image!("../../../data/peace.svg");
|
||||
|
||||
// First paint a small version, sized the same as the source…
|
||||
ui.add(
|
||||
egui::Image::new(img_src.clone())
|
||||
.fit_to_original_size(1.0)
|
||||
.tint(*color),
|
||||
);
|
||||
|
||||
// …then a big one, to make sure they are both crisp
|
||||
ui.add(egui::Image::new(img_src).tint(*color));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use egui::{
|
||||
emath::{GuiRounding, TSTransform},
|
||||
emath::{GuiRounding as _, TSTransform},
|
||||
epaint::{self, RectShape},
|
||||
vec2, Color32, Pos2, Rect, Sense, StrokeKind, Vec2,
|
||||
};
|
||||
|
||||
@@ -113,8 +113,8 @@ impl crate::View for TextEditDemo {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use egui::{accesskit, CentralPanel};
|
||||
use egui_kittest::kittest::{Key, Queryable};
|
||||
use egui::{accesskit, CentralPanel, Key, Modifiers};
|
||||
use egui_kittest::kittest::Queryable as _;
|
||||
use egui_kittest::Harness;
|
||||
|
||||
#[test]
|
||||
@@ -133,8 +133,9 @@ mod tests {
|
||||
|
||||
let text_edit = harness.get_by_role(accesskit::Role::TextInput);
|
||||
assert_eq!(text_edit.value().as_deref(), Some("Hello, world!"));
|
||||
text_edit.focus();
|
||||
|
||||
text_edit.key_combination(&[Key::Command, Key::A]);
|
||||
harness.key_press_modifiers(Modifiers::COMMAND, Key::A);
|
||||
text_edit.type_text("Hi ");
|
||||
|
||||
harness.run();
|
||||
|
||||
@@ -76,7 +76,7 @@ pub fn toggle_ui(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
||||
}
|
||||
|
||||
/// Here is the same code again, but a bit more compact:
|
||||
#[allow(dead_code)]
|
||||
#[expect(dead_code)]
|
||||
fn toggle_ui_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
||||
let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0, 1.0);
|
||||
let (rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
|
||||
@@ -121,5 +121,5 @@ pub fn toggle(on: &mut bool) -> impl egui::Widget + '_ {
|
||||
}
|
||||
|
||||
pub fn url_to_file_source_code() -> String {
|
||||
format!("https://github.com/emilk/egui/blob/master/{}", file!())
|
||||
format!("https://github.com/emilk/egui/blob/main/{}", file!())
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ impl Default for WidgetGallery {
|
||||
}
|
||||
|
||||
impl WidgetGallery {
|
||||
#[allow(unused_mut)] // if not chrono
|
||||
#[allow(unused_mut, clippy::allow_attributes)] // if not chrono
|
||||
#[inline]
|
||||
pub fn with_date_button(mut self, _with_date_button: bool) -> Self {
|
||||
#[cfg(feature = "chrono")]
|
||||
@@ -308,7 +308,7 @@ fn doc_link_label_with_crate<'a>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::View;
|
||||
use crate::View as _;
|
||||
use egui::Vec2;
|
||||
use egui_kittest::Harness;
|
||||
|
||||
@@ -322,7 +322,10 @@ mod tests {
|
||||
let mut harness = Harness::builder()
|
||||
.with_pixels_per_point(2.0)
|
||||
.with_size(Vec2::new(380.0, 550.0))
|
||||
.build_ui(|ui| demo.ui(ui));
|
||||
.build_ui(|ui| {
|
||||
egui_extras::install_image_loaders(ui.ctx());
|
||||
demo.ui(ui);
|
||||
});
|
||||
|
||||
harness.fit_contents();
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ Goals:
|
||||
2. easy to learn
|
||||
3. similar to markdown
|
||||
|
||||
[The reference parser](https://github.com/emilk/egui/blob/master/crates/egui_demo_lib/src/easy_mark/easy_mark_parser.rs) is \~250 lines of code, using only the Rust standard library. The parser uses no look-ahead or recursion.
|
||||
[The reference parser](https://github.com/emilk/egui/blob/main/crates/egui_demo_lib/src/easy_mark/easy_mark_parser.rs) is \~250 lines of code, using only the Rust standard library. The parser uses no look-ahead or recursion.
|
||||
|
||||
There is never more than one way to accomplish the same thing, and each special character is only used for one thing. For instance `*` is used for *strong* and `-` is used for bullet lists. There is no alternative way to specify the *strong* style or getting a bullet list.
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ macro_rules! egui_github_link_file {
|
||||
};
|
||||
($label: expr) => {
|
||||
egui::github_link_file!(
|
||||
"https://github.com/emilk/egui/blob/master/",
|
||||
"https://github.com/emilk/egui/blob/main/",
|
||||
egui::RichText::new($label).small()
|
||||
)
|
||||
};
|
||||
@@ -49,7 +49,7 @@ macro_rules! egui_github_link_file_line {
|
||||
};
|
||||
($label: expr) => {
|
||||
egui::github_link_file_line!(
|
||||
"https://github.com/emilk/egui/blob/master/",
|
||||
"https://github.com/emilk/egui/blob/main/",
|
||||
egui::RichText::new($label).small()
|
||||
)
|
||||
};
|
||||
|
||||
@@ -419,10 +419,7 @@ impl TextureManager {
|
||||
let height = 1;
|
||||
ctx.load_texture(
|
||||
"color_test_gradient",
|
||||
epaint::ColorImage {
|
||||
size: [width, height],
|
||||
pixels,
|
||||
},
|
||||
epaint::ColorImage::new([width, height], pixels),
|
||||
TextureOptions::LINEAR,
|
||||
)
|
||||
})
|
||||
@@ -740,8 +737,9 @@ mod tests {
|
||||
});
|
||||
|
||||
{
|
||||
// Expand color-test collapsing header
|
||||
harness.get_by_label("Color test").click();
|
||||
// Expand color-test collapsing header. We accesskit-click since collapsing header
|
||||
// might not be on screen at this point.
|
||||
harness.get_by_label("Color test").click_accesskit();
|
||||
harness.run();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c69c211061663cd17756eb0ad5a7720ed883047dbcedb39c493c544cfc644ed3
|
||||
size 99087
|
||||
oid sha256:72f442ded64947394ef90b16dc0a044d9bd8669a848b7f776d2b1d0788b5e244
|
||||
size 249
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:18fe761145335a60b1eeb1f7f2072224df86f0e2006caa09d1f3cc4bd263d90c
|
||||
size 46560
|
||||
oid sha256:4e71161bee8e69ad4d0ea9ced961c38d37cf611e1120649060570bb9dd283bbc
|
||||
size 260
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:880344367ed65f83898ceca4843b1b6259d1690242ced0d29ac8dc48100a8faa
|
||||
size 62956
|
||||
oid sha256:116a53258be27d9c7c56538e5f83202ea731f19887fabadc0449d24fde4d80d9
|
||||
size 64494
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1160361c41ffa9cde6d83cb32eeb9f9b75b275e98b97b625eababee460b69ba9
|
||||
size 24072
|
||||
oid sha256:af2a0e33647cf08c2927e18f8ea6a1c8388c19e6cac81e6f3eb1c1d5514408be
|
||||
size 260
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0fcfee082fe1dcbb7515ca6e3d5457e71fecf91a3efc4f76906a32fdb588adb4
|
||||
size 35096
|
||||
oid sha256:5b205ddb14069ac41a912954518e2763bc16285b4c86048dc3aef98eed1c76a8
|
||||
size 260
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b236fe02f6cd52041359cf4b1a00e9812b95560353ce5df4fa6cb20fdbb45307
|
||||
oid sha256:4a347875ef98ebbd606774e03baffdb317cb0246882db116fee1aa7685efbb88
|
||||
size 179653
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1579351658875af48ad9aafeb08d928d83f1bda42bf092fdcceecd0aa6730e26
|
||||
size 115313
|
||||
oid sha256:f0e3eeca8abb4fba632cef4621d478fb66af1a0f13e099dda9a79420cc2b6301
|
||||
size 115320
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9446da28768cae0b489e0f6243410a8b3acf0ca2a0b70690d65d2a6221bc25b9
|
||||
size 30517
|
||||
oid sha256:9d27ed8292a2612b337f663bff73cd009a82f806c61f0863bf70a53fd4c281ff
|
||||
size 75074
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:af75f773e9e4ad2615893babce5b99e7fd127c76dd0976ac8dc95307f38a59dc
|
||||
size 152854
|
||||
oid sha256:ee129f0542f21e12f5aa3c2f9746e7cadd73441a04d580f57c12c1cdd40d8b07
|
||||
size 153136
|
||||
|
||||
Reference in New Issue
Block a user