1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-01 06:10:06 -04:00

Merge remote-tracking branch 'egui/master' into dynamic-grid

This commit is contained in:
René Rössler
2022-03-23 14:51:55 +01:00
88 changed files with 2148 additions and 1997 deletions

View File

@@ -45,6 +45,7 @@ epi = { version = "0.17.0", path = "../epi" }
chrono = { version = "0.4", optional = true, features = ["js-sys", "wasmbind"] }
enum-map = { version = "2", features = ["serde"] }
tracing = "0.1"
unicode_names2 = { version = "0.5.0", default-features = false }
# feature "http":

View File

@@ -17,7 +17,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
demo_windows.ui(ctx);
});
ctx.tessellate(full_output.shapes)
})
});
});
c.bench_function("demo_no_tessellate", |b| {
@@ -25,14 +25,14 @@ pub fn criterion_benchmark(c: &mut Criterion) {
ctx.run(RawInput::default(), |ctx| {
demo_windows.ui(ctx);
})
})
});
});
let full_output = ctx.run(RawInput::default(), |ctx| {
demo_windows.ui(ctx);
});
c.bench_function("demo_only_tessellate", |b| {
b.iter(|| ctx.tessellate(full_output.shapes.clone()))
b.iter(|| ctx.tessellate(full_output.shapes.clone()));
});
}
@@ -45,7 +45,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
ctx.run(RawInput::default(), |ctx| {
demo_windows.ui(ctx);
})
})
});
});
}
@@ -56,12 +56,12 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("label &str", |b| {
b.iter(|| {
ui.label("the quick brown fox jumps over the lazy dog");
})
});
});
c.bench_function("label format!", |b| {
b.iter(|| {
ui.label("the quick brown fox jumps over the lazy dog".to_owned());
})
});
});
});
});
@@ -77,7 +77,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let rect = ui.max_rect();
b.iter(|| {
painter.rect(rect, 2.0, egui::Color32::RED, (1.0, egui::Color32::WHITE));
})
});
});
});
@@ -108,7 +108,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
wrap_width,
);
layout(&mut locked_fonts.fonts, job.into())
})
});
});
}
c.bench_function("text_layout_cached", |b| {
@@ -119,19 +119,19 @@ pub fn criterion_benchmark(c: &mut Criterion) {
color,
wrap_width,
)
})
});
});
let galley = fonts.layout(LOREM_IPSUM_LONG.to_owned(), font_id, color, wrap_width);
let mut tessellator = egui::epaint::Tessellator::from_options(Default::default());
let mut tessellator = egui::epaint::Tessellator::new(1.0, Default::default());
let mut mesh = egui::epaint::Mesh::default();
let text_shape = TextShape::new(egui::Pos2::ZERO, galley);
let font_image_size = fonts.font_image_size();
c.bench_function("tessellate_text", |b| {
b.iter(|| {
tessellator.tessellate_text(font_image_size, text_shape.clone(), &mut mesh);
tessellator.tessellate_text(font_image_size, &text_shape, &mut mesh);
mesh.clear();
})
});
});
}
}

View File

@@ -30,10 +30,6 @@ impl Default for ColorTest {
}
impl epi::App for ColorTest {
fn name(&self) -> &str {
"🎨 Color test"
}
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
if frame.is_web() {
@@ -132,9 +128,9 @@ impl ColorTest {
ui.separator();
// TODO: another ground truth where we do the alpha-blending against the background also.
// TODO: exactly the same thing, but with vertex colors (no textures)
self.show_gradients(ui, WHITE, (TRANSPARENT, BLACK));
self.show_gradients(ui, BLACK, (BLACK, WHITE));
ui.separator();
self.show_gradients(ui, WHITE, (BLACK, TRANSPARENT));
ui.separator();
self.show_gradients(ui, BLACK, (TRANSPARENT, WHITE));
ui.separator();
@@ -149,6 +145,10 @@ impl ColorTest {
ui.separator();
pixel_test(ui);
ui.separator();
fine_line_test(ui);
}
fn show_gradients(&mut self, ui: &mut Ui, bg_fill: Color32, (left, right): (Color32, Color32)) {
@@ -357,6 +357,12 @@ impl TextureManager {
fn pixel_test(ui: &mut Ui) {
ui.label("Each subsequent square should be one physical pixel larger than the previous. They should be exactly one physical pixel apart. They should be perfectly aligned to the pixel grid.");
let color = if ui.style().visuals.dark_mode {
egui::Color32::WHITE
} else {
egui::Color32::BLACK
};
let pixels_per_point = ui.ctx().pixels_per_point();
let num_squares: u32 = 8;
let size_pixels = Vec2::new(
@@ -379,7 +385,71 @@ fn pixel_test(ui: &mut Ui) {
),
Vec2::splat(size as f32) / pixels_per_point,
);
painter.rect_filled(rect_points, 0.0, egui::Color32::WHITE);
painter.rect_filled(rect_points, 0.0, color);
cursor_pixel.x += (1 + size) as f32;
}
}
fn fine_line_test(ui: &mut Ui) {
ui.label("Some fine lines for testing anti-aliasing and blending:");
let size = Vec2::new(256.0, 512.0);
let (response, painter) = ui.allocate_painter(size, Sense::hover());
let rect = response.rect;
let mut top_half = rect;
top_half.set_bottom(top_half.center().y);
painter.rect_filled(top_half, 0.0, Color32::BLACK);
paint_fine_lines(&painter, top_half, Color32::WHITE);
let mut bottom_half = rect;
bottom_half.set_top(bottom_half.center().y);
painter.rect_filled(bottom_half, 0.0, Color32::WHITE);
paint_fine_lines(&painter, bottom_half, Color32::BLACK);
}
fn paint_fine_lines(painter: &egui::Painter, mut rect: Rect, color: Color32) {
rect = rect.shrink(12.0);
for width in [0.5, 1.0, 2.0] {
painter.text(
rect.left_top(),
Align2::CENTER_CENTER,
width.to_string(),
FontId::monospace(14.0),
color,
);
painter.add(egui::epaint::CubicBezierShape::from_points_stroke(
[
rect.left_top() + Vec2::new(16.0, 0.0),
rect.right_top(),
rect.right_center(),
rect.right_bottom(),
],
false,
Color32::TRANSPARENT,
Stroke::new(width, color),
));
rect.min.y += 32.0;
rect.max.x -= 32.0;
}
rect.min.y += 16.0;
painter.text(
rect.left_top(),
Align2::LEFT_CENTER,
"transparent --> opaque",
FontId::monospace(11.0),
color,
);
rect.min.y += 12.0;
let mut mesh = Mesh::default();
mesh.colored_vertex(rect.left_bottom(), Color32::TRANSPARENT);
mesh.colored_vertex(rect.left_top(), Color32::TRANSPARENT);
mesh.colored_vertex(rect.right_bottom(), color);
mesh.colored_vertex(rect.right_top(), color);
mesh.add_triangle(0, 1, 2);
mesh.add_triangle(1, 2, 3);
painter.add(mesh);
}

View File

@@ -1,7 +1,3 @@
/// Demonstrates how to make an app using egui.
///
/// Implements `epi::App` so it can be used with
/// [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium), [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) and [`egui_web`](https://github.com/emilk/egui/tree/master/egui_web).
#[derive(Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
@@ -10,28 +6,6 @@ pub struct DemoApp {
}
impl epi::App for DemoApp {
fn name(&self) -> &str {
"✨ Demos"
}
fn setup(
&mut self,
_ctx: &egui::Context,
_frame: &epi::Frame,
_storage: Option<&dyn epi::Storage>,
_gl: &std::rc::Rc<epi::glow::Context>,
) {
#[cfg(feature = "persistence")]
if let Some(storage) = _storage {
*self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default();
}
}
#[cfg(feature = "persistence")]
fn save(&mut self, storage: &mut dyn epi::Storage) {
epi::set_value(storage, epi::APP_KEY, self);
}
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
self.demo_windows.ui(ctx);
}

View File

@@ -64,6 +64,7 @@ impl super::View for TextEdit {
anything_selected,
egui::Label::new("Press ctrl+T to toggle the case of selected text (cmd+T on Mac)"),
);
if ui
.input_mut()
.consume_key(egui::Modifiers::COMMAND, egui::Key::T)
@@ -82,5 +83,29 @@ impl super::View for TextEdit {
text.insert_text(&new_text, selected_chars.start);
}
}
ui.horizontal(|ui| {
ui.label("Move cursor to the:");
if ui.button("start").clicked() {
let text_edit_id = output.response.id;
if let Some(mut state) = egui::TextEdit::load_state(ui.ctx(), text_edit_id) {
let ccursor = egui::text::CCursor::new(0);
state.set_ccursor_range(Some(egui::text::CCursorRange::one(ccursor)));
state.store(ui.ctx(), text_edit_id);
ui.ctx().memory().request_focus(text_edit_id); // give focus back to the `TextEdit`.
}
}
if ui.button("end").clicked() {
let text_edit_id = output.response.id;
if let Some(mut state) = egui::TextEdit::load_state(ui.ctx(), text_edit_id) {
let ccursor = egui::text::CCursor::new(text.chars().count());
state.set_ccursor_range(Some(egui::text::CCursorRange::one(ccursor)));
state.store(ui.ctx(), text_edit_id);
ui.ctx().memory().request_focus(text_edit_id); // give focus back to the `TextEdit`.
}
}
});
}
}

View File

@@ -33,10 +33,6 @@ impl Default for FractalClock {
}
impl epi::App for FractalClock {
fn name(&self) -> &str {
"🕑 Fractal Clock"
}
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
egui::CentralPanel::default()
.frame(Frame::dark_canvas(&ctx.style()))

View File

@@ -54,10 +54,6 @@ impl Default for HttpApp {
}
impl epi::App for HttpApp {
fn name(&self) -> &str {
"⬇ HTTP"
}
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
egui::TopBottomPanel::bottom("http_bottom").show(ctx, |ui| {
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
@@ -78,11 +74,10 @@ impl epi::App for HttpApp {
if trigger_fetch {
let ctx = ctx.clone();
let frame = frame.clone();
let (sender, promise) = Promise::new();
let request = ehttp::Request::get(&self.url);
ehttp::fetch(request, move |response| {
frame.request_repaint(); // wake up UI thread
ctx.request_repaint(); // wake up UI thread
let resource = response.map(|response| Resource::from_response(&ctx, response));
sender.send(resource);
});

View File

@@ -54,10 +54,6 @@ pub struct BackendPanel {
#[cfg_attr(feature = "serde", serde(skip))]
pixels_per_point: Option<f32>,
/// maximum size of the web browser canvas
max_size_points_ui: egui::Vec2,
pub max_size_points_active: egui::Vec2,
#[cfg_attr(feature = "serde", serde(skip))]
frame_history: crate::frame_history::FrameHistory,
@@ -70,8 +66,6 @@ impl Default for BackendPanel {
open: false,
run_mode: Default::default(),
pixels_per_point: Default::default(),
max_size_points_ui: egui::Vec2::new(1024.0, 2048.0),
max_size_points_active: egui::Vec2::new(1024.0, 2048.0),
frame_history: Default::default(),
egui_windows: Default::default(),
}
@@ -157,17 +151,6 @@ impl BackendPanel {
ui.hyperlink("https://github.com/emilk/egui");
ui.separator();
ui.add(
egui::Slider::new(&mut self.max_size_points_ui.x, 512.0..=f32::INFINITY)
.logarithmic(true)
.largest_finite(8192.0)
.text("Max width"),
)
.on_hover_text("Maximum width of the egui region of the web page.");
if !ui.ctx().is_using_pointer() {
self.max_size_points_active = self.max_size_points_ui;
}
}
show_integration_name(ui, &frame.info());

View File

@@ -30,10 +30,6 @@ impl Default for EasyMarkEditor {
}
impl epi::App for EasyMarkEditor {
fn name(&self) -> &str {
"🖹 EasyMark editor"
}
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |ui| {
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);

View File

@@ -2,85 +2,6 @@
//!
//! The demo-code is also used in benchmarks and tests.
// Forbid warnings in release builds:
#![cfg_attr(not(debug_assertions), deny(warnings))]
#![forbid(unsafe_code)]
#![warn(
clippy::all,
clippy::await_holding_lock,
clippy::char_lit_as_u8,
clippy::checked_conversions,
clippy::dbg_macro,
clippy::debug_assert_with_mut_call,
clippy::disallowed_method,
clippy::doc_markdown,
clippy::empty_enum,
clippy::enum_glob_use,
clippy::exit,
clippy::expl_impl_clone_on_copy,
clippy::explicit_deref_methods,
clippy::explicit_into_iter_loop,
clippy::fallible_impl_from,
clippy::filter_map_next,
clippy::flat_map_option,
clippy::float_cmp_const,
clippy::fn_params_excessive_bools,
clippy::from_iter_instead_of_collect,
clippy::if_let_mutex,
clippy::implicit_clone,
clippy::imprecise_flops,
clippy::inefficient_to_string,
clippy::invalid_upcast_comparisons,
clippy::large_digit_groups,
clippy::large_stack_arrays,
clippy::large_types_passed_by_value,
clippy::let_unit_value,
clippy::linkedlist,
clippy::lossy_float_literal,
clippy::macro_use_imports,
clippy::manual_ok_or,
clippy::map_err_ignore,
clippy::map_flatten,
clippy::map_unwrap_or,
clippy::match_on_vec_items,
clippy::match_same_arms,
clippy::match_wild_err_arm,
clippy::match_wildcard_for_single_variants,
clippy::mem_forget,
clippy::mismatched_target_os,
clippy::missing_errors_doc,
clippy::missing_safety_doc,
clippy::mut_mut,
clippy::mutex_integer,
clippy::needless_borrow,
clippy::needless_continue,
clippy::needless_for_each,
clippy::needless_pass_by_value,
clippy::option_option,
clippy::path_buf_push_overwrite,
clippy::ptr_as_ptr,
clippy::ref_option_ref,
clippy::rest_pat_in_fully_bound_structs,
clippy::same_functions_in_if_condition,
clippy::semicolon_if_nothing_returned,
clippy::single_match_else,
clippy::string_add_assign,
clippy::string_add,
clippy::string_lit_as_bytes,
clippy::string_to_string,
clippy::todo,
clippy::trait_duplication_in_bounds,
clippy::unimplemented,
clippy::unnested_or_patterns,
clippy::unused_self,
clippy::useless_transmute,
clippy::verbose_file_reads,
clippy::zero_sized_map_values,
future_incompatible,
nonstandard_style,
rust_2018_idioms,
rustdoc::missing_crate_level_docs
)]
#![allow(clippy::float_cmp)]
#![allow(clippy::manual_range_contains)]

View File

@@ -277,7 +277,7 @@ impl CodeTheme {
ui.data().insert_persisted(selected_id, selected_tt);
egui::Frame::group(ui.style())
.margin(egui::Vec2::splat(2.0))
.inner_margin(egui::Vec2::splat(2.0))
.show(ui, |ui| {
// ui.group(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Small);

View File

@@ -12,14 +12,26 @@ pub struct Apps {
}
impl Apps {
fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut dyn epi::App)> {
fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &str, &mut dyn epi::App)> {
vec![
("demo", &mut self.demo as &mut dyn epi::App),
("easymark", &mut self.easy_mark_editor as &mut dyn epi::App),
("✨ Demos", "demo", &mut self.demo as &mut dyn epi::App),
(
"🖹 EasyMark editor",
"easymark",
&mut self.easy_mark_editor as &mut dyn epi::App,
),
#[cfg(feature = "http")]
("http", &mut self.http as &mut dyn epi::App),
("clock", &mut self.clock as &mut dyn epi::App),
("colors", &mut self.color_test as &mut dyn epi::App),
("⬇ HTTP", "http", &mut self.http as &mut dyn epi::App),
(
"🕑 Fractal Clock",
"clock",
&mut self.clock as &mut dyn epi::App,
),
(
"🎨 Color test",
"colors",
&mut self.color_test as &mut dyn epi::App,
),
]
.into_iter()
}
@@ -37,33 +49,22 @@ pub struct WrapApp {
dropped_files: Vec<egui::DroppedFile>,
}
impl epi::App for WrapApp {
fn name(&self) -> &str {
"egui demo apps"
}
fn setup(
&mut self,
_ctx: &egui::Context,
_frame: &epi::Frame,
_storage: Option<&dyn epi::Storage>,
_gl: &std::rc::Rc<epi::glow::Context>,
) {
impl WrapApp {
pub fn new(_cc: &epi::CreationContext<'_>) -> Self {
#[cfg(feature = "persistence")]
if let Some(storage) = _storage {
*self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default();
if let Some(storage) = _cc.storage {
return epi::get_value(storage, epi::APP_KEY).unwrap_or_default();
}
Self::default()
}
}
impl epi::App for WrapApp {
#[cfg(feature = "persistence")]
fn save(&mut self, storage: &mut dyn epi::Storage) {
epi::set_value(storage, epi::APP_KEY, self);
}
fn max_size_points(&self) -> egui::Vec2 {
self.backend_panel.max_size_points_active
}
fn clear_color(&self) -> egui::Rgba {
egui::Rgba::TRANSPARENT // we set a `CentralPanel` fill color in `demo_windows.rs`
}
@@ -111,7 +112,7 @@ impl epi::App for WrapApp {
let mut found_anchor = false;
for (anchor, app) in self.apps.iter_mut() {
for (_name, anchor, app) in self.apps.iter_mut() {
if anchor == self.selected_anchor || ctx.memory().everything_is_visible() {
app.update(ctx, frame);
found_anchor = true;
@@ -138,9 +139,9 @@ impl WrapApp {
ui.checkbox(&mut self.backend_panel.open, "💻 Backend");
ui.separator();
for (anchor, app) in self.apps.iter_mut() {
for (name, anchor, _app) in self.apps.iter_mut() {
if ui
.selectable_label(self.selected_anchor == anchor, app.name())
.selectable_label(self.selected_anchor == anchor, name)
.clicked()
{
self.selected_anchor = anchor.to_owned();