From beb2ecf7e475eaa07ccc755626e05c1906c4e750 Mon Sep 17 00:00:00 2001 From: jacekpoz <64381190+jacekpoz@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:59:49 +0000 Subject: [PATCH 01/43] fix typo in NativeOptions docs (#3108) Co-authored-by: jacekpoz --- crates/eframe/src/epi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eframe/src/epi/mod.rs b/crates/eframe/src/epi/mod.rs index 0f6f42290..fd4f0280f 100644 --- a/crates/eframe/src/epi/mod.rs +++ b/crates/eframe/src/epi/mod.rs @@ -431,7 +431,7 @@ pub struct NativeOptions { /// will be used instead. /// /// ### On Wayland - /// On Wauland this sets the Application ID for the window. + /// On Wayland this sets the Application ID for the window. /// /// The application ID is used in several places of the compositor, e.g. for /// grouping windows of the same application. It is also important for From 67d5bd4392daaf520fd733aa190dca5fde799470 Mon Sep 17 00:00:00 2001 From: bernsteining <32954876+bernsteining@users.noreply.github.com> Date: Wed, 26 Jul 2023 19:00:13 +0200 Subject: [PATCH 02/43] fix(docs): remove duplicate typo (#3111) --- crates/egui-winit/src/clipboard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/egui-winit/src/clipboard.rs b/crates/egui-winit/src/clipboard.rs index e80414961..71d913dbb 100644 --- a/crates/egui-winit/src/clipboard.rs +++ b/crates/egui-winit/src/clipboard.rs @@ -3,7 +3,7 @@ use raw_window_handle::HasRawDisplayHandle; /// Handles interfacing with the OS clipboard. /// /// If the "clipboard" feature is off, or we cannot connect to the OS clipboard, -/// then a fallback clipboard that just works works within the same app is used instead. +/// then a fallback clipboard that just works within the same app is used instead. pub struct Clipboard { #[cfg(all(feature = "arboard", not(target_os = "android")))] arboard: Option, From 936c9583b5b15a766c9aac52ccc35f1625d5d69d Mon Sep 17 00:00:00 2001 From: Forest Anderson Date: Wed, 26 Jul 2023 13:00:51 -0400 Subject: [PATCH 03/43] Spelling fix (#3133) --- crates/egui_demo_lib/src/demo/plot_demo.rs | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/crates/egui_demo_lib/src/demo/plot_demo.rs b/crates/egui_demo_lib/src/demo/plot_demo.rs index 12d79ce0e..8c5bcfd3c 100644 --- a/crates/egui_demo_lib/src/demo/plot_demo.rs +++ b/crates/egui_demo_lib/src/demo/plot_demo.rs @@ -39,8 +39,8 @@ pub struct PlotDemo { charts_demo: ChartsDemo, items_demo: ItemsDemo, interaction_demo: InteractionDemo, - custom_axes_demo: CustomAxisDemo, - linked_axes_demo: LinkedAxisDemo, + custom_axes_demo: CustomAxesDemo, + linked_axes_demo: LinkedAxesDemo, open_panel: Panel, } @@ -448,19 +448,19 @@ impl LegendDemo { // ---------------------------------------------------------------------------- #[derive(PartialEq, Default)] -struct CustomAxisDemo {} +struct CustomAxesDemo {} -impl CustomAxisDemo { +impl CustomAxesDemo { const MINS_PER_DAY: f64 = 24.0 * 60.0; const MINS_PER_H: f64 = 60.0; fn logistic_fn() -> Line { fn days(min: f64) -> f64 { - CustomAxisDemo::MINS_PER_DAY * min + CustomAxesDemo::MINS_PER_DAY * min } let values = PlotPoints::from_explicit_callback( - move |x| 1.0 / (1.0 + (-2.5 * (x / CustomAxisDemo::MINS_PER_DAY - 2.0)).exp()), + move |x| 1.0 / (1.0 + (-2.5 * (x / CustomAxesDemo::MINS_PER_DAY - 2.0)).exp()), days(0.0)..days(5.0), 100, ); @@ -504,8 +504,8 @@ impl CustomAxisDemo { #[allow(clippy::unused_self)] fn ui(&mut self, ui: &mut Ui) -> Response { - const MINS_PER_DAY: f64 = CustomAxisDemo::MINS_PER_DAY; - const MINS_PER_H: f64 = CustomAxisDemo::MINS_PER_H; + const MINS_PER_DAY: f64 = CustomAxesDemo::MINS_PER_DAY; + const MINS_PER_H: f64 = CustomAxesDemo::MINS_PER_H; fn day(x: f64) -> f64 { (x / MINS_PER_DAY).floor() @@ -561,10 +561,10 @@ impl CustomAxisDemo { .data_aspect(2.0 * MINS_PER_DAY as f32) .x_axis_formatter(x_fmt) .y_axis_formatter(y_fmt) - .x_grid_spacer(CustomAxisDemo::x_grid) + .x_grid_spacer(CustomAxesDemo::x_grid) .label_formatter(label_fmt) .show(ui, |plot_ui| { - plot_ui.line(CustomAxisDemo::logistic_fn()); + plot_ui.line(CustomAxesDemo::logistic_fn()); }) .response } @@ -573,14 +573,14 @@ impl CustomAxisDemo { // ---------------------------------------------------------------------------- #[derive(PartialEq)] -struct LinkedAxisDemo { +struct LinkedAxesDemo { link_x: bool, link_y: bool, link_cursor_x: bool, link_cursor_y: bool, } -impl Default for LinkedAxisDemo { +impl Default for LinkedAxesDemo { fn default() -> Self { let link_x = true; let link_y = false; @@ -595,7 +595,7 @@ impl Default for LinkedAxisDemo { } } -impl LinkedAxisDemo { +impl LinkedAxesDemo { fn line_with_slope(slope: f64) -> Line { Line::new(PlotPoints::from_explicit_callback( move |x| slope * x, @@ -621,11 +621,11 @@ impl LinkedAxisDemo { } fn configure_plot(plot_ui: &mut plot::PlotUi) { - plot_ui.line(LinkedAxisDemo::line_with_slope(0.5)); - plot_ui.line(LinkedAxisDemo::line_with_slope(1.0)); - plot_ui.line(LinkedAxisDemo::line_with_slope(2.0)); - plot_ui.line(LinkedAxisDemo::sin()); - plot_ui.line(LinkedAxisDemo::cos()); + plot_ui.line(LinkedAxesDemo::line_with_slope(0.5)); + plot_ui.line(LinkedAxesDemo::line_with_slope(1.0)); + plot_ui.line(LinkedAxesDemo::line_with_slope(2.0)); + plot_ui.line(LinkedAxesDemo::sin()); + plot_ui.line(LinkedAxesDemo::cos()); } fn ui(&mut self, ui: &mut Ui) -> Response { @@ -648,14 +648,14 @@ impl LinkedAxisDemo { .height(250.0) .link_axis(link_group_id, self.link_x, self.link_y) .link_cursor(link_group_id, self.link_cursor_x, self.link_cursor_y) - .show(ui, LinkedAxisDemo::configure_plot); + .show(ui, LinkedAxesDemo::configure_plot); Plot::new("linked_axis_2") .data_aspect(2.0) .width(150.0) .height(250.0) .link_axis(link_group_id, self.link_x, self.link_y) .link_cursor(link_group_id, self.link_cursor_x, self.link_cursor_y) - .show(ui, LinkedAxisDemo::configure_plot); + .show(ui, LinkedAxesDemo::configure_plot); }); Plot::new("linked_axis_3") .data_aspect(0.5) @@ -663,7 +663,7 @@ impl LinkedAxisDemo { .height(150.0) .link_axis(link_group_id, self.link_x, self.link_y) .link_cursor(link_group_id, self.link_cursor_x, self.link_cursor_y) - .show(ui, LinkedAxisDemo::configure_plot) + .show(ui, LinkedAxesDemo::configure_plot) .response } } From 65eecde2446495c0ea88c37318ead66457c7ab81 Mon Sep 17 00:00:00 2001 From: Matt Fellenz Date: Wed, 26 Jul 2023 10:07:05 -0700 Subject: [PATCH 04/43] Use cfg attribute (#3113) --- crates/eframe/src/native/run.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 367daea74..7771265a1 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -144,11 +144,13 @@ fn run_and_return( // Platform-dependent event handlers to workaround a winit bug // See: https://github.com/rust-windowing/winit/issues/987 // See: https://github.com/rust-windowing/winit/issues/1619 - winit::event::Event::RedrawEventsCleared if cfg!(windows) => { + #[cfg(windows)] + winit::event::Event::RedrawEventsCleared => { next_repaint_time = extremely_far_future(); winit_app.run_ui_and_paint() } - winit::event::Event::RedrawRequested(_) if !cfg!(windows) => { + #[cfg(not(windows))] + winit::event::Event::RedrawRequested(_) => { next_repaint_time = extremely_far_future(); winit_app.run_ui_and_paint() } From 339b758c60d04688e7b53cd964473524650036e8 Mon Sep 17 00:00:00 2001 From: Serv Date: Wed, 26 Jul 2023 22:21:28 +0400 Subject: [PATCH 05/43] fixed char limit (#3173) --- crates/egui/src/widgets/text_edit/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index b76c6e336..c9eaa1d4b 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -1185,7 +1185,7 @@ fn insert_text( if char_limit < usize::MAX { let mut new_string = text_to_insert; // Avoid subtract with overflow panic - let cutoff = char_limit.saturating_sub(text.as_str().len()); + let cutoff = char_limit.saturating_sub(text.as_str().chars().count()); new_string = match new_string.char_indices().nth(cutoff) { None => new_string, From bdc8795b0476c25faab927fc3c731f2d79f2098f Mon Sep 17 00:00:00 2001 From: Antoine Beyeler <49431240+abey79@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:53:06 +0200 Subject: [PATCH 06/43] Set the correct unicode character for "ctrl" shortcuts (#3186) Fixes rerun-io/rerun#2862 --- crates/egui/src/data/input.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 99ea6ac03..29ff3f5dd 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -610,11 +610,11 @@ pub struct ModifierNames<'a> { } impl ModifierNames<'static> { - /// ⌥ ^ ⇧ ⌘ - NOTE: not supported by the default egui font. + /// ⌥ ⌃ ⇧ ⌘ - NOTE: not supported by the default egui font. pub const SYMBOLS: Self = Self { is_short: true, alt: "⌥", - ctrl: "^", + ctrl: "⌃", shift: "⇧", mac_cmd: "⌘", mac_alt: "⌥", @@ -906,7 +906,7 @@ fn format_kb_shortcut() { cmd_shift_f.format(&ModifierNames::NAMES, true), "Shift+Cmd+F" ); - assert_eq!(cmd_shift_f.format(&ModifierNames::SYMBOLS, false), "^⇧F"); + assert_eq!(cmd_shift_f.format(&ModifierNames::SYMBOLS, false), "⌃⇧F"); assert_eq!(cmd_shift_f.format(&ModifierNames::SYMBOLS, true), "⇧⌘F"); } From 924a903610f1bee64178531d943a91e8922411aa Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 8 Aug 2023 10:34:37 +0200 Subject: [PATCH 07/43] Rename _typos.toml to .typos.toml --- _typos.toml => .typos.toml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename _typos.toml => .typos.toml (100%) diff --git a/_typos.toml b/.typos.toml similarity index 100% rename from _typos.toml rename to .typos.toml From 0e5f93b65d7613de58ce8d16e9eba652d1d3d562 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 8 Aug 2023 11:50:10 +0200 Subject: [PATCH 08/43] Add `Margin::expand_rect` and `shrink_rect` (#3214) * Add `Margin::expand_rect` and `shrink_rect` * fix typo * Use the new helpers --- crates/egui/src/containers/frame.rs | 16 +++++----------- crates/egui/src/containers/scroll_area.rs | 2 +- crates/egui/src/style.rs | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/crates/egui/src/containers/frame.rs b/crates/egui/src/containers/frame.rs index fa1caee70..08b5e5a0e 100644 --- a/crates/egui/src/containers/frame.rs +++ b/crates/egui/src/containers/frame.rs @@ -193,9 +193,7 @@ impl Frame { let where_to_put_background = ui.painter().add(Shape::Noop); let outer_rect_bounds = ui.available_rect_before_wrap(); - let mut inner_rect = outer_rect_bounds; - inner_rect.min += self.outer_margin.left_top() + self.inner_margin.left_top(); - inner_rect.max -= self.outer_margin.right_bottom() + self.inner_margin.right_bottom(); + let mut inner_rect = (self.inner_margin + self.outer_margin).shrink_rect(outer_rect_bounds); // Make sure we don't shrink to the negative: inner_rect.max.x = inner_rect.max.x.max(inner_rect.min.x); @@ -256,17 +254,13 @@ impl Frame { impl Prepared { fn paint_rect(&self) -> Rect { - let mut rect = self.content_ui.min_rect(); - rect.min -= self.frame.inner_margin.left_top(); - rect.max += self.frame.inner_margin.right_bottom(); - rect + self.frame + .inner_margin + .expand_rect(self.content_ui.min_rect()) } fn content_with_margin(&self) -> Rect { - let mut rect = self.content_ui.min_rect(); - rect.min -= self.frame.inner_margin.left_top() + self.frame.outer_margin.left_top(); - rect.max += self.frame.inner_margin.right_bottom() + self.frame.outer_margin.right_bottom(); - rect + (self.frame.inner_margin + self.frame.outer_margin).expand_rect(self.content_ui.min_rect()) } pub fn end(self, ui: &mut Ui) -> Response { diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 2f67bf3e0..341e61f2f 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -459,7 +459,7 @@ impl ScrollArea { content_clip_rect.max[d] = ui.clip_rect().max[d] - current_bar_use[d]; } } - // Make sure we din't accidentally expand the clip rect + // Make sure we didn't accidentally expand the clip rect content_clip_rect = content_clip_rect.intersect(ui.clip_rect()); content_ui.set_clip_rect(content_clip_rect); } diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index eb3b6036b..09eb5835b 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -360,30 +360,46 @@ impl Margin { } /// Total margins on both sides + #[inline] pub fn sum(&self) -> Vec2 { vec2(self.left + self.right, self.top + self.bottom) } + #[inline] pub fn left_top(&self) -> Vec2 { vec2(self.left, self.top) } + #[inline] pub fn right_bottom(&self) -> Vec2 { vec2(self.right, self.bottom) } + #[inline] pub fn is_same(&self) -> bool { self.left == self.right && self.left == self.top && self.left == self.bottom } + + #[inline] + pub fn expand_rect(&self, rect: Rect) -> Rect { + Rect::from_min_max(rect.min - self.left_top(), rect.max + self.right_bottom()) + } + + #[inline] + pub fn shrink_rect(&self, rect: Rect) -> Rect { + Rect::from_min_max(rect.min + self.left_top(), rect.max - self.right_bottom()) + } } impl From for Margin { + #[inline] fn from(v: f32) -> Self { Self::same(v) } } impl From for Margin { + #[inline] fn from(v: Vec2) -> Self { Self::symmetric(v.x, v.y) } @@ -392,6 +408,7 @@ impl From for Margin { impl std::ops::Add for Margin { type Output = Self; + #[inline] fn add(self, other: Self) -> Self { Self { left: self.left + other.left, From cd917e49f210b14b6961379e672fa60f84a78fe6 Mon Sep 17 00:00:00 2001 From: lampsitter <96946613+lampsitter@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:07:40 +0200 Subject: [PATCH 09/43] Separate text cursor from selection visuals (#3181) --- crates/egui/src/style.rs | 11 +++++++---- crates/egui/src/widgets/text_edit/builder.rs | 7 ++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index 09eb5835b..4a8dba7c0 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -508,7 +508,8 @@ pub struct Visuals { pub resize_corner_size: f32, - pub text_cursor_width: f32, + /// The color and width of the text cursor + pub text_cursor: Stroke, /// show where the text cursor would be if you clicked pub text_cursor_preview: bool, @@ -784,7 +785,7 @@ impl Visuals { popup_shadow: Shadow::small_dark(), resize_corner_size: 12.0, - text_cursor_width: 2.0, + text_cursor: Stroke::new(2.0, Color32::from_rgb(192, 222, 255)), text_cursor_preview: false, clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion button_frame: true, @@ -817,6 +818,7 @@ impl Visuals { panel_fill: Color32::from_gray(248), popup_shadow: Shadow::small_light(), + text_cursor: Stroke::new(2.0, Color32::from_rgb(0, 83, 125)), ..Self::dark() } } @@ -1351,7 +1353,7 @@ impl Visuals { popup_shadow, resize_corner_size, - text_cursor_width, + text_cursor, text_cursor_preview, clip_rect_margin, button_frame, @@ -1409,8 +1411,9 @@ impl Visuals { }); ui_color(ui, hyperlink_color, "hyperlink_color"); + stroke_ui(ui, text_cursor, "Text Cursor"); + ui.add(Slider::new(resize_corner_size, 0.0..=20.0).text("resize_corner_size")); - ui.add(Slider::new(text_cursor_width, 0.0..=4.0).text("text_cursor_width")); ui.checkbox(text_cursor_preview, "Preview text cursor on hover"); ui.add(Slider::new(clip_rect_margin, 0.0..=20.0).text("clip_rect_margin")); diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index c9eaa1d4b..e92bf9dbc 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -1138,7 +1138,7 @@ fn paint_cursor_end( galley: &Galley, cursor: &Cursor, ) -> Rect { - let stroke = ui.visuals().selection.stroke; + let stroke = ui.visuals().text_cursor; let mut cursor_pos = galley.pos_from_cursor(cursor).translate(pos.to_vec2()); cursor_pos.max.y = cursor_pos.max.y.at_least(cursor_pos.min.y + row_height); // Handle completely empty galleys @@ -1147,10 +1147,7 @@ fn paint_cursor_end( let top = cursor_pos.center_top(); let bottom = cursor_pos.center_bottom(); - painter.line_segment( - [top, bottom], - (ui.visuals().text_cursor_width, stroke.color), - ); + painter.line_segment([top, bottom], (stroke.width, stroke.color)); if false { // Roof/floor: From d483ac47ba05311cbb2098e27f31a89450b3560f Mon Sep 17 00:00:00 2001 From: Felix Wiegand Date: Wed, 9 Aug 2023 11:08:04 +0200 Subject: [PATCH 10/43] Fix auto_bounds when only one axis has restricted navigation (#3171) --- crates/egui/src/widgets/plot/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index c5db91992..8f04be4fa 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -864,7 +864,7 @@ impl Plot { delta.y = 0.0; } transform.translate_bounds(delta); - bounds_modified = true.into(); + bounds_modified = allow_drag; } // Zooming @@ -935,7 +935,7 @@ impl Plot { } if zoom_factor != Vec2::splat(1.0) { transform.zoom(zoom_factor, hover_pos); - bounds_modified = true.into(); + bounds_modified = allow_zoom; } } if allow_scroll { From 387b07568198c04c7f15ebeab8c4a6533bc65a26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:15:37 +0200 Subject: [PATCH 11/43] Bump xml-rs from 0.8.13 to 0.8.15 (#3145) Bumps [xml-rs](https://github.com/kornelski/xml-rs) from 0.8.13 to 0.8.15. - [Changelog](https://github.com/kornelski/xml-rs/blob/main/Changelog.md) - [Commits](https://github.com/kornelski/xml-rs/compare/0.8.13...0.8.15) --- updated-dependencies: - dependency-name: xml-rs dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c781b851b..632040aa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4465,9 +4465,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.13" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d8f380ae16a37b30e6a2cf67040608071384b1450c189e61bea3ff57cde922d" +checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336" [[package]] name = "xmlparser" From 67ba4f2811d49c1b2446d114e5a7e7f31ce50368 Mon Sep 17 00:00:00 2001 From: Brian Janssen Date: Wed, 9 Aug 2023 11:48:54 +0200 Subject: [PATCH 12/43] Add comment explaining Tab button (#2872) --- crates/egui-winit/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 75c9028cf..ae82f6e4c 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -307,6 +307,7 @@ impl State { } WindowEvent::KeyboardInput { input, .. } => { self.on_keyboard_input(input); + // When pressing the Tab key, egui focuses the first focusable element, hence Tab always consumes. let consumed = egui_ctx.wants_keyboard_input() || input.virtual_keycode == Some(winit::event::VirtualKeyCode::Tab); EventResponse { From 486cff8ac39cfba0a804a6126621dd9093adaea9 Mon Sep 17 00:00:00 2001 From: "Stephen M. Coakley" Date: Wed, 9 Aug 2023 05:42:43 -0500 Subject: [PATCH 13/43] Fix panic with persistence without window (#3167) A window may not always be available and may have already been closed by the time an eframe app is closing. An example of this is Android, where the main activity window may have been stopped or discarded because the app is no longer in the foreground, and then the user decides to close your app without resuming it using the multitasking view. In this case, skip the window persistence step if it does not exist anymore by the time we are saving the persistence data. Currently eframe will panic with `winit window doesn't exist` instead. --- crates/eframe/src/native/epi_integration.rs | 20 +++++++++++--------- crates/eframe/src/native/run.rs | 8 ++++---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index 4409c1298..eeb7d485d 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -562,24 +562,26 @@ impl EpiIntegration { pub fn maybe_autosave(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) { let now = std::time::Instant::now(); if now - self.last_auto_save > app.auto_save_interval() { - self.save(app, window); + self.save(app, Some(window)); self.last_auto_save = now; } } #[allow(clippy::unused_self)] - pub fn save(&mut self, _app: &mut dyn epi::App, _window: &winit::window::Window) { + pub fn save(&mut self, _app: &mut dyn epi::App, _window: Option<&winit::window::Window>) { #[cfg(feature = "persistence")] if let Some(storage) = self.frame.storage_mut() { crate::profile_function!(); - if _app.persist_native_window() { - crate::profile_scope!("native_window"); - epi::set_value( - storage, - STORAGE_WINDOW_KEY, - &WindowSettings::from_display(_window), - ); + if let Some(window) = _window { + if _app.persist_native_window() { + crate::profile_scope!("native_window"); + epi::set_value( + storage, + STORAGE_WINDOW_KEY, + &WindowSettings::from_display(window), + ); + } } if _app.persist_egui_memory() { crate::profile_scope!("egui_memory"); diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 7771265a1..3b4cc5c46 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -801,7 +801,7 @@ mod glow_integration { if let Some(mut running) = self.running.take() { running .integration - .save(running.app.as_mut(), running.gl_window.window()); + .save(running.app.as_mut(), running.gl_window.window.as_ref()); running.app.on_exit(Some(&running.gl)); running.painter.destroy(); } @@ -1260,9 +1260,9 @@ mod wgpu_integration { fn save_and_destroy(&mut self) { if let Some(mut running) = self.running.take() { - if let Some(window) = &self.window { - running.integration.save(running.app.as_mut(), window); - } + running + .integration + .save(running.app.as_mut(), self.window.as_ref()); #[cfg(feature = "glow")] running.app.on_exit(None); From 9731cfd9cf61cf1836ca7e867a3d98a9c8de6e91 Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Wed, 9 Aug 2023 12:50:33 +0200 Subject: [PATCH 14/43] Update GitHub Actions CI (#3150) The following updates are performed: * update actions/checkout to v3 * replace unmaintained actions-rs/toolchain by dtolnay/rust-toolchain * replace unmaintained actions-rs/cargo by direct invocation of cargo --- .github/workflows/rust.yml | 110 +++++++++--------------------------- .github/workflows/typos.yml | 2 +- 2 files changed, 28 insertions(+), 84 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 201fec289..55865370a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -15,13 +15,11 @@ jobs: name: Format + check + test runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - profile: default toolchain: 1.65.0 - override: true - name: Install packages (Linux) if: runner.os == 'Linux' @@ -37,10 +35,7 @@ jobs: uses: Swatinem/rust-cache@v2 - name: Rustfmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + run: cargo fmt --all -- --check - name: Install cargo-cranky uses: baptiste0928/cargo-install@v1 @@ -48,70 +43,37 @@ jobs: crate: cargo-cranky - name: check --all-features - uses: actions-rs/cargo@v1 - with: - command: check - args: --locked --all-features --all-targets + run: cargo check --locked --all-features --all-targets - name: check egui_extras --all-features - uses: actions-rs/cargo@v1 - with: - command: check - args: --locked --all-features --all-targets -p egui_extras + run: cargo check --locked --all-features --all-targets -p egui_extras - name: check default features - uses: actions-rs/cargo@v1 - with: - command: check - args: --locked --all-targets + run: cargo check --locked --all-targets - name: check --no-default-features - uses: actions-rs/cargo@v1 - with: - command: check - args: --locked --no-default-features --lib --all-targets + run: cargo check --locked --no-default-features --lib --all-targets - name: check epaint --no-default-features - uses: actions-rs/cargo@v1 - with: - command: check - args: --locked --no-default-features --lib --all-targets -p epaint + run: cargo check --locked --no-default-features --lib --all-targets -p epaint - name: check eframe --no-default-features - uses: actions-rs/cargo@v1 - with: - command: check - args: --locked --no-default-features --lib --all-targets -p eframe + run: cargo check --locked --no-default-features --lib --all-targets -p eframe - name: Test doc-tests - uses: actions-rs/cargo@v1 - with: - command: test - args: --doc --all-features + run: cargo test --doc --all-features - name: cargo doc --lib - uses: actions-rs/cargo@v1 - with: - command: doc - args: --lib --no-deps --all-features + run: cargo doc --lib --no-deps --all-features - name: cargo doc --document-private-items - uses: actions-rs/cargo@v1 - with: - command: doc - args: --document-private-items --no-deps --all-features + run: cargo doc --document-private-items --no-deps --all-features - name: Test - uses: actions-rs/cargo@v1 - with: - command: test - args: --all-features + run: cargo test --all-features - name: Cranky - uses: actions-rs/cargo@v1 - with: - command: cranky - args: --all-targets --all-features -- -D warnings + run: cargo cranky --all-targets --all-features -- -D warnings # --------------------------------------------------------------------------- @@ -119,13 +81,11 @@ jobs: name: Check wasm32 + wasm-bindgen runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: 1.65.0 - target: wasm32-unknown-unknown - override: true + targets: wasm32-unknown-unknown - run: sudo apt-get update && sudo apt-get install libgtk-3-dev @@ -138,22 +98,13 @@ jobs: crate: cargo-cranky - name: Check wasm32 egui_demo_app - uses: actions-rs/cargo@v1 - with: - command: check - args: -p egui_demo_app --lib --target wasm32-unknown-unknown + run: cargo check -p egui_demo_app --lib --target wasm32-unknown-unknown - name: Check wasm32 egui_demo_app --all-features - uses: actions-rs/cargo@v1 - with: - command: check - args: -p egui_demo_app --lib --target wasm32-unknown-unknown --all-features + run: cargo check -p egui_demo_app --lib --target wasm32-unknown-unknown --all-features - name: Check wasm32 eframe - uses: actions-rs/cargo@v1 - with: - command: check - args: -p eframe --lib --no-default-features --features glow,persistence --target wasm32-unknown-unknown + run: cargo check -p eframe --lib --no-default-features --features glow,persistence --target wasm32-unknown-unknown - name: wasm-bindgen uses: jetli/wasm-bindgen-action@v0.1.0 @@ -188,7 +139,7 @@ jobs: name: cargo-deny ${{ matrix.target }} runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: EmbarkStudios/cargo-deny-action@v1 with: rust-version: "1.65.0" @@ -202,14 +153,12 @@ jobs: name: android runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: 1.65.0 - target: aarch64-linux-android - override: true + targets: aarch64-linux-android - name: Set up cargo cache uses: Swatinem/rust-cache@v2 @@ -223,18 +172,13 @@ jobs: name: Check Windows runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: 1.65.0 - override: true - name: Set up cargo cache uses: Swatinem/rust-cache@v2 - name: Check - uses: actions-rs/cargo@v1 - with: - command: check - args: --all-targets --all-features + run: cargo check --all-targets --all-features diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index c3bc84125..4f3ae1d8b 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Check spelling of entire workspace uses: crate-ci/typos@master From 9c15783fab8328a4de0bfdfa1c9218c926b3f4ab Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 9 Aug 2023 12:51:08 +0200 Subject: [PATCH 15/43] CI: update list of accepted PR labels --- .github/workflows/labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index e5292c15b..fe72e5870 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -29,4 +29,4 @@ jobs: with: mode: minimum count: 1 - labels: "ecolor, eframe, egui_extras, egui_glow, egui-wgpu, egui-winit, egui, epaint" + labels: "CI, dependencies, docs and examples, ecolor, eframe, egui_extras, egui_glow, egui-wgpu, egui-winit, egui, epaint" From 46daaa8a340ddcbae5491a0f720b7167fc211e54 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 9 Aug 2023 12:51:22 +0200 Subject: [PATCH 16/43] Improve PR template --- .github/pull_request_template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 57db1de4a..c00eac197 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,8 +4,8 @@ Please read the "Making a PR" section of [`CONTRIBUTING.md`](https://github.com/ * Keep your PR:s small and focused. * If applicable, add a screenshot or gif. * If it is a non-trivial addition, consider adding a demo for it to `egui_demo_lib`, or a new example. -* Do not open PR:s from your `master` branch, as thart makes it difficult for maintainers to add commits to your PR. -* Remember to run `cargo fmt` and `cargo clippy`. +* Do NOT open PR:s from your `master` branch, as that makes it hard for maintainers to add commits to your PR. +* Remember to run `cargo fmt` and `cargo cranky`. * Open the PR as a draft until you have self-reviewed it and run `./scripts/check.sh`. * When you have addressed a PR comment, mark it as resolved. From 20be0847c80624290d669e4228062d2dcfc8819b Mon Sep 17 00:00:00 2001 From: Yuan Chang Date: Wed, 9 Aug 2023 22:20:59 +0800 Subject: [PATCH 17/43] Add `into_inner` methods. (#3110) --- crates/epaint/src/mutex.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/epaint/src/mutex.rs b/crates/epaint/src/mutex.rs index f3a18bf15..cca86466e 100644 --- a/crates/epaint/src/mutex.rs +++ b/crates/epaint/src/mutex.rs @@ -82,6 +82,11 @@ mod mutex_impl { MutexGuard(self.0.lock(), ptr) } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0.into_inner() + } } impl Drop for MutexGuard<'_, T> { @@ -314,6 +319,11 @@ mod rw_lock_impl { holders: Arc::clone(&self.holders), } } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.lock.into_inner() + } } fn make_backtrace() -> backtrace::Backtrace { @@ -366,6 +376,11 @@ mod mutex_impl { pub fn lock(&self) -> MutexGuard<'_, T> { self.0.borrow_mut() } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0.into_inner() + } } } @@ -401,6 +416,11 @@ mod rw_lock_impl { pub fn write(&self) -> RwLockWriteGuard<'_, T> { self.0.borrow_mut() } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0.into_inner() + } } } From 35027d3ebe4ca04dd3a3ad02aeb1a5099615950c Mon Sep 17 00:00:00 2001 From: Ho Kim Date: Wed, 9 Aug 2023 14:24:32 +0000 Subject: [PATCH 18/43] Fix a document: `eframe::start_web` (#3026) In `0.22.0`, `eframe::start_web` has been replaced with `eframe::WebRunner`, which also installs a nice panic hook (no need for `console_error_panic_hook`). --- crates/eframe/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eframe/src/lib.rs b/crates/eframe/src/lib.rs index afa602cc9..8164e7e65 100644 --- a/crates/eframe/src/lib.rs +++ b/crates/eframe/src/lib.rs @@ -7,7 +7,7 @@ //! To learn how to set up `eframe` for web and native, go to and follow the instructions there! //! //! In short, you implement [`App`] (especially [`App::update`]) and then -//! call [`crate::run_native`] from your `main.rs`, and/or call `eframe::start_web` from your `lib.rs`. +//! call [`crate::run_native`] from your `main.rs`, and/or use `eframe::WebRunner` from your `lib.rs`. //! //! ## Usage, native: //! ``` no_run From e82ec74c5cc3a9e63f058580a283bf14025c4385 Mon Sep 17 00:00:00 2001 From: thomaseliot Date: Wed, 9 Aug 2023 07:46:45 -0700 Subject: [PATCH 19/43] epaint: Add `ColorImage::from_gray` (#3166) * epaint: Add from_gray_unmultiplied function * Rename to just `from_gray` --------- Co-authored-by: Emil Ernerfeldt --- crates/epaint/src/image.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/epaint/src/image.rs b/crates/epaint/src/image.rs index 35b0885c7..7ca33b3ac 100644 --- a/crates/epaint/src/image.rs +++ b/crates/epaint/src/image.rs @@ -110,6 +110,15 @@ impl ColorImage { Self { size, pixels } } + /// Create a [`ColorImage`] from flat opaque gray data. + /// + /// Panics if `size[0] * size[1] != gray.len()`. + pub fn from_gray(size: [usize; 2], gray: &[u8]) -> Self { + assert_eq!(size[0] * size[1], gray.len()); + let pixels = gray.iter().map(|p| Color32::from_gray(*p)).collect(); + Self { size, pixels } + } + /// A view of the underlying data as `&[u8]` #[cfg(feature = "bytemuck")] pub fn as_raw(&self) -> &[u8] { From cbdf748a3b49ba4f516cfba6def9c9c6bbf40c89 Mon Sep 17 00:00:00 2001 From: Nicolas Riebesel Date: Wed, 9 Aug 2023 16:47:46 +0200 Subject: [PATCH 20/43] egui: Plot Arrows add method to specify tip_size (#3138) Normally the tip_size will be dependent on the arrow length. This patch adds a new method to explicitly set the arrow tip size. --- crates/egui/src/widgets/plot/items/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/widgets/plot/items/mod.rs b/crates/egui/src/widgets/plot/items/mod.rs index e96d8b3b4..c56de6bb7 100644 --- a/crates/egui/src/widgets/plot/items/mod.rs +++ b/crates/egui/src/widgets/plot/items/mod.rs @@ -997,6 +997,7 @@ impl PlotItem for Points { pub struct Arrows { pub(super) origins: PlotPoints, pub(super) tips: PlotPoints, + pub(super) tip_length: Option, pub(super) color: Color32, pub(super) name: String, pub(super) highlight: bool, @@ -1007,6 +1008,7 @@ impl Arrows { Self { origins: origins.into(), tips: tips.into(), + tip_length: None, color: Color32::TRANSPARENT, name: Default::default(), highlight: false, @@ -1019,6 +1021,12 @@ impl Arrows { self } + /// Set the length of the arrow tips + pub fn tip_length(mut self, tip_length: f32) -> Self { + self.tip_length = Some(tip_length); + self + } + /// Set the arrows' color. pub fn color(mut self, color: impl Into) -> Self { self.color = color.into(); @@ -1044,6 +1052,7 @@ impl PlotItem for Arrows { let Self { origins, tips, + tip_length, color, highlight, .. @@ -1062,7 +1071,11 @@ impl PlotItem for Arrows { .for_each(|(origin, tip)| { let vector = tip - origin; let rot = Rot2::from_angle(std::f32::consts::TAU / 10.0); - let tip_length = vector.length() / 4.0; + let tip_length = if let Some(tip_length) = tip_length { + *tip_length + } else { + vector.length() / 4.0 + }; let tip = origin + vector; let dir = vector.normalized(); shapes.push(Shape::line_segment([origin, tip], stroke)); From f2769f30101ea73c53578ea2cbbc6c9bc89fd82b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20D=C3=ADaz?= <49416765+AgustinRamiroDiaz@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:48:21 -0300 Subject: [PATCH 21/43] Fix dobule "for" typo (#3189) --- crates/egui_extras/src/strip.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/egui_extras/src/strip.rs b/crates/egui_extras/src/strip.rs index 52a768f35..86b8db3e2 100644 --- a/crates/egui_extras/src/strip.rs +++ b/crates/egui_extras/src/strip.rs @@ -72,13 +72,13 @@ impl<'a> StripBuilder<'a> { self } - /// Allocate space for for one column/row. + /// Allocate space for one column/row. pub fn size(mut self, size: Size) -> Self { self.sizing.add(size); self } - /// Allocate space for for several columns/rows at once. + /// Allocate space for several columns/rows at once. pub fn sizes(mut self, size: Size, count: usize) -> Self { for _ in 0..count { self.sizing.add(size); From b2b6558c78ee8a85d778f2c885639a45a7eab87f Mon Sep 17 00:00:00 2001 From: Steven Weiss Date: Wed, 9 Aug 2023 08:06:33 -0700 Subject: [PATCH 22/43] Tiny PR: Document available_width() and available_height() (#3130) * Update ui.rs docs to clarify available_size and co Added docs to the available_width() and available_height() methods. Added a quick note about the wrapping versions of the methods as well. * fix a couple of typos, and use code-style for doc-links * fix doclinks --------- Co-authored-by: Emil Ernerfeldt --- crates/egui/src/ui.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 13b3e81f1..4e4b4559d 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -556,6 +556,7 @@ impl Ui { // Layout related measures: /// The available space at the moment, given the current cursor. + /// /// This how much more space we can take up without overflowing our parent. /// Shrinks as widgets allocate space and the cursor moves. /// A small size should be interpreted as "as little as possible". @@ -564,19 +565,30 @@ impl Ui { self.placer.available_size() } + /// The available width at the moment, given the current cursor. + /// + /// See [`Self::available_size`] for more information. pub fn available_width(&self) -> f32 { self.available_size().x } + /// The available height at the moment, given the current cursor. + /// + /// See [`Self::available_size`] for more information. pub fn available_height(&self) -> f32 { self.available_size().y } /// In case of a wrapping layout, how much space is left on this row/column? + /// + /// If the layout does not wrap, this will return the same value as [`Self::available_size`]. pub fn available_size_before_wrap(&self) -> Vec2 { self.placer.available_rect_before_wrap().size() } + /// In case of a wrapping layout, how much space is left on this row/column? + /// + /// If the layout does not wrap, this will return the same value as [`Self::available_size`]. pub fn available_rect_before_wrap(&self) -> Rect { self.placer.available_rect_before_wrap() } From 92593b70facdf3af1cae32ea5fa4ba612cfe43be Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 9 Aug 2023 17:12:47 +0200 Subject: [PATCH 23/43] Changelogs: document that they are updated upon release (not by users) --- CHANGELOG.md | 4 ++-- crates/ecolor/CHANGELOG.md | 3 ++- crates/eframe/CHANGELOG.md | 4 ++-- crates/egui-wgpu/CHANGELOG.md | 4 ++-- crates/egui-winit/CHANGELOG.md | 4 ++-- crates/egui_extras/CHANGELOG.md | 4 ++-- crates/egui_glium/CHANGELOG.md | 3 +++ crates/egui_glow/CHANGELOG.md | 4 ++-- crates/epaint/CHANGELOG.md | 3 ++- 9 files changed, 19 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cddbc286a..fc129dd8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,8 @@ All notable changes to the `egui` crate will be documented in this file. NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG.md), [`egui-winit`](crates/egui-winit/CHANGELOG.md), [`egui_glium`](crates/egui_glium/CHANGELOG.md), [`egui_glow`](crates/egui_glow/CHANGELOG.md) and [`egui-wgpu`](crates/egui-wgpu/CHANGELOG.md) have their own changelogs! - -## Unreleased +This file is updated upon each release. +Changes since the last release can be found by running the `scripts/generate_changelog.py` script. ## 0.22.0 - 2023-05-23 - A plethora of small improvements diff --git a/crates/ecolor/CHANGELOG.md b/crates/ecolor/CHANGELOG.md index f4a3e1d72..228275e04 100644 --- a/crates/ecolor/CHANGELOG.md +++ b/crates/ecolor/CHANGELOG.md @@ -2,7 +2,8 @@ All notable changes to the `ecolor` crate will be noted in this file. -## Unreleased +This file is updated upon each release. +Changes since the last release can be found by running the `scripts/generate_changelog.py` script. ## 0.22.0 - 2023-05-23 diff --git a/crates/eframe/CHANGELOG.md b/crates/eframe/CHANGELOG.md index 37eb3b985..072a54e8c 100644 --- a/crates/eframe/CHANGELOG.md +++ b/crates/eframe/CHANGELOG.md @@ -3,9 +3,9 @@ All notable changes to the `eframe` crate. NOTE: [`egui-winit`](../egui-winit/CHANGELOG.md), [`egui_glium`](../egui_glium/CHANGELOG.md), [`egui_glow`](../egui_glow/CHANGELOG.md),and [`egui-wgpu`](../egui-wgpu/CHANGELOG.md) have their own changelogs! +This file is updated upon each release. +Changes since the last release can be found by running the `scripts/generate_changelog.py` script. -## Unreleased -* Expose raw window and display handles in `CreationContext` and `Frame` ## 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) diff --git a/crates/egui-wgpu/CHANGELOG.md b/crates/egui-wgpu/CHANGELOG.md index ecae53cfd..d7cbee4d1 100644 --- a/crates/egui-wgpu/CHANGELOG.md +++ b/crates/egui-wgpu/CHANGELOG.md @@ -2,8 +2,8 @@ All notable changes to the `egui-wgpu` integration will be noted in this file. -## Unreleased -* Fix panic on wgpu GL backend due to new screenshot capability ([#3068](https://github.com/emilk/egui/issues/3068), [#3078](https://github.com/emilk/egui/pull/3078) +This file is updated upon each release. +Changes since the last release can be found by running the `scripts/generate_changelog.py` script. ## 0.22.0 - 2023-05-23 diff --git a/crates/egui-winit/CHANGELOG.md b/crates/egui-winit/CHANGELOG.md index af64b1b46..d181b99b4 100644 --- a/crates/egui-winit/CHANGELOG.md +++ b/crates/egui-winit/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog for egui-winit All notable changes to the `egui-winit` integration will be noted in this file. - -## Unreleased +This file is updated upon each release. +Changes since the last release can be found by running the `scripts/generate_changelog.py` script. ## 0.22.0 - 2023-05-23 diff --git a/crates/egui_extras/CHANGELOG.md b/crates/egui_extras/CHANGELOG.md index ab60317d6..3a968179b 100644 --- a/crates/egui_extras/CHANGELOG.md +++ b/crates/egui_extras/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog for egui_extras All notable changes to the `egui_extras` integration will be noted in this file. - -## Unreleased +This file is updated upon each release. +Changes since the last release can be found by running the `scripts/generate_changelog.py` script. ## 0.22.0 - 2023-05-23 diff --git a/crates/egui_glium/CHANGELOG.md b/crates/egui_glium/CHANGELOG.md index a34c23416..c1e98201d 100644 --- a/crates/egui_glium/CHANGELOG.md +++ b/crates/egui_glium/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog for egui_glium All notable changes to the `egui_glium` 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. + ## Unreleased * Remove the `screen_reader` feature ([#2669](https://github.com/emilk/egui/pull/2669)). diff --git a/crates/egui_glow/CHANGELOG.md b/crates/egui_glow/CHANGELOG.md index a3dc5acfa..3710edab4 100644 --- a/crates/egui_glow/CHANGELOG.md +++ b/crates/egui_glow/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog for egui_glow All notable changes to the `egui_glow` integration will be noted in this file. - -## Unreleased +This file is updated upon each release. +Changes since the last release can be found by running the `scripts/generate_changelog.py` script. ## 0.22.0 - 2023-05-23 diff --git a/crates/epaint/CHANGELOG.md b/crates/epaint/CHANGELOG.md index ebe9e6f6e..e0f4e0569 100644 --- a/crates/epaint/CHANGELOG.md +++ b/crates/epaint/CHANGELOG.md @@ -1,8 +1,9 @@ # epaint changelog All notable changes to the epaint crate will be documented 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. -## Unreleased ## 0.22.0 - 2023-05-23 From 51da2ac490da3f50b15ed6e6b93bc289ff3f61bd Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 9 Aug 2023 17:13:10 +0200 Subject: [PATCH 24/43] Improve documentation of Window/Area::resizable --- crates/egui/src/containers/resize.rs | 5 ++++- crates/egui/src/containers/window.rs | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/containers/resize.rs b/crates/egui/src/containers/resize.rs index befb51a10..2f71a57c0 100644 --- a/crates/egui/src/containers/resize.rs +++ b/crates/egui/src/containers/resize.rs @@ -124,7 +124,10 @@ impl Resize { } /// Can you resize it with the mouse? - /// Note that a window can still auto-resize + /// + /// Note that a window can still auto-resize. + /// + /// Default is `true`. pub fn resizable(mut self, resizable: bool) -> Self { self.resizable = resizable; self diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index d5c3f680f..1d2444ca3 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -217,7 +217,10 @@ impl<'open> Window<'open> { } /// Can the user resize the window by dragging its edges? + /// /// Note that even if you set this to `false` the window may still auto-resize. + /// + /// Default is `true`. pub fn resizable(mut self, resizable: bool) -> Self { self.resize = self.resize.resizable(resizable); self From abe91b00a47e54f6b37c917c1f6a0f0f8696c995 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 9 Aug 2023 17:13:22 +0200 Subject: [PATCH 25/43] Improve generate_changelog.py --- .github/workflows/labels.yml | 2 +- scripts/generate_changelog.py | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index fe72e5870..193ac9134 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -29,4 +29,4 @@ jobs: with: mode: minimum count: 1 - labels: "CI, dependencies, docs and examples, ecolor, eframe, egui_extras, egui_glow, egui-wgpu, egui-winit, egui, epaint" + labels: "CI, dependencies, docs and examples, ecolor, eframe, egui_extras, egui_glow, egui-wgpu, egui-winit, egui, epaint, plot, typo" diff --git a/scripts/generate_changelog.py b/scripts/generate_changelog.py index 3431bf985..2e97d01b2 100755 --- a/scripts/generate_changelog.py +++ b/scripts/generate_changelog.py @@ -141,6 +141,8 @@ def main() -> None: unsorted_prs = [] unsorted_commits = [] + plot = [] + for commit_info, pr_info in zip(commit_infos, pr_infos): hexsha = commit_info.hexsha title = commit_info.title @@ -164,11 +166,18 @@ def main() -> None: if gh_user_name not in OFFICIAL_DEVS: summary += f" (thanks [@{gh_user_name}](https://github.com/{gh_user_name})!)" + if 'typo' in labels: + continue # We get so many typo PRs. Let's not flood the changelog with them. + added = False - for crate in crate_names: - if crate in labels: - sections.setdefault(crate, []).append(summary) - added = True + if 'plot' in labels: + plot.append(summary) + added = True + else: + for crate in crate_names: + if crate in labels: + sections.setdefault(crate, []).append(summary) + added = True if not added: if not any(label in labels for label in ignore_labels): @@ -179,6 +188,9 @@ def main() -> None: if crate in sections: summary = sections[crate] print_section(crate, summary) + if crate == 'egui': + if 0 < len(plot): + print_section("egui plot", plot) print_section("Unsorted PRs", unsorted_prs) print_section("Unsorted commits", unsorted_commits) From f9f9abf7496e41ae9b67201f08452fdbdffc8382 Mon Sep 17 00:00:00 2001 From: Barugon <16503728+Barugon@users.noreply.github.com> Date: Wed, 9 Aug 2023 08:13:58 -0700 Subject: [PATCH 26/43] `DragValue`: update value on each key press by default (#2880) * Use `Response::changed` to fix editing issues * Update comment * Make update while editing an option * improve docstring --------- Co-authored-by: Emil Ernerfeldt --- crates/egui/src/widgets/drag_value.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 0d33978f2..1a965d4e1 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -63,6 +63,7 @@ pub struct DragValue<'a> { max_decimals: Option, custom_formatter: Option>, custom_parser: Option>, + update_while_editing: bool, } impl<'a> DragValue<'a> { @@ -94,6 +95,7 @@ impl<'a> DragValue<'a> { max_decimals: None, custom_formatter: None, custom_parser: None, + update_while_editing: true, } } @@ -352,6 +354,15 @@ impl<'a> DragValue<'a> { } .custom_parser(|s| i64::from_str_radix(s, 16).map(|n| n as f64).ok()) } + + /// Update the value on each key press when text-editing the value. + /// + /// Default: `true`. + /// If `false`, the value will only be updated when user presses enter or deselects the value. + pub fn update_while_editing(mut self, update: bool) -> Self { + self.update_while_editing = update; + self + } } impl<'a> Widget for DragValue<'a> { @@ -366,6 +377,7 @@ impl<'a> Widget for DragValue<'a> { max_decimals, custom_formatter, custom_parser, + update_while_editing, } = self; let shift = ui.input(|i| i.modifiers.shift_only()); @@ -475,9 +487,15 @@ impl<'a> Widget for DragValue<'a> { .desired_width(ui.spacing().interact_size.x) .font(text_style), ); - // Only update the value when the user presses enter, or clicks elsewhere. NOT every frame. - // See https://github.com/emilk/egui/issues/2687 - if response.lost_focus() { + + let update = if update_while_editing { + // Update when the edit content has changed. + response.changed() + } else { + // Update only when the edit has lost focus. + response.lost_focus() + }; + if update { let parsed_value = match custom_parser { Some(parser) => parser(&value_text), None => value_text.parse().ok(), From af6419343d8e864e0c9afaa559363315abb55424 Mon Sep 17 00:00:00 2001 From: mauliu <67208725+mauliu@users.noreply.github.com> Date: Wed, 9 Aug 2023 20:59:36 +0200 Subject: [PATCH 27/43] fix depth texture init with multisampling (#3207) Co-authored-by: user --- crates/egui-wgpu/src/winit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/egui-wgpu/src/winit.rs b/crates/egui-wgpu/src/winit.rs index 7b6a9b180..171d5f08e 100644 --- a/crates/egui-wgpu/src/winit.rs +++ b/crates/egui-wgpu/src/winit.rs @@ -279,7 +279,7 @@ impl Painter { depth_or_array_layers: 1, }, mip_level_count: 1, - sample_count: 1, + sample_count: self.msaa_samples, dimension: wgpu::TextureDimension::D2, format: depth_format, usage: wgpu::TextureUsages::RENDER_ATTACHMENT From f2a58244c8e27ceeb9a95abd2573bc9b20979ca3 Mon Sep 17 00:00:00 2001 From: jacekpoz <64381190+jacekpoz@users.noreply.github.com> Date: Thu, 10 Aug 2023 09:50:15 +0200 Subject: [PATCH 28/43] fix the title not being used when app_id is not set (#3107) Co-authored-by: jacekpoz --- crates/eframe/src/native/epi_integration.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index eeb7d485d..faed7360c 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -121,9 +121,12 @@ pub fn window_builder( } #[cfg(all(feature = "wayland", target_os = "linux"))] - if let Some(app_id) = &native_options.app_id { + { use winit::platform::wayland::WindowBuilderExtWayland as _; - window_builder = window_builder.with_name(app_id, ""); + match &native_options.app_id { + Some(app_id) => window_builder = window_builder.with_name(app_id, ""), + None => window_builder = window_builder.with_name(title, ""), + } } if let Some(min_size) = *min_window_size { From 01b1b2da761f618ec1a89f21c76f7bc1c1c6ac99 Mon Sep 17 00:00:00 2001 From: Roshan Mehta Date: Thu, 10 Aug 2023 00:50:25 -0700 Subject: [PATCH 29/43] rotation feature to plot images (#3121) --- crates/egui/src/widgets/plot/items/mod.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/egui/src/widgets/plot/items/mod.rs b/crates/egui/src/widgets/plot/items/mod.rs index c56de6bb7..3f21b0e83 100644 --- a/crates/egui/src/widgets/plot/items/mod.rs +++ b/crates/egui/src/widgets/plot/items/mod.rs @@ -1132,6 +1132,7 @@ pub struct PlotImage { pub(super) tint: Color32, pub(super) highlight: bool, pub(super) name: String, + pub(crate) rotation: Option<(f32, Vec2)>, } impl PlotImage { @@ -1150,6 +1151,7 @@ impl PlotImage { size: size.into(), bg_fill: Default::default(), tint: Color32::WHITE, + rotation: None, } } @@ -1188,6 +1190,17 @@ impl PlotImage { self.name = name.to_string(); self } + + /// Rotate the image about an origin by some angle + /// + /// Positive angle is clockwise. + /// Origin is a vector in normalized UV space ((0,0) in top-left, (1,1) bottom right). + /// + /// To rotate about the center you can pass `Vec2::splat(0.5)` as the origin. + pub fn rotate(mut self, angle: f32, origin: Vec2) -> Self { + self.rotation = Some((angle, origin)); + self + } } impl PlotItem for PlotImage { @@ -1215,11 +1228,14 @@ impl PlotItem for PlotImage { let right_bottom_tf = transform.position_from_point(&right_bottom); Rect::from_two_pos(left_top_tf, right_bottom_tf) }; - Image::new(*texture_id, *size) + let mut image = Image::new(*texture_id, *size) .bg_fill(*bg_fill) .tint(*tint) - .uv(*uv) - .paint_at(ui, rect); + .uv(*uv); + if let Some((angle, origin)) = self.rotation { + image = image.rotate(angle, origin); + } + image.paint_at(ui, rect); if *highlight { shapes.push(Shape::rect_stroke( rect, From 871041c4e7cd2d38bda7d2e0c57002b631a8618e Mon Sep 17 00:00:00 2001 From: hacknus <33124824+hacknus@users.noreply.github.com> Date: Thu, 10 Aug 2023 12:35:11 +0200 Subject: [PATCH 30/43] Added an example to save plot to image (#2769) * implement save_plot * fix for check.sh * clippy * add save_plot to Cargo.lock * adapted for PR #2676 (removes unsafe code) * add some comments * implemented the comments from emilk * update comments in code * rustfmt * remove picked_path * add more comments * removed unused import * use `inner.response.rect` as the plot position * remove plot_location from MyApp members * sort entries * Update examples/save_plot/src/main.rs Co-authored-by: Emil Ernerfeldt * use env_logger instead of tracing subscriber * use env_logger instead of tracing subscriber and combine if let --------- Co-authored-by: Emil Ernerfeldt --- Cargo.lock | 10 ++++ examples/save_plot/Cargo.toml | 16 ++++++ examples/save_plot/README.md | 5 ++ examples/save_plot/src/main.rs | 99 ++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 examples/save_plot/Cargo.toml create mode 100644 examples/save_plot/README.md create mode 100644 examples/save_plot/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 632040aa4..37dd41bc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3102,6 +3102,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "save_plot" +version = "0.1.0" +dependencies = [ + "eframe", + "env_logger", + "image", + "rfd", +] + [[package]] name = "scoped-tls" version = "1.0.1" diff --git a/examples/save_plot/Cargo.toml b/examples/save_plot/Cargo.toml new file mode 100644 index 000000000..83f919d79 --- /dev/null +++ b/examples/save_plot/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "save_plot" +version = "0.1.0" +authors = ["hacknus "] +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.65" +publish = false + +[dependencies] +eframe = { path = "../../crates/eframe", features = [ + "__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO +] } +image = { version = "0.24", default-features = false, features = ["png"] } +rfd = "0.11.0" +env_logger = "0.10" diff --git a/examples/save_plot/README.md b/examples/save_plot/README.md new file mode 100644 index 000000000..523af1d6b --- /dev/null +++ b/examples/save_plot/README.md @@ -0,0 +1,5 @@ +This example shows that you can save a plot in egui as a png. + +```sh +cargo run -p save_plot +``` diff --git a/examples/save_plot/src/main.rs b/examples/save_plot/src/main.rs new file mode 100644 index 000000000..68c48182a --- /dev/null +++ b/examples/save_plot/src/main.rs @@ -0,0 +1,99 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +use eframe::egui; +use eframe::egui::plot::{Legend, Line, Plot, PlotPoints}; +use eframe::egui::ColorImage; + +fn main() -> Result<(), eframe::Error> { + env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`). + + let options = eframe::NativeOptions { + initial_window_size: Some(egui::vec2(350.0, 400.0)), + ..Default::default() + }; + eframe::run_native( + "My egui App with a plot", + options, + Box::new(|_cc| Box::new(MyApp::default())), + ) +} + +#[derive(Default)] +struct MyApp { + screenshot: Option, +} + +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + let mut plot_rect = None; + egui::CentralPanel::default().show(ctx, |ui| { + // these are just some dummy variables for the example, + // such that the plot is not at position (0,0) + let height = 200.0; + let border_x = 11.0; + let border_y = 18.0; + let width = 300.0; + + ui.heading("My egui Application"); + + // add some whitespace in y direction + ui.add_space(border_y); + + if ui.button("Save Plot").clicked() { + frame.request_screenshot(); + } + + // add some whitespace in y direction + ui.add_space(border_y); + + ui.horizontal(|ui| { + // add some whitespace in x direction + ui.add_space(border_x); + + let my_plot = Plot::new("My Plot") + .height(height) + .width(width) + .legend(Legend::default()); + + // let's create a dummy line in the plot + let graph: Vec<[f64; 2]> = vec![[0.0, 1.0], [2.0, 3.0], [3.0, 2.0]]; + let inner = my_plot.show(ui, |plot_ui| { + plot_ui.line(Line::new(PlotPoints::from(graph)).name("curve")); + }); + // Remember the position of the plot + plot_rect = Some(inner.response.rect); + }); + + // add some whitespace in y direction + ui.add_space(border_y); + }); + + if let (Some(screenshot), Some(plot_location)) = (self.screenshot.take(), plot_rect) { + if let Some(mut path) = rfd::FileDialog::new().save_file() { + path.set_extension("png"); + + // for a full size application, we should put this in a different thread, + // so that the GUI doesn't lag during saving + + let pixels_per_point = frame.info().native_pixels_per_point; + let plot = screenshot.region(&plot_location, pixels_per_point); + // save the plot to png + image::save_buffer( + &path, + plot.as_raw(), + plot.width() as u32, + plot.height() as u32, + image::ColorType::Rgba8, + ) + .unwrap(); + } + } + } + + fn post_rendering(&mut self, _screen_size_px: [u32; 2], frame: &eframe::Frame) { + // this is inspired by the Egui screenshot example + if let Some(screenshot) = frame.screenshot() { + self.screenshot = Some(screenshot); + } + } +} From 4c3b380889af5ad3c8b97d7193a3fa69a9f9443d Mon Sep 17 00:00:00 2001 From: "Valeriy V. Vorotyntsev" Date: Thu, 10 Aug 2023 13:35:40 +0300 Subject: [PATCH 31/43] Fix the "ever-growing height" problem of Strip and Table demos (#3122) * Fix the "ever-growing height" problem of Strip and Table Demos Problem ------- The height of "Table Demo" or "Strip Demo" floating window grows when the demo app is interacted with. If 'Continuous' mode is enabled in 'Backend' settings, the window grows irrespectively of user interaction. Observations ------------ I noticed that [`area_content_ui.min_rect().max.y`][1] is increasing monotonically with speed 0.5 px/frame. I also noticed that commenting out `ui.add(crate::egui_github_link_file!());` [statement][2] in `table_demo.rs` makes the problem disappear. The "Fix" --------- I added 0.5 to the height of the row with GitHub link. This solved the problem. Closes #3029. Warning ------- I failed to find the root cause of the problem. I don't understand why this change makes the problem disappear. [1]: https://github.com/emilk/egui/blob/9478e50d012c5138551c38cbee16b07bc1fcf283/crates/egui/src/containers/window.rs#L403 [2]: https://github.com/emilk/egui/blob/9478e50d012c5138551c38cbee16b07bc1fcf283/crates/egui_demo_lib/src/demo/table_demo.rs#L114 * Document `Rect::size` Other changes: - `area.rs`: Use existing API. - `table_demo.rs`: Remove unnecessary call. --- crates/egui/src/containers/area.rs | 2 +- crates/egui_demo_lib/src/demo/strip_demo.rs | 2 +- crates/egui_demo_lib/src/demo/table_demo.rs | 3 +-- crates/emath/src/rect.rs | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/egui/src/containers/area.rs b/crates/egui/src/containers/area.rs index 380c175b3..953391cad 100644 --- a/crates/egui/src/containers/area.rs +++ b/crates/egui/src/containers/area.rs @@ -426,7 +426,7 @@ impl Prepared { temporarily_invisible: _, } = self; - state.size = content_ui.min_rect().size(); + state.size = content_ui.min_size(); ctx.memory_mut(|m| m.areas.set_state(layer_id, state)); diff --git a/crates/egui_demo_lib/src/demo/strip_demo.rs b/crates/egui_demo_lib/src/demo/strip_demo.rs index 2e9038b3a..db42fcb0b 100644 --- a/crates/egui_demo_lib/src/demo/strip_demo.rs +++ b/crates/egui_demo_lib/src/demo/strip_demo.rs @@ -37,7 +37,7 @@ impl super::View for StripDemo { .size(Size::exact(50.0)) .size(Size::remainder()) .size(Size::relative(0.5).at_least(60.0)) - .size(Size::exact(10.0)) + .size(Size::exact(10.5)) .vertical(|mut strip| { strip.cell(|ui| { ui.painter().rect_filled( diff --git a/crates/egui_demo_lib/src/demo/table_demo.rs b/crates/egui_demo_lib/src/demo/table_demo.rs index 8fdea4202..6523805ba 100644 --- a/crates/egui_demo_lib/src/demo/table_demo.rs +++ b/crates/egui_demo_lib/src/demo/table_demo.rs @@ -38,7 +38,6 @@ impl super::Demo for TableDemo { fn show(&mut self, ctx: &egui::Context, open: &mut bool) { egui::Window::new(self.name()) .open(open) - .resizable(true) .default_width(400.0) .show(ctx, |ui| { use super::View as _; @@ -102,7 +101,7 @@ impl super::View for TableDemo { use egui_extras::{Size, StripBuilder}; StripBuilder::new(ui) .size(Size::remainder().at_least(100.0)) // for the table - .size(Size::exact(10.0)) // for the source code link + .size(Size::exact(10.5)) // for the source code link .vertical(|mut strip| { strip.cell(|ui| { egui::ScrollArea::horizontal().show(ui, |ui| { diff --git a/crates/emath/src/rect.rs b/crates/emath/src/rect.rs index b8c6085a2..de115b985 100644 --- a/crates/emath/src/rect.rs +++ b/crates/emath/src/rect.rs @@ -280,6 +280,7 @@ impl Rect { } } + /// `rect.size() == Vec2 { x: rect.width(), y: rect.height() }` #[inline(always)] pub fn size(&self) -> Vec2 { self.max - self.min From 8cdffc4e2d66d54f3059b3a31fac924f630dce8b Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 10 Aug 2023 13:07:00 +0200 Subject: [PATCH 32/43] Replace uses of `RangeInclusive` with `emath::Rangef` (#3221) * Replace uses of `RangeInclusive` with `emath::Rangef` * Fix doc-test --- crates/egui/src/containers/panel.rs | 71 ++++++++++++----------- crates/egui/src/containers/scroll_area.rs | 3 +- crates/egui/src/frame_state.rs | 4 +- crates/egui/src/lib.rs | 4 +- crates/egui/src/painter.rs | 7 +-- crates/egui/src/ui.rs | 20 ++++--- crates/egui/src/widgets/slider.rs | 39 ++++++------- crates/egui_extras/src/sizing.rs | 42 ++++++-------- crates/egui_extras/src/table.rs | 54 +++++++++-------- crates/emath/src/align.rs | 18 +++--- crates/emath/src/lib.rs | 15 ++++- crates/emath/src/range.rs | 64 +++++++++++++++++++- crates/emath/src/rect.rs | 22 +++---- crates/epaint/src/shape.rs | 11 ++-- 14 files changed, 213 insertions(+), 161 deletions(-) diff --git a/crates/egui/src/containers/panel.rs b/crates/egui/src/containers/panel.rs index d829ac219..f5267e0f0 100644 --- a/crates/egui/src/containers/panel.rs +++ b/crates/egui/src/containers/panel.rs @@ -15,8 +15,6 @@ //! //! Add your [`Window`]:s after any top-level panels. -use std::ops::RangeInclusive; - use crate::*; /// State regarding panels. @@ -99,7 +97,7 @@ pub struct SidePanel { resizable: bool, show_separator_line: bool, default_width: f32, - width_range: RangeInclusive, + width_range: Rangef, } impl SidePanel { @@ -122,7 +120,7 @@ impl SidePanel { resizable: true, show_separator_line: true, default_width: 200.0, - width_range: 96.0..=f32::INFINITY, + width_range: Rangef::new(96.0, f32::INFINITY), } } @@ -153,26 +151,29 @@ impl SidePanel { /// The initial wrapping width of the [`SidePanel`]. pub fn default_width(mut self, default_width: f32) -> Self { self.default_width = default_width; - self.width_range = self.width_range.start().at_most(default_width) - ..=self.width_range.end().at_least(default_width); + self.width_range = Rangef::new( + self.width_range.min.at_most(default_width), + self.width_range.max.at_least(default_width), + ); self } /// Minimum width of the panel. pub fn min_width(mut self, min_width: f32) -> Self { - self.width_range = min_width..=self.width_range.end().at_least(min_width); + self.width_range = Rangef::new(min_width, self.width_range.max.at_least(min_width)); self } /// Maximum width of the panel. pub fn max_width(mut self, max_width: f32) -> Self { - self.width_range = self.width_range.start().at_most(max_width)..=max_width; + self.width_range = Rangef::new(self.width_range.min.at_most(max_width), max_width); self } /// The allowable width range for the panel. - pub fn width_range(mut self, width_range: RangeInclusive) -> Self { - self.default_width = clamp_to_range(self.default_width, width_range.clone()); + pub fn width_range(mut self, width_range: impl Into) -> Self { + let width_range = width_range.into(); + self.default_width = clamp_to_range(self.default_width, width_range); self.width_range = width_range; self } @@ -180,7 +181,7 @@ impl SidePanel { /// Enforce this exact width. pub fn exact_width(mut self, width: f32) -> Self { self.default_width = width; - self.width_range = width..=width; + self.width_range = Rangef::point(width); self } @@ -224,7 +225,7 @@ impl SidePanel { if let Some(state) = PanelState::load(ui.ctx(), id) { width = state.rect.width(); } - width = clamp_to_range(width, width_range.clone()).at_most(available_rect.width()); + width = clamp_to_range(width, width_range).at_most(available_rect.width()); side.set_rect_width(&mut panel_rect, width); ui.ctx().check_for_id_clash(id, panel_rect, "SidePanel"); } @@ -241,7 +242,7 @@ impl SidePanel { let resize_x = side.opposite().side_x(panel_rect); let mouse_over_resize_line = we_are_on_top - && panel_rect.y_range().contains(&pointer.y) + && panel_rect.y_range().contains(pointer.y) && (resize_x - pointer.x).abs() <= ui.style().interaction.resize_grab_radius_side; @@ -253,8 +254,7 @@ impl SidePanel { is_resizing = ui.memory(|mem| mem.is_being_dragged(resize_id)); if is_resizing { let width = (pointer.x - side.side_x(panel_rect)).abs(); - let width = - clamp_to_range(width, width_range.clone()).at_most(available_rect.width()); + let width = clamp_to_range(width, width_range).at_most(available_rect.width()); side.set_rect_width(&mut panel_rect, width); } @@ -273,7 +273,7 @@ impl SidePanel { let frame = frame.unwrap_or_else(|| Frame::side_top_panel(ui.style())); let inner_response = frame.show(&mut panel_ui, |ui| { ui.set_min_height(ui.max_rect().height()); // Make sure the frame fills the full height - ui.set_min_width(*width_range.start()); + ui.set_min_width(width_range.min); add_contents(ui) }); @@ -544,7 +544,7 @@ pub struct TopBottomPanel { resizable: bool, show_separator_line: bool, default_height: Option, - height_range: RangeInclusive, + height_range: Rangef, } impl TopBottomPanel { @@ -567,7 +567,7 @@ impl TopBottomPanel { resizable: false, show_separator_line: true, default_height: None, - height_range: 20.0..=f32::INFINITY, + height_range: Rangef::new(20.0, f32::INFINITY), } } @@ -599,28 +599,31 @@ impl TopBottomPanel { /// Defaults to [`style::Spacing::interact_size`].y. pub fn default_height(mut self, default_height: f32) -> Self { self.default_height = Some(default_height); - self.height_range = self.height_range.start().at_most(default_height) - ..=self.height_range.end().at_least(default_height); + self.height_range = Rangef::new( + self.height_range.min.at_most(default_height), + self.height_range.max.at_least(default_height), + ); self } /// Minimum height of the panel. pub fn min_height(mut self, min_height: f32) -> Self { - self.height_range = min_height..=self.height_range.end().at_least(min_height); + self.height_range = Rangef::new(min_height, self.height_range.max.at_least(min_height)); self } /// Maximum height of the panel. pub fn max_height(mut self, max_height: f32) -> Self { - self.height_range = self.height_range.start().at_most(max_height)..=max_height; + self.height_range = Rangef::new(self.height_range.min.at_most(max_height), max_height); self } /// The allowable height range for the panel. - pub fn height_range(mut self, height_range: RangeInclusive) -> Self { + pub fn height_range(mut self, height_range: impl Into) -> Self { + let height_range = height_range.into(); self.default_height = self .default_height - .map(|default_height| clamp_to_range(default_height, height_range.clone())); + .map(|default_height| clamp_to_range(default_height, height_range)); self.height_range = height_range; self } @@ -628,7 +631,7 @@ impl TopBottomPanel { /// Enforce this exact height. pub fn exact_height(mut self, height: f32) -> Self { self.default_height = Some(height); - self.height_range = height..=height; + self.height_range = Rangef::point(height); self } @@ -673,7 +676,7 @@ impl TopBottomPanel { } else { default_height.unwrap_or_else(|| ui.style().spacing.interact_size.y) }; - height = clamp_to_range(height, height_range.clone()).at_most(available_rect.height()); + height = clamp_to_range(height, height_range).at_most(available_rect.height()); side.set_rect_height(&mut panel_rect, height); ui.ctx() .check_for_id_clash(id, panel_rect, "TopBottomPanel"); @@ -692,7 +695,7 @@ impl TopBottomPanel { let resize_y = side.opposite().side_y(panel_rect); let mouse_over_resize_line = we_are_on_top - && panel_rect.x_range().contains(&pointer.x) + && panel_rect.x_range().contains(pointer.x) && (resize_y - pointer.y).abs() <= ui.style().interaction.resize_grab_radius_side; @@ -704,8 +707,8 @@ impl TopBottomPanel { is_resizing = ui.memory(|mem| mem.interaction.drag_id == Some(resize_id)); if is_resizing { let height = (pointer.y - side.side_y(panel_rect)).abs(); - let height = clamp_to_range(height, height_range.clone()) - .at_most(available_rect.height()); + let height = + clamp_to_range(height, height_range).at_most(available_rect.height()); side.set_rect_height(&mut panel_rect, height); } @@ -724,7 +727,7 @@ impl TopBottomPanel { let frame = frame.unwrap_or_else(|| Frame::side_top_panel(ui.style())); let inner_response = frame.show(&mut panel_ui, |ui| { ui.set_min_width(ui.max_rect().width()); // Make the frame fill full width - ui.set_min_height(*height_range.start()); + ui.set_min_height(height_range.min); add_contents(ui) }); @@ -1056,9 +1059,7 @@ impl CentralPanel { } } -fn clamp_to_range(x: f32, range: RangeInclusive) -> f32 { - x.clamp( - range.start().min(*range.end()), - range.start().max(*range.end()), - ) +fn clamp_to_range(x: f32, range: Rangef) -> f32 { + let range = range.as_positive(); + x.clamp(range.min, range.max) } diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 341e61f2f..b75a16ab2 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -640,8 +640,7 @@ impl Prepared { let min = content_ui.min_rect().min[d]; let clip_rect = content_ui.clip_rect(); let visible_range = min..=min + clip_rect.size()[d]; - let start = *scroll.start(); - let end = *scroll.end(); + let (start, end) = (scroll.min, scroll.max); let clip_start = clip_rect.min[d]; let clip_end = clip_rect.max[d]; let mut spacing = ui.spacing().item_spacing[d]; diff --git a/crates/egui/src/frame_state.rs b/crates/egui/src/frame_state.rs index 0d7106843..287b35c56 100644 --- a/crates/egui/src/frame_state.rs +++ b/crates/egui/src/frame_state.rs @@ -1,5 +1,3 @@ -use std::ops::RangeInclusive; - use crate::{id::IdSet, *}; #[derive(Clone, Copy, Debug)] @@ -46,7 +44,7 @@ pub(crate) struct FrameState { pub(crate) scroll_delta: Vec2, // TODO(emilk): move to `InputState` ? /// horizontal, vertical - pub(crate) scroll_target: [Option<(RangeInclusive, Option)>; 2], + pub(crate) scroll_target: [Option<(Rangef, Option)>; 2], #[cfg(feature = "accesskit")] pub(crate) accesskit_state: Option, diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index f7eef71a9..aab9049b6 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -335,7 +335,9 @@ pub use epaint::emath; #[cfg(feature = "color-hex")] pub use ecolor::hex_color; pub use ecolor::{Color32, Rgba}; -pub use emath::{lerp, pos2, remap, remap_clamp, vec2, Align, Align2, NumExt, Pos2, Rect, Vec2}; +pub use emath::{ + lerp, pos2, remap, remap_clamp, vec2, Align, Align2, NumExt, Pos2, Rangef, Rect, Vec2, +}; pub use epaint::{ mutex, text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak}, diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index 214bbe175..baf3b9212 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -1,8 +1,7 @@ -use std::ops::RangeInclusive; use std::sync::Arc; use crate::{ - emath::{Align2, Pos2, Rect, Vec2}, + emath::{Align2, Pos2, Rangef, Rect, Vec2}, layers::{LayerId, PaintList, ShapeIdx}, Color32, Context, FontId, }; @@ -263,12 +262,12 @@ impl Painter { } /// Paints a horizontal line. - pub fn hline(&self, x: RangeInclusive, y: f32, stroke: impl Into) { + pub fn hline(&self, x: impl Into, y: f32, stroke: impl Into) { self.add(Shape::hline(x, y, stroke)); } /// Paints a vertical line. - pub fn vline(&self, x: f32, y: RangeInclusive, stroke: impl Into) { + pub fn vline(&self, x: f32, y: impl Into, stroke: impl Into) { self.add(Shape::vline(x, y, stroke)); } diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 4e4b4559d..83713e487 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -517,15 +517,17 @@ impl Ui { } /// `ui.set_width_range(min..=max);` is equivalent to `ui.set_min_width(min); ui.set_max_width(max);`. - pub fn set_width_range(&mut self, width: std::ops::RangeInclusive) { - self.set_min_width(*width.start()); - self.set_max_width(*width.end()); + pub fn set_width_range(&mut self, width: impl Into) { + let width = width.into(); + self.set_min_width(width.min); + self.set_max_width(width.max); } /// `ui.set_height_range(min..=max);` is equivalent to `ui.set_min_height(min); ui.set_max_height(max);`. - pub fn set_height_range(&mut self, height: std::ops::RangeInclusive) { - self.set_min_height(*height.start()); - self.set_max_height(*height.end()); + pub fn set_height_range(&mut self, height: impl Into) { + let height = height.into(); + self.set_min_height(height.min); + self.set_max_height(height.max); } /// Set both the minimum and maximum width. @@ -978,7 +980,7 @@ impl Ui { /// ``` pub fn scroll_to_rect(&self, rect: Rect, align: Option) { for d in 0..2 { - let range = rect.min[d]..=rect.max[d]; + let range = Rangef::new(rect.min[d], rect.max[d]); self.ctx() .frame_state_mut(|state| state.scroll_target[d] = Some((range, align))); } @@ -1008,9 +1010,9 @@ impl Ui { pub fn scroll_to_cursor(&self, align: Option) { let target = self.next_widget_position(); for d in 0..2 { - let target = target[d]; + let target = Rangef::point(target[d]); self.ctx() - .frame_state_mut(|state| state.scroll_target[d] = Some((target..=target, align))); + .frame_state_mut(|state| state.scroll_target[d] = Some((target, align))); } } diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 9ebcaf493..f298a7831 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -524,12 +524,12 @@ impl<'a> Slider<'a> { } /// For instance, `position` is the mouse position and `position_range` is the physical location of the slider on the screen. - fn value_from_position(&self, position: f32, position_range: RangeInclusive) -> f64 { + fn value_from_position(&self, position: f32, position_range: Rangef) -> f64 { let normalized = remap_clamp(position, position_range, 0.0..=1.0) as f64; value_from_normalized(normalized, self.range(), &self.spec) } - fn position_from_value(&self, value: f64, position_range: RangeInclusive) -> f32 { + fn position_from_value(&self, value: f64, position_range: Rangef) -> f32 { let normalized = normalized_from_value(value, self.range(), &self.spec); lerp(position_range, normalized as f32) } @@ -555,11 +555,11 @@ impl<'a> Slider<'a> { let new_value = if self.smart_aim { let aim_radius = ui.input(|i| i.aim_radius()); emath::smart_aim::best_in_range_f64( - self.value_from_position(position - aim_radius, position_range.clone()), - self.value_from_position(position + aim_radius, position_range.clone()), + self.value_from_position(position - aim_radius, position_range), + self.value_from_position(position + aim_radius, position_range), ) } else { - self.value_from_position(position, position_range.clone()) + self.value_from_position(position, position_range) }; self.set_value(new_value); } @@ -594,18 +594,18 @@ impl<'a> Slider<'a> { if kb_step != 0.0 { let prev_value = self.get_value(); - let prev_position = self.position_from_value(prev_value, position_range.clone()); + let prev_position = self.position_from_value(prev_value, position_range); let new_position = prev_position + kb_step; let new_value = match self.step { Some(step) => prev_value + (kb_step as f64 * step), None if self.smart_aim => { let aim_radius = ui.input(|i| i.aim_radius()); emath::smart_aim::best_in_range_f64( - self.value_from_position(new_position - aim_radius, position_range.clone()), - self.value_from_position(new_position + aim_radius, position_range.clone()), + self.value_from_position(new_position - aim_radius, position_range), + self.value_from_position(new_position + aim_radius, position_range), ) } - _ => self.value_from_position(new_position, position_range.clone()), + _ => self.value_from_position(new_position, position_range), }; self.set_value(new_value); } @@ -686,15 +686,11 @@ impl<'a> Slider<'a> { } } - fn position_range(&self, rect: &Rect) -> RangeInclusive { + fn position_range(&self, rect: &Rect) -> Rangef { let handle_radius = self.handle_radius(rect); match self.orientation { - SliderOrientation::Horizontal => { - (rect.left() + handle_radius)..=(rect.right() - handle_radius) - } - SliderOrientation::Vertical => { - (rect.bottom() - handle_radius)..=(rect.top() + handle_radius) - } + SliderOrientation::Horizontal => rect.x_range().shrink(handle_radius), + SliderOrientation::Vertical => rect.y_range().shrink(handle_radius), } } @@ -726,7 +722,7 @@ impl<'a> Slider<'a> { } } - fn value_ui(&mut self, ui: &mut Ui, position_range: RangeInclusive) -> Response { + fn value_ui(&mut self, ui: &mut Ui, position_range: Rangef) -> Response { // If [`DragValue`] is controlled from the keyboard and `step` is defined, set speed to `step` let change = ui.input(|input| { input.num_presses(Key::ArrowUp) as i32 + input.num_presses(Key::ArrowRight) as i32 @@ -740,7 +736,7 @@ impl<'a> Slider<'a> { step } else { self.drag_value_speed - .unwrap_or_else(|| self.current_gradient(&position_range)) + .unwrap_or_else(|| self.current_gradient(position_range)) }; let mut value = self.get_value(); @@ -767,12 +763,11 @@ impl<'a> Slider<'a> { } /// delta(value) / delta(points) - fn current_gradient(&mut self, position_range: &RangeInclusive) -> f64 { + fn current_gradient(&mut self, position_range: Rangef) -> f64 { // TODO(emilk): handle clamping let value = self.get_value(); - let value_from_pos = - |position: f32| self.value_from_position(position, position_range.clone()); - let pos_from_value = |value: f64| self.position_from_value(value, position_range.clone()); + let value_from_pos = |position: f32| self.value_from_position(position, position_range); + let pos_from_value = |value: f64| self.position_from_value(value, position_range); let left_value = value_from_pos(pos_from_value(value) - 0.5); let right_value = value_from_pos(pos_from_value(value) + 0.5); right_value - left_value diff --git a/crates/egui_extras/src/sizing.rs b/crates/egui_extras/src/sizing.rs index 8a58302d5..c6ae9d6da 100644 --- a/crates/egui_extras/src/sizing.rs +++ b/crates/egui_extras/src/sizing.rs @@ -1,14 +1,16 @@ +use egui::Rangef; + /// Size hint for table column/strip cell. #[derive(Clone, Debug, Copy)] pub enum Size { /// Absolute size in points, with a given range of allowed sizes to resize within. - Absolute { initial: f32, range: (f32, f32) }, + Absolute { initial: f32, range: Rangef }, /// Relative size relative to all available space. - Relative { fraction: f32, range: (f32, f32) }, + Relative { fraction: f32, range: Rangef }, /// Multiple remainders each get the same space. - Remainder { range: (f32, f32) }, + Remainder { range: Rangef }, } impl Size { @@ -16,7 +18,7 @@ impl Size { pub fn exact(points: f32) -> Self { Self::Absolute { initial: points, - range: (points, points), + range: Rangef::new(points, points), } } @@ -24,7 +26,7 @@ impl Size { pub fn initial(points: f32) -> Self { Self::Absolute { initial: points, - range: (0.0, f32::INFINITY), + range: Rangef::new(0.0, f32::INFINITY), } } @@ -33,14 +35,14 @@ impl Size { egui::egui_assert!(0.0 <= fraction && fraction <= 1.0); Self::Relative { fraction, - range: (0.0, f32::INFINITY), + range: Rangef::new(0.0, f32::INFINITY), } } /// Multiple remainders each get the same space. pub fn remainder() -> Self { Self::Remainder { - range: (0.0, f32::INFINITY), + range: Rangef::new(0.0, f32::INFINITY), } } @@ -50,7 +52,7 @@ impl Size { Self::Absolute { range, .. } | Self::Relative { range, .. } | Self::Remainder { range, .. } => { - range.0 = minimum; + range.min = minimum; } } self @@ -62,14 +64,14 @@ impl Size { Self::Absolute { range, .. } | Self::Relative { range, .. } | Self::Remainder { range, .. } => { - range.1 = maximum; + range.max = maximum; } } self } /// Allowed range of movement (in points), if in a resizable [`Table`](crate::table::Table). - pub fn range(self) -> (f32, f32) { + pub fn range(self) -> Rangef { match self { Self::Absolute { range, .. } | Self::Relative { range, .. } @@ -99,12 +101,9 @@ impl Sizing { .iter() .map(|&size| match size { Size::Absolute { initial, .. } => initial, - Size::Relative { - fraction, - range: (min, max), - } => { + Size::Relative { fraction, range } => { assert!(0.0 <= fraction && fraction <= 1.0); - (length * fraction).clamp(min, max) + range.clamp(length * fraction) } Size::Remainder { .. } => { remainders += 1; @@ -120,9 +119,9 @@ impl Sizing { let mut remainder_length = length - sum_non_remainder; let avg_remainder_length = 0.0f32.max(remainder_length / remainders as f32).floor(); self.sizes.iter().for_each(|&size| { - if let Size::Remainder { range: (min, _max) } = size { - if avg_remainder_length < min { - remainder_length -= min; + if let Size::Remainder { range } = size { + if avg_remainder_length < range.min { + remainder_length -= range.min; remainders -= 1; } } @@ -138,11 +137,8 @@ impl Sizing { .iter() .map(|&size| match size { Size::Absolute { initial, .. } => initial, - Size::Relative { - fraction, - range: (min, max), - } => (length * fraction).clamp(min, max), - Size::Remainder { range: (min, max) } => avg_remainder_length.clamp(min, max), + Size::Relative { fraction, range } => range.clamp(length * fraction), + Size::Remainder { range } => range.clamp(avg_remainder_length), }) .collect() } diff --git a/crates/egui_extras/src/table.rs b/crates/egui_extras/src/table.rs index 2283ab4d7..9966a8b99 100644 --- a/crates/egui_extras/src/table.rs +++ b/crates/egui_extras/src/table.rs @@ -3,7 +3,7 @@ //! | fixed size | all available space/minimum | 30% of available width | fixed size | //! Takes all available height, so if you want something below the table, put it in a strip. -use egui::{Align, NumExt as _, Rect, Response, ScrollArea, Ui, Vec2}; +use egui::{Align, NumExt as _, Rangef, Rect, Response, ScrollArea, Ui, Vec2}; use crate::{ layout::{CellDirection, CellSize}, @@ -28,7 +28,7 @@ enum InitialColumnSize { #[derive(Clone, Copy, Debug, PartialEq)] pub struct Column { initial_width: InitialColumnSize, - width_range: (f32, f32), + width_range: Rangef, /// Clip contents if too narrow? clip: bool, @@ -78,7 +78,7 @@ impl Column { fn new(initial_width: InitialColumnSize) -> Self { Self { initial_width, - width_range: (0.0, f32::INFINITY), + width_range: Rangef::new(0.0, f32::INFINITY), resizable: None, clip: false, } @@ -110,7 +110,7 @@ impl Column { /// /// Default: 0.0 pub fn at_least(mut self, minimum: f32) -> Self { - self.width_range.0 = minimum; + self.width_range.min = minimum; self } @@ -118,13 +118,13 @@ impl Column { /// /// Default: [`f32::INFINITY`] pub fn at_most(mut self, maximum: f32) -> Self { - self.width_range.1 = maximum; + self.width_range.max = maximum; self } /// Allowed range of movement (in points), if in a resizable [`Table`](crate::table::Table). - pub fn range(mut self, range: std::ops::RangeInclusive) -> Self { - self.width_range = (*range.start(), *range.end()); + pub fn range(mut self, range: impl Into) -> Self { + self.width_range = range.into(); self } @@ -146,8 +146,8 @@ fn to_sizing(columns: &[Column]) -> crate::sizing::Sizing { InitialColumnSize::Automatic(suggested_width) => Size::initial(suggested_width), InitialColumnSize::Remainder => Size::remainder(), } - .at_least(column.width_range.0) - .at_most(column.width_range.1); + .at_least(column.width_range.min) + .at_most(column.width_range.max); sizing.add(size); } sizing @@ -598,13 +598,13 @@ impl<'a> Table<'a> { if scroll_to_row.is_some() && scroll_to_y_range.is_none() { // TableBody::row didn't find the right row, so scroll to the bottom: - scroll_to_y_range = Some((f32::INFINITY, f32::INFINITY)); + scroll_to_y_range = Some(Rangef::new(f32::INFINITY, f32::INFINITY)); } }); - if let Some((min_y, max_y)) = scroll_to_y_range { + if let Some(y_range) = scroll_to_y_range { let x = 0.0; // ignored, we only have vertical scrolling - let rect = egui::Rect::from_min_max(egui::pos2(x, min_y), egui::pos2(x, max_y)); + let rect = egui::Rect::from_x_y_ranges(x..=x, y_range); let align = scroll_to_row.and_then(|(_, a)| a); ui.scroll_to_rect(rect, align); } @@ -617,14 +617,14 @@ impl<'a> Table<'a> { for (i, column_width) in state.column_widths.iter_mut().enumerate() { let column = &columns[i]; let column_is_resizable = column.resizable.unwrap_or(resizable); - let (min_width, max_width) = column.width_range; + let width_range = column.width_range; if !column.clip { // Unless we clip we don't want to shrink below the // size that was actually used: *column_width = column_width.at_least(max_used_widths[i]); } - *column_width = column_width.clamp(min_width, max_width); + *column_width = width_range.clamp(*column_width); let is_last_column = i + 1 == columns.len(); @@ -633,7 +633,7 @@ impl<'a> Table<'a> { let eps = 0.1; // just to avoid some rounding errors. *column_width = available_width - eps; *column_width = column_width.at_least(max_used_widths[i]); - *column_width = column_width.clamp(min_width, max_width); + *column_width = width_range.clamp(*column_width); break; } @@ -641,7 +641,7 @@ impl<'a> Table<'a> { if column.is_auto() && (first_frame_auto_size_columns || !column_is_resizable) { *column_width = max_used_widths[i]; - *column_width = column_width.clamp(min_width, max_width); + *column_width = width_range.clamp(*column_width); } else if column_is_resizable { let column_resize_id = ui.id().with("resize_column").with(i); @@ -656,7 +656,7 @@ impl<'a> Table<'a> { if resize_response.double_clicked() { // Resize to the minimum of what is needed. - *column_width = max_used_widths[i].clamp(min_width, max_width); + *column_width = width_range.clamp(max_used_widths[i]); } else if resize_response.dragged() { if let Some(pointer) = ui.ctx().pointer_latest_pos() { let mut new_width = *column_width + pointer.x - x; @@ -671,7 +671,7 @@ impl<'a> Table<'a> { new_width = new_width.at_least(max_used_widths[i] - max_shrinkage_per_frame); } - new_width = new_width.clamp(min_width, max_width); + new_width = width_range.clamp(new_width); let x = x - *column_width + new_width; (p0.x, p1.x) = (x, x); @@ -731,7 +731,7 @@ pub struct TableBody<'a> { /// If we find the correct row to scroll to, /// this is set to the y-range of the row. - scroll_to_y_range: &'a mut Option<(f32, f32)>, + scroll_to_y_range: &'a mut Option, } impl<'a> TableBody<'a> { @@ -779,7 +779,7 @@ impl<'a> TableBody<'a> { let bottom_y = self.layout.cursor.y; if Some(self.row_nr) == self.scroll_to_row { - *self.scroll_to_y_range = Some((top_y, bottom_y)); + *self.scroll_to_y_range = Some(Rangef::new(top_y, bottom_y)); } self.row_nr += 1; @@ -819,7 +819,7 @@ impl<'a> TableBody<'a> { if let Some(scroll_to_row) = self.scroll_to_row { let scroll_to_row = scroll_to_row.at_most(total_rows.saturating_sub(1)) as f32; - *self.scroll_to_y_range = Some(( + *self.scroll_to_y_range = Some(Rangef::new( self.layout.cursor.y + scroll_to_row * row_height_with_spacing, self.layout.cursor.y + (scroll_to_row + 1.0) * row_height_with_spacing, )); @@ -909,7 +909,7 @@ impl<'a> TableBody<'a> { cursor_y += (row_height + spacing.y) as f64; if Some(row_index) == self.scroll_to_row { - *self.scroll_to_y_range = Some(( + *self.scroll_to_y_range = Some(Rangef::new( (scroll_to_y_range_offset + old_cursor_y) as f32, (scroll_to_y_range_offset + cursor_y) as f32, )); @@ -953,7 +953,7 @@ impl<'a> TableBody<'a> { cursor_y += (row_height + spacing.y) as f64; if Some(row_index) == self.scroll_to_row { - *self.scroll_to_y_range = Some(( + *self.scroll_to_y_range = Some(Rangef::new( (scroll_to_y_range_offset + top_y) as f32, (scroll_to_y_range_offset + cursor_y) as f32, )); @@ -972,7 +972,7 @@ impl<'a> TableBody<'a> { let top_y = cursor_y; cursor_y += (row_height + spacing.y) as f64; if Some(row_index) == self.scroll_to_row { - *self.scroll_to_y_range = Some(( + *self.scroll_to_y_range = Some(Rangef::new( (scroll_to_y_range_offset + top_y) as f32, (scroll_to_y_range_offset + cursor_y) as f32, )); @@ -981,10 +981,8 @@ impl<'a> TableBody<'a> { if self.scroll_to_row.is_some() && self.scroll_to_y_range.is_none() { // Catch desire to scroll past the end: - *self.scroll_to_y_range = Some(( - (scroll_to_y_range_offset + cursor_y) as f32, - (scroll_to_y_range_offset + cursor_y) as f32, - )); + *self.scroll_to_y_range = + Some(Rangef::point((scroll_to_y_range_offset + cursor_y) as f32)); } if height_below_visible > 0.0 { diff --git a/crates/emath/src/align.rs b/crates/emath/src/align.rs index 9d7ccf81e..ef07cc1d3 100644 --- a/crates/emath/src/align.rs +++ b/crates/emath/src/align.rs @@ -110,29 +110,25 @@ impl Align { /// assert_eq!(Max .align_size_within_range(INFINITY, NEG_INFINITY..=20.0), NEG_INFINITY..=20.0); /// ``` #[inline] - pub fn align_size_within_range( - self, - size: f32, - range: RangeInclusive, - ) -> RangeInclusive { - let min = *range.start(); - let max = *range.end(); + pub fn align_size_within_range(self, size: f32, range: impl Into) -> Rangef { + let range = range.into(); + let Rangef { min, max } = range; if max - min == f32::INFINITY && size == f32::INFINITY { return range; } match self { - Self::Min => min..=min + size, + Self::Min => Rangef::new(min, min + size), Self::Center => { if size == f32::INFINITY { - f32::NEG_INFINITY..=f32::INFINITY + Rangef::new(f32::NEG_INFINITY, f32::INFINITY) } else { let left = (min + max) / 2.0 - size / 2.0; - left..=left + size + Rangef::new(left, left + size) } } - Self::Max => max - size..=max, + Self::Max => Rangef::new(max - size, max), } } } diff --git a/crates/emath/src/lib.rs b/crates/emath/src/lib.rs index 89b2db209..25b3b9eac 100644 --- a/crates/emath/src/lib.rs +++ b/crates/emath/src/lib.rs @@ -99,11 +99,12 @@ impl Real for f64 {} /// assert_eq!(lerp(1.0..=5.0, 2.0), 9.0); /// ``` #[inline(always)] -pub fn lerp(range: RangeInclusive, t: T) -> R +pub fn lerp(range: impl Into>, t: T) -> R where T: Real + Mul, R: Copy + Add, { + let range = range.into(); (T::one() - t) * *range.start() + t * *range.end() } @@ -138,20 +139,28 @@ where /// Linearly remap a value from one range to another, /// so that when `x == from.start()` returns `to.start()` /// and when `x == from.end()` returns `to.end()`. -pub fn remap(x: T, from: RangeInclusive, to: RangeInclusive) -> T +pub fn remap(x: T, from: impl Into>, to: impl Into>) -> T where T: Real, { + let from = from.into(); + let to = to.into(); crate::emath_assert!(from.start() != from.end()); let t = (x - *from.start()) / (*from.end() - *from.start()); lerp(to, t) } /// Like [`remap`], but also clamps the value so that the returned value is always in the `to` range. -pub fn remap_clamp(x: T, from: RangeInclusive, to: RangeInclusive) -> T +pub fn remap_clamp( + x: T, + from: impl Into>, + to: impl Into>, +) -> T where T: Real, { + let from = from.into(); + let to = to.into(); if from.end() < from.start() { return remap_clamp(x, *from.end()..=*from.start(), *to.end()..=*to.start()); } diff --git a/crates/emath/src/range.rs b/crates/emath/src/range.rs index ae3e3f0e5..11459763d 100644 --- a/crates/emath/src/range.rs +++ b/crates/emath/src/range.rs @@ -36,14 +36,60 @@ impl Rangef { } #[inline] - pub fn span(&self) -> f32 { + pub fn point(min_and_max: f32) -> Self { + Self { + min: min_and_max, + max: min_and_max, + } + } + + /// The length of the range, i.e. `max - min`. + #[inline] + pub fn span(self) -> f32 { self.max - self.min } #[inline] - pub fn contains(&self, x: f32) -> bool { + #[must_use] + pub fn contains(self, x: f32) -> bool { self.min <= x && x <= self.max } + + /// Equivalent to `x.clamp(min, max)` + #[inline] + #[must_use] + pub fn clamp(self, x: f32) -> f32 { + x.clamp(self.min, self.max) + } + + /// Flip `min` and `max` if needed, so that `min <= max` after. + #[inline] + pub fn as_positive(self) -> Self { + Rangef { + min: self.min.min(self.max), + max: self.min.max(self.max), + } + } + + /// Shrink by this much on each side, keeping the center + #[inline] + #[must_use] + pub fn shrink(self, amnt: f32) -> Self { + Self { + min: self.min + amnt, + max: self.max - amnt, + } + } + + /// Expand by this much on each side, keeping the center + #[inline] + #[must_use] + pub fn expand(self, amnt: f32) -> Self { + Self { + min: self.min - amnt, + max: self.max + amnt, + } + } } impl From for RangeInclusive { @@ -108,3 +154,17 @@ impl From> for Rangef { Self::new(f32::NEG_INFINITY, range.end) } } + +impl PartialEq> for Rangef { + #[inline] + fn eq(&self, other: &RangeInclusive) -> bool { + self.min == *other.start() && self.max == *other.end() + } +} + +impl PartialEq for RangeInclusive { + #[inline] + fn eq(&self, other: &Rangef) -> bool { + *self.start() == other.min && *self.end() == other.max + } +} diff --git a/crates/emath/src/rect.rs b/crates/emath/src/rect.rs index de115b985..d6d148d27 100644 --- a/crates/emath/src/rect.rs +++ b/crates/emath/src/rect.rs @@ -1,5 +1,4 @@ use std::f32::INFINITY; -use std::ops::RangeInclusive; use crate::*; @@ -82,15 +81,12 @@ impl Rect { } #[inline(always)] - pub fn from_x_y_ranges( - x_range: impl Into>, - y_range: impl Into>, - ) -> Self { + pub fn from_x_y_ranges(x_range: impl Into, y_range: impl Into) -> Self { let x_range = x_range.into(); let y_range = y_range.into(); Rect { - min: pos2(*x_range.start(), *y_range.start()), - max: pos2(*x_range.end(), *y_range.end()), + min: pos2(x_range.min, y_range.min), + max: pos2(x_range.max, y_range.max), } } @@ -390,18 +386,18 @@ impl Rect { } #[inline(always)] - pub fn x_range(&self) -> RangeInclusive { - self.min.x..=self.max.x + pub fn x_range(&self) -> Rangef { + Rangef::new(self.min.x, self.max.x) } #[inline(always)] - pub fn y_range(&self) -> RangeInclusive { - self.min.y..=self.max.y + pub fn y_range(&self) -> Rangef { + Rangef::new(self.min.y, self.max.y) } #[inline(always)] - pub fn bottom_up_range(&self) -> RangeInclusive { - self.max.y..=self.min.y + pub fn bottom_up_range(&self) -> Rangef { + Rangef::new(self.max.y, self.min.y) } /// `width < 0 || height < 0` diff --git a/crates/epaint/src/shape.rs b/crates/epaint/src/shape.rs index 046215661..401f51d8a 100644 --- a/crates/epaint/src/shape.rs +++ b/crates/epaint/src/shape.rs @@ -1,6 +1,5 @@ //! The different shapes that can be painted. -use std::ops::RangeInclusive; use std::{any::Any, sync::Arc}; use crate::{ @@ -94,17 +93,19 @@ impl Shape { } /// A horizontal line. - pub fn hline(x: RangeInclusive, y: f32, stroke: impl Into) -> Self { + pub fn hline(x: impl Into, y: f32, stroke: impl Into) -> Self { + let x = x.into(); Shape::LineSegment { - points: [pos2(*x.start(), y), pos2(*x.end(), y)], + points: [pos2(x.min, y), pos2(x.max, y)], stroke: stroke.into(), } } /// A vertical line. - pub fn vline(x: f32, y: RangeInclusive, stroke: impl Into) -> Self { + pub fn vline(x: f32, y: impl Into, stroke: impl Into) -> Self { + let y = y.into(); Shape::LineSegment { - points: [pos2(x, *y.start()), pos2(x, *y.end())], + points: [pos2(x, y.min), pos2(x, y.max)], stroke: stroke.into(), } } From b15e17587a5ceec9bd0c024b53d506d4fd87d695 Mon Sep 17 00:00:00 2001 From: Valentin Date: Thu, 10 Aug 2023 13:11:56 +0200 Subject: [PATCH 33/43] Document when Galleys get invalidated (#3024) --- crates/epaint/src/text/text_layout_types.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index d6d81d88b..28301c85a 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -310,7 +310,13 @@ impl Default for TextWrapping { /// /// You can create a [`Galley`] using [`crate::Fonts::layout_job`]; /// -/// This needs to be recreated if `pixels_per_point` (dpi scale) changes. +/// Needs to be recreated if the underlying font atlas texture changes, which +/// happens under the following conditions: +/// - `pixels_per_point` or `max_texture_size` change. These parameters are set +/// in [`crate::text::Fonts::begin_frame`]. When using `egui` they are set +/// from `egui::InputState` and can change at any time. +/// - The atlas has become full. This can happen any time a new glyph is added +/// to the atlas, which in turn can happen any time new text is laid out. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Galley { From 66cbb61ad5a4434d6c723ff81f416205d39c6299 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 10 Aug 2023 13:14:19 +0200 Subject: [PATCH 34/43] Add `PlotUi::response()` to replace `plot_clicked()` etc (#3223) Closes https://github.com/emilk/egui/pull/2571 --- crates/egui/src/widgets/plot/mod.rs | 8 ++++++++ crates/egui_demo_lib/src/demo/plot_demo.rs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 8f04be4fa..9fa09b7e1 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1081,17 +1081,25 @@ impl PlotUi { .push(BoundsModification::Translate(delta_pos)); } + /// Can be used to check if the plot was hovered or clicked. + pub fn response(&self) -> &Response { + &self.response + } + /// Returns `true` if the plot area is currently hovered. + #[deprecated = "Use plot_ui.response().hovered()"] pub fn plot_hovered(&self) -> bool { self.response.hovered() } /// Returns `true` if the plot was clicked by the primary button. + #[deprecated = "Use plot_ui.response().clicked()"] pub fn plot_clicked(&self) -> bool { self.response.clicked() } /// Returns `true` if the plot was clicked by the secondary button. + #[deprecated = "Use plot_ui.response().secondary_clicked()"] pub fn plot_secondary_clicked(&self) -> bool { self.response.secondary_clicked() } diff --git a/crates/egui_demo_lib/src/demo/plot_demo.rs b/crates/egui_demo_lib/src/demo/plot_demo.rs index 8c5bcfd3c..2f6180eae 100644 --- a/crates/egui_demo_lib/src/demo/plot_demo.rs +++ b/crates/egui_demo_lib/src/demo/plot_demo.rs @@ -761,7 +761,7 @@ impl InteractionDemo { plot_ui.pointer_coordinate(), plot_ui.pointer_coordinate_drag_delta(), plot_ui.plot_bounds(), - plot_ui.plot_hovered(), + plot_ui.response().hovered(), ) }); From 83c18498e9853fdd953a43e6bd133e3e4ba2c367 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 10 Aug 2023 14:50:11 +0200 Subject: [PATCH 35/43] Refactor: turn `ClippedShape` from struct-enum to a normal struct (#3225) --- crates/egui/src/layers.rs | 8 ++++---- crates/epaint/benches/benchmark.rs | 2 +- crates/epaint/src/lib.rs | 9 +++++---- crates/epaint/src/stats.rs | 2 +- crates/epaint/src/tessellator.rs | 18 +++++++++++++++--- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/crates/egui/src/layers.rs b/crates/egui/src/layers.rs index 9e951f0dc..83e7fdeb6 100644 --- a/crates/egui/src/layers.rs +++ b/crates/egui/src/layers.rs @@ -127,7 +127,7 @@ impl PaintList { #[inline(always)] pub fn add(&mut self, clip_rect: Rect, shape: Shape) -> ShapeIdx { let idx = ShapeIdx(self.0.len()); - self.0.push(ClippedShape(clip_rect, shape)); + self.0.push(ClippedShape { clip_rect, shape }); idx } @@ -135,7 +135,7 @@ impl PaintList { self.0.extend( shapes .into_iter() - .map(|shape| ClippedShape(clip_rect, shape)), + .map(|shape| ClippedShape { clip_rect, shape }), ); } @@ -148,12 +148,12 @@ impl PaintList { /// and then later setting it using `paint_list.set(idx, cr, frame);`. #[inline(always)] pub fn set(&mut self, idx: ShapeIdx, clip_rect: Rect, shape: Shape) { - self.0[idx.0] = ClippedShape(clip_rect, shape); + self.0[idx.0] = ClippedShape { clip_rect, shape }; } /// Translate each [`Shape`] and clip rectangle by this much, in-place pub fn translate(&mut self, delta: Vec2) { - for ClippedShape(clip_rect, shape) in &mut self.0 { + for ClippedShape { clip_rect, shape } in &mut self.0 { *clip_rect = clip_rect.translate(delta); shape.translate(delta); } diff --git a/crates/epaint/benches/benchmark.rs b/crates/epaint/benches/benchmark.rs index 126ec2bf2..7f7c9f1b1 100644 --- a/crates/epaint/benches/benchmark.rs +++ b/crates/epaint/benches/benchmark.rs @@ -47,7 +47,7 @@ fn tessellate_circles(c: &mut Criterion) { for _ in 0..10_000 { let clip_rect = Rect::from_min_size(Pos2::ZERO, Vec2::splat(1024.0)); let shape = Shape::circle_filled(Pos2::new(10.0, 10.0), r, Color32::WHITE); - clipped_shapes.push(ClippedShape(clip_rect, shape)); + clipped_shapes.push(ClippedShape { clip_rect, shape }); } } assert_eq!(clipped_shapes.len(), 100_000); diff --git a/crates/epaint/src/lib.rs b/crates/epaint/src/lib.rs index 82fc7e0f4..1662c94a1 100644 --- a/crates/epaint/src/lib.rs +++ b/crates/epaint/src/lib.rs @@ -90,13 +90,14 @@ impl Default for TextureId { /// /// Everything is using logical points. #[derive(Clone, Debug, PartialEq)] -pub struct ClippedShape( +pub struct ClippedShape { /// Clip / scissor rectangle. /// Only show the part of the [`Shape`] that falls within this. - pub emath::Rect, + pub clip_rect: emath::Rect, + /// The shape - pub Shape, -); + pub shape: Shape, +} /// A [`Mesh`] or [`PaintCallback`] within a clip rectangle. /// diff --git a/crates/epaint/src/stats.rs b/crates/epaint/src/stats.rs index 5abbe456f..24293aa7b 100644 --- a/crates/epaint/src/stats.rs +++ b/crates/epaint/src/stats.rs @@ -183,7 +183,7 @@ impl PaintStats { stats.shape_vec.element_size = ElementSize::Heterogenous; // nicer display later stats.shapes = AllocInfo::from_slice(shapes); - for ClippedShape(_, shape) in shapes { + for ClippedShape { shape, .. } in shapes { stats.add(shape); } stats diff --git a/crates/epaint/src/tessellator.rs b/crates/epaint/src/tessellator.rs index 75b5dc963..6671859b1 100644 --- a/crates/epaint/src/tessellator.rs +++ b/crates/epaint/src/tessellator.rs @@ -1036,7 +1036,10 @@ impl Tessellator { clipped_shape: ClippedShape, out_primitives: &mut Vec, ) { - let ClippedShape(new_clip_rect, new_shape) = clipped_shape; + let ClippedShape { + clip_rect: new_clip_rect, + shape: new_shape, + } = clipped_shape; if !new_clip_rect.is_positive() { return; // skip empty clip rectangles @@ -1044,7 +1047,13 @@ impl Tessellator { if let Shape::Vec(shapes) = new_shape { for shape in shapes { - self.tessellate_clipped_shape(ClippedShape(new_clip_rect, shape), out_primitives); + self.tessellate_clipped_shape( + ClippedShape { + clip_rect: new_clip_rect, + shape, + }, + out_primitives, + ); } return; } @@ -1641,7 +1650,10 @@ fn test_tessellator() { shapes.push(Shape::mesh(mesh)); let shape = Shape::Vec(shapes); - let clipped_shapes = vec![ClippedShape(rect, shape)]; + let clipped_shapes = vec![ClippedShape { + clip_rect: rect, + shape, + }]; let font_tex_size = [1024, 1024]; // unused let prepared_discs = vec![]; // unused From d568d9f5d0c36728afad1aaf365e91a9d3e0b899 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 10 Aug 2023 15:26:54 +0200 Subject: [PATCH 36/43] Lint vertical spacing in the code (#3224) * Lint vertical spacing in the code * Add some vertical spacing for readability --- .github/workflows/rust.yml | 7 +- CONTRIBUTING.md | 2 +- crates/eframe/src/lib.rs | 1 + crates/eframe/src/native/epi_integration.rs | 2 + crates/eframe/src/native/run.rs | 1 + crates/egui/src/containers/scroll_area.rs | 6 + crates/egui/src/data/input.rs | 10 ++ crates/egui/src/grid.rs | 1 + crates/egui/src/memory.rs | 2 + crates/egui/src/widgets/button.rs | 1 + crates/egui/src/widgets/drag_value.rs | 1 + crates/egui/src/widgets/plot/items/mod.rs | 11 ++ crates/egui/src/widgets/plot/mod.rs | 2 + crates/egui/src/widgets/slider.rs | 2 + crates/egui_extras/src/image.rs | 4 + crates/egui_extras/src/layout.rs | 2 + crates/egui_extras/src/table.rs | 6 + crates/epaint/src/tessellator.rs | 20 ++- crates/epaint/src/text/font.rs | 6 + crates/epaint/src/text/text_layout_types.rs | 8 ++ crates/epaint/src/textures.rs | 2 + scripts/lint.py | 132 ++++++++++++++++++++ 22 files changed, 215 insertions(+), 14 deletions(-) create mode 100755 scripts/lint.py diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 55865370a..6d4e8e5dd 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,6 +1,6 @@ on: [push, pull_request] -name: CI +name: Rust env: # web_sys_unstable_apis is required to enable the web_sys clipboard API which eframe web uses, @@ -37,6 +37,9 @@ jobs: - name: Rustfmt run: cargo fmt --all -- --check + - name: Lint vertical spacing + run: ./scripts/lint.py + - name: Install cargo-cranky uses: baptiste0928/cargo-install@v1 with: @@ -145,7 +148,7 @@ jobs: rust-version: "1.65.0" log-level: error command: check - arguments: ${{ matrix.flags }} --target ${{ matrix.target }} + arguments: --target ${{ matrix.target }} # --------------------------------------------------------------------------- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 28ff70d42..8d3897457 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,7 +60,7 @@ Read the section on integrations at ## Code Conventions Conventions unless otherwise specified: -* angles are in radians +* angles are in radians and clock-wise * `Vec2::X` is right and `Vec2::Y` is down. * `Pos2::ZERO` is left top. diff --git a/crates/eframe/src/lib.rs b/crates/eframe/src/lib.rs index 8164e7e65..8093339e8 100644 --- a/crates/eframe/src/lib.rs +++ b/crates/eframe/src/lib.rs @@ -272,6 +272,7 @@ pub fn run_simple_native( struct SimpleApp { update_fun: U, } + impl App for SimpleApp { fn update(&mut self, ctx: &egui::Context, frame: &mut Frame) { (self.update_fun)(ctx, frame); diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index faed7360c..a0bec23bd 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -335,8 +335,10 @@ pub struct EpiIntegration { pub egui_ctx: egui::Context, pending_full_output: egui::FullOutput, egui_winit: egui_winit::State, + /// When set, it is time to close the native window. close: bool, + can_drag_window: bool, window_state: WindowState, follow_system_theme: bool, diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 3b4cc5c46..3672c9bf1 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -22,6 +22,7 @@ use super::epi_integration::{self, EpiIntegration}; pub enum UserEvent { RequestRepaint { when: Instant, + /// What the frame number was when the repaint was _requested_. frame_nr: u64, }, diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index b75a16ab2..8bd8142cf 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -334,16 +334,22 @@ struct Prepared { state: State, has_bar: [bool; 2], auto_shrink: [bool; 2], + /// How much horizontal and vertical space are used up by the /// width of the vertical bar, and the height of the horizontal bar? current_bar_use: Vec2, + scroll_bar_visibility: ScrollBarVisibility, + /// Where on the screen the content is (excludes scroll bars). inner_rect: Rect, + content_ui: Ui, + /// Relative coordinates: the offset and size of the view of the inner UI. /// `viewport.min == ZERO` means we scrolled to the top. viewport: Rect, + scrolling_enabled: bool, stick_to_end: [bool; 2], } diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 29ff3f5dd..4bb9fdc06 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -693,27 +693,37 @@ pub enum Key { /// The virtual keycode for the Minus key. Minus, + /// The virtual keycode for the Plus/Equals key. PlusEquals, /// Either from the main row or from the numpad. Num0, + /// Either from the main row or from the numpad. Num1, + /// Either from the main row or from the numpad. Num2, + /// Either from the main row or from the numpad. Num3, + /// Either from the main row or from the numpad. Num4, + /// Either from the main row or from the numpad. Num5, + /// Either from the main row or from the numpad. Num6, + /// Either from the main row or from the numpad. Num7, + /// Either from the main row or from the numpad. Num8, + /// Either from the main row or from the numpad. Num9, diff --git a/crates/egui/src/grid.rs b/crates/egui/src/grid.rs index 314266a75..eb33e00ed 100644 --- a/crates/egui/src/grid.rs +++ b/crates/egui/src/grid.rs @@ -60,6 +60,7 @@ pub(crate) struct GridLayout { /// State previous frame (if any). /// This can be used to predict future sizes of cells. prev_state: State, + /// State accumulated during the current frame. curr_state: State, initial_available: Rect, diff --git a/crates/egui/src/memory.rs b/crates/egui/src/memory.rs index db76f7e7c..d89fd344a 100644 --- a/crates/egui/src/memory.rs +++ b/crates/egui/src/memory.rs @@ -546,8 +546,10 @@ impl Memory { #[cfg_attr(feature = "serde", serde(default))] pub struct Areas { areas: IdMap, + /// Back-to-front. Top is last. order: Vec, + visible_last_frame: ahash::HashSet, visible_current_frame: ahash::HashSet, diff --git a/crates/egui/src/widgets/button.rs b/crates/egui/src/widgets/button.rs index a7fa67818..ca211987a 100644 --- a/crates/egui/src/widgets/button.rs +++ b/crates/egui/src/widgets/button.rs @@ -23,6 +23,7 @@ pub struct Button { text: WidgetText, shortcut_text: WidgetText, wrap: Option, + /// None means default for interact fill: Option, stroke: Option, diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 1a965d4e1..b09033c19 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -11,6 +11,7 @@ use crate::*; pub(crate) struct MonoState { last_dragged_id: Option, last_dragged_value: Option, + /// For temporary edit of a [`DragValue`] value. /// Couples with the current focus id. edit_string: Option, diff --git a/crates/egui/src/widgets/plot/items/mod.rs b/crates/egui/src/widgets/plot/items/mod.rs index 3f21b0e83..f18f34aff 100644 --- a/crates/egui/src/widgets/plot/items/mod.rs +++ b/crates/egui/src/widgets/plot/items/mod.rs @@ -760,15 +760,22 @@ impl PlotItem for Text { /// A set of points. pub struct Points { pub(super) series: PlotPoints, + pub(super) shape: MarkerShape, + /// Color of the marker. `Color32::TRANSPARENT` means that it will be picked automatically. pub(super) color: Color32, + /// Whether to fill the marker. Does not apply to all types. pub(super) filled: bool, + /// The maximum extent of the marker from its center. pub(super) radius: f32, + pub(super) name: String, + pub(super) highlight: bool, + pub(super) stems: Option, } @@ -1290,8 +1297,10 @@ pub struct BarChart { pub(super) bars: Vec, pub(super) default_color: Color32, pub(super) name: String, + /// A custom element formatter pub(super) element_formatter: Option String>>, + highlight: bool, } @@ -1460,8 +1469,10 @@ pub struct BoxPlot { pub(super) boxes: Vec, pub(super) default_color: Color32, pub(super) name: String, + /// A custom element formatter pub(super) element_formatter: Option String>>, + highlight: bool, } diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 9fa09b7e1..9eca796dc 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -101,9 +101,11 @@ struct PlotMemory { /// Indicates if the user has modified the bounds, for example by moving or zooming, /// or if the bounds should be calculated based by included point or auto bounds. bounds_modified: AxisBools, + hovered_entry: Option, hidden_items: ahash::HashSet, last_plot_transform: PlotTransform, + /// Allows to remember the first click position when performing a boxed zoom last_click_pos_for_zoom: Option, } diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index f298a7831..f793d86e7 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -77,8 +77,10 @@ pub struct Slider<'a> { prefix: String, suffix: String, text: WidgetText, + /// Sets the minimal step of the widget value step: Option, + drag_value_speed: Option, min_decimals: usize, max_decimals: Option, diff --git a/crates/egui_extras/src/image.rs b/crates/egui_extras/src/image.rs index 3526b6de2..ba8acaf41 100644 --- a/crates/egui_extras/src/image.rs +++ b/crates/egui_extras/src/image.rs @@ -10,11 +10,15 @@ pub use usvg::FitTo; /// Use the `svg` and `image` features to enable more constructors. pub struct RetainedImage { debug_name: String, + size: [usize; 2], + /// Cleared once [`Self::texture`] has been loaded. image: Mutex, + /// Lazily loaded when we have an egui context. texture: Mutex>, + options: TextureOptions, } diff --git a/crates/egui_extras/src/layout.rs b/crates/egui_extras/src/layout.rs index 932594bf5..fbd15e7ad 100644 --- a/crates/egui_extras/src/layout.rs +++ b/crates/egui_extras/src/layout.rs @@ -32,9 +32,11 @@ pub struct StripLayout<'l> { direction: CellDirection, pub(crate) rect: Rect, pub(crate) cursor: Pos2, + /// Keeps track of the max used position, /// so we know how much space we used. max: Pos2, + cell_layout: egui::Layout, } diff --git a/crates/egui_extras/src/table.rs b/crates/egui_extras/src/table.rs index 9966a8b99..de0e98704 100644 --- a/crates/egui_extras/src/table.rs +++ b/crates/egui_extras/src/table.rs @@ -28,7 +28,9 @@ enum InitialColumnSize { #[derive(Clone, Copy, Debug, PartialEq)] pub struct Column { initial_width: InitialColumnSize, + width_range: Rangef, + /// Clip contents if too narrow? clip: bool, @@ -511,8 +513,10 @@ pub struct Table<'a> { columns: Vec, available_width: f32, state: TableState, + /// Accumulated maximum used widths for each column. max_used_widths: Vec, + first_frame_auto_size_columns: bool, resizable: bool, striped: bool, @@ -1011,8 +1015,10 @@ pub struct TableRow<'a, 'b> { layout: &'b mut StripLayout<'a>, columns: &'b [Column], widths: &'b [f32], + /// grows during building with the maximum widths max_used_widths: &'b mut [f32], + col_index: usize, striped: bool, height: f32, diff --git a/crates/epaint/src/tessellator.rs b/crates/epaint/src/tessellator.rs index 6671859b1..facb2612d 100644 --- a/crates/epaint/src/tessellator.rs +++ b/crates/epaint/src/tessellator.rs @@ -13,17 +13,15 @@ use emath::*; #[allow(clippy::approx_constant)] mod precomputed_vertices { - /* - fn main() { - let n = 64; - println!("pub const CIRCLE_{}: [Vec2; {}] = [", n, n+1); - for i in 0..=n { - let a = std::f64::consts::TAU * i as f64 / n as f64; - println!(" vec2({:.06}, {:.06}),", a.cos(), a.sin()); - } - println!("];") - } - */ + // fn main() { + // let n = 64; + // println!("pub const CIRCLE_{}: [Vec2; {}] = [", n, n+1); + // for i in 0..=n { + // let a = std::f64::consts::TAU * i as f64 / n as f64; + // println!(" vec2({:.06}, {:.06}),", a.cos(), a.sin()); + // } + // println!("];") + // } use emath::{vec2, Vec2}; diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs index 939cdf9ee..4cf26014f 100644 --- a/crates/epaint/src/text/font.rs +++ b/crates/epaint/src/text/font.rs @@ -78,11 +78,15 @@ impl Default for GlyphInfo { pub struct FontImpl { name: String, ab_glyph_font: ab_glyph::FontArc, + /// Maximum character height scale_in_pixels: u32, + height_in_points: f32, + // move each character by this much (hack) y_offset: f32, + ascent: f32, pixels_per_point: f32, glyph_info_cache: RwLock>, // TODO(emilk): standard Mutex @@ -320,8 +324,10 @@ type FontIndex = usize; /// Wrapper over multiple [`FontImpl`] (e.g. a primary + fallbacks for emojis) pub struct Font { fonts: Vec>, + /// Lazily calculated. characters: Option>, + replacement_glyph: (FontIndex, GlyphInfo), pixels_per_point: f32, row_height: f32, diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index 28301c85a..8ec829b8a 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -193,8 +193,10 @@ impl std::hash::Hash for LayoutJob { pub struct LayoutSection { /// Can be used for first row indentation. pub leading_space: f32, + /// Range into the galley text pub byte_range: Range, + pub format: TextFormat, } @@ -218,12 +220,18 @@ impl std::hash::Hash for LayoutSection { #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct TextFormat { pub font_id: FontId, + /// Text color pub color: Color32, + pub background: Color32, + pub italics: bool, + pub underline: Stroke, + pub strikethrough: Stroke, + /// If you use a small font and [`Align::TOP`] you /// can get the effect of raised text. pub valign: Align, diff --git a/crates/epaint/src/textures.rs b/crates/epaint/src/textures.rs index e6b423746..abe8d0b91 100644 --- a/crates/epaint/src/textures.rs +++ b/crates/epaint/src/textures.rs @@ -9,8 +9,10 @@ use crate::{ImageData, ImageDelta, TextureId}; pub struct TextureManager { /// We allocate texture id:s linearly. next_id: u64, + /// Information about currently allocated textures. metas: ahash::HashMap, + delta: TexturesDelta, } diff --git a/scripts/lint.py b/scripts/lint.py new file mode 100755 index 000000000..93851ffa1 --- /dev/null +++ b/scripts/lint.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +""" +Runs custom linting on Rust code. +""" + +import argparse +import os +import re +import sys + + +def lint_file_path(filepath, args) -> int: + with open(filepath) as f: + lines_in = f.readlines() + + errors, lines_out = lint_lines(filepath, lines_in) + + for error in errors: + print(error) + + if args.fix and lines_in != lines_out: + with open(filepath, 'w') as f: + f.writelines(lines_out) + print(f'{filepath} fixed.') + + return len(errors) + + + +def lint_lines(filepath, lines_in): + last_line_was_empty = True + + errors = [] + lines_out = [] + + for line_nr, line in enumerate(lines_in): + line_nr = line_nr+1 + + # TODO: only # and /// on lines before a keyword + + pattern = r'^\s*((///)|((pub(\(\w*\))? )?((impl|fn|struct|enum|union|trait)\b))).*$' + if re.match(pattern, line): + if not last_line_was_empty: + errors.append( + f'{filepath}:{line_nr}: for readability, add newline before `{line.strip()}`') + lines_out.append("\n") + lines_out.append(line) + + stripped = line.strip() + last_line_was_empty = stripped == '' or \ + stripped.startswith('#') or \ + stripped.startswith('//') or \ + stripped.endswith('{') or \ + stripped.endswith('(') or \ + stripped.endswith('\\') or \ + stripped.endswith('r"') or \ + stripped.endswith(']') + + return errors, lines_out + + +def test_lint(): + should_pass = [ + "hello world", + """ + /// docstring + foo + + /// docstring + bar + """ + ] + + should_fail = [ + """ + /// docstring + foo + /// docstring + bar + """ + ] + + for code in should_pass: + errors, _ = lint_lines("test.py", code.split('\n')) + assert len(errors) == 0, f'expected this to pass:\n{code}\ngot: {errors}' + + for code in should_fail: + errors, _ = lint_lines("test.py", code.split('\n')) + assert len(errors) > 0, f'expected this to fail:\n{code}' + + pass + + +def main(): + test_lint() # Make sure we are bug free before we run! + + parser = argparse.ArgumentParser( + description='Lint Rust code with custom linter.') + parser.add_argument('files', metavar='file', type=str, nargs='*', + help='File paths. Empty = all files, recursively.') + parser.add_argument('--fix', dest='fix', action='store_true', + help='Automatically fix the files') + + args = parser.parse_args() + + num_errors = 0 + + if args.files: + for filepath in args.files: + num_errors += lint_file_path(filepath, args) + else: + script_dirpath = os.path.dirname(os.path.realpath(__file__)) + root_dirpath = os.path.abspath(f'{script_dirpath}/..') + os.chdir(root_dirpath) + + exclude = set(['target', 'target_ra']) + for root, dirs, files in os.walk('.', topdown=True): + dirs[:] = [d for d in dirs if d not in exclude] + for filename in files: + if filename.endswith('.rs'): + filepath = os.path.join(root, filename) + num_errors += lint_file_path(filepath, args) + + if num_errors == 0: + print(f"{sys.argv[0]} finished without error") + sys.exit(0) + else: + print(f"{sys.argv[0]} found {num_errors} errors.") + sys.exit(1) + +if __name__ == '__main__': + main() From 7e035c6dd16e605ad640475dbb37bc62867e428e Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 10 Aug 2023 17:09:01 +0200 Subject: [PATCH 37/43] Allow users to opt-out of default `winit` features (#3228) * Do not enable winit features by default * Enable default winit features by default * Add x11 feature --- .github/workflows/rust.yml | 2 +- crates/eframe/Cargo.toml | 14 ++++++++++++-- crates/egui-wgpu/Cargo.toml | 2 +- crates/egui-winit/Cargo.toml | 5 ++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6d4e8e5dd..61fb36f79 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -61,7 +61,7 @@ jobs: run: cargo check --locked --no-default-features --lib --all-targets -p epaint - name: check eframe --no-default-features - run: cargo check --locked --no-default-features --lib --all-targets -p eframe + run: cargo check --locked --no-default-features --features x11 --lib --all-targets -p eframe - name: Test doc-tests run: cargo test --doc --all-features diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index 87ad0a2d7..81b36d82a 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -27,7 +27,14 @@ targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] [features] -default = ["accesskit", "default_fonts", "glow"] +default = [ + "accesskit", + "default_fonts", + "glow", + "wayland", + "winit/default", + "x11", +] ## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/). accesskit = ["egui/accesskit", "egui-winit/accesskit"] @@ -42,6 +49,9 @@ 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", @@ -109,7 +119,7 @@ image = { version = "0.24", default-features = false, features = [ "png", ] } # Needed for app icon raw-window-handle = { version = "0.5.0" } -winit = "0.28.1" +winit = { version = "0.28.1", default-features = false } # optional native: directories-next = { version = "2", optional = true } diff --git a/crates/egui-wgpu/Cargo.toml b/crates/egui-wgpu/Cargo.toml index 7fc095b2d..d1812dcb0 100644 --- a/crates/egui-wgpu/Cargo.toml +++ b/crates/egui-wgpu/Cargo.toml @@ -50,7 +50,7 @@ wgpu = "0.16.0" ## Enable this when generating docs. document-features = { version = "0.2", optional = true } -winit = { version = "0.28", optional = true } +winit = { version = "0.28", default-features = false, optional = true } # Native: [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/crates/egui-winit/Cargo.toml b/crates/egui-winit/Cargo.toml index bf3f128f3..27a456da9 100644 --- a/crates/egui-winit/Cargo.toml +++ b/crates/egui-winit/Cargo.toml @@ -18,7 +18,7 @@ all-features = true [features] -default = ["clipboard", "links", "wayland", "winit/default"] +default = ["clipboard", "links", "wayland", "winit/default", "x11"] ## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/). accesskit = ["accesskit_winit", "egui/accesskit"] @@ -42,6 +42,9 @@ serde = ["egui/serde", "dep:serde"] ## Enables Wayland support. 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) From 1e885abe0835589f6aaf14ec8849cec22b02e079 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 10 Aug 2023 17:28:21 +0200 Subject: [PATCH 38/43] Gracefully catch error saving state to disk (#3230) --- crates/eframe/src/native/file_storage.rs | 45 ++++++++++++++++++++---- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/crates/eframe/src/native/file_storage.rs b/crates/eframe/src/native/file_storage.rs index 30ec3cb64..2f316a8c9 100644 --- a/crates/eframe/src/native/file_storage.rs +++ b/crates/eframe/src/native/file_storage.rs @@ -80,14 +80,45 @@ impl crate::Storage for FileStorage { join_handle.join().ok(); } - let join_handle = std::thread::spawn(move || { - let file = std::fs::File::create(&file_path).unwrap(); - let config = Default::default(); - ron::ser::to_writer_pretty(file, &kv, config).unwrap(); - log::trace!("Persisted to {:?}", file_path); - }); + match std::thread::Builder::new() + .name("eframe_persist".to_owned()) + .spawn(move || { + save_to_disk(&file_path, &kv); + }) { + Ok(join_handle) => { + self.last_save_join_handle = Some(join_handle); + } + Err(err) => { + log::warn!("Failed to spawn thread to save app state: {err}"); + } + } + } + } +} - self.last_save_join_handle = Some(join_handle); +fn save_to_disk(file_path: &PathBuf, kv: &HashMap) { + crate::profile_function!(); + + if let Some(parent_dir) = file_path.parent() { + if !parent_dir.exists() { + if let Err(err) = std::fs::create_dir_all(parent_dir) { + log::warn!("Failed to create directory {parent_dir:?}: {err}"); + } + } + } + + match std::fs::File::create(file_path) { + Ok(file) => { + let config = Default::default(); + + if let Err(err) = ron::ser::to_writer_pretty(file, &kv, config) { + log::warn!("Failed to serialize app state: {err}"); + } else { + log::trace!("Persisted to {:?}", file_path); + } + } + Err(err) => { + log::warn!("Failed to create file {file_path:?}: {err}"); } } } From ea6bdfc1c9544e4a9239ec8007107f13c10eb4c7 Mon Sep 17 00:00:00 2001 From: Idan Arye Date: Fri, 11 Aug 2023 09:23:29 +0300 Subject: [PATCH 39/43] Force `ColorPickerFn` to be `Send + Sync` (#3148) (#3233) --- crates/egui/src/grid.rs | 4 ++-- crates/egui/src/ui.rs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/egui/src/grid.rs b/crates/egui/src/grid.rs index eb33e00ed..acd5c3576 100644 --- a/crates/egui/src/grid.rs +++ b/crates/egui/src/grid.rs @@ -47,7 +47,7 @@ impl State { // ---------------------------------------------------------------------------- // type alias for boxed function to determine row color during grid generation -type ColorPickerFn = Box Option>; +type ColorPickerFn = Box Option>; pub(crate) struct GridLayout { ctx: Context, @@ -312,7 +312,7 @@ impl Grid { /// Setting this will allow for dynamic coloring of rows of the grid object pub fn with_row_color(mut self, color_picker: F) -> Self where - F: Fn(usize, &Style) -> Option + 'static, + F: Send + Sync + Fn(usize, &Style) -> Option + 'static, { self.color_picker = Some(Box::new(color_picker)); self diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 83713e487..e29a40097 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -2245,3 +2245,9 @@ impl Ui { } } } + +#[test] +fn ui_impl_send_sync() { + fn assert_send_sync() {} + assert_send_sync::(); +} From bdeae9e9596f2b2fbe20c77d2c3a5e54da507f8c Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 11 Aug 2023 08:24:39 +0200 Subject: [PATCH 40/43] Fix crash in DragValue when only setting `min_decimals` (#3231) --- crates/egui/src/widgets/drag_value.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index b09033c19..2b62c8d8f 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -405,7 +405,9 @@ impl<'a> Widget for DragValue<'a> { let auto_decimals = (aim_rad / speed.abs()).log10().ceil().clamp(0.0, 15.0) as usize; let auto_decimals = auto_decimals + is_slow_speed as usize; - let max_decimals = max_decimals.unwrap_or(auto_decimals + 2); + let max_decimals = max_decimals + .unwrap_or(auto_decimals + 2) + .at_least(min_decimals); let auto_decimals = auto_decimals.clamp(min_decimals, max_decimals); let change = ui.input_mut(|input| { From 08fb447fb55293b2d49343cf5ade2c59d436bc58 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 11 Aug 2023 13:54:02 +0200 Subject: [PATCH 41/43] Increase MSRV to 1.67 (#3234) * Bump MSRV to 1.67 * clippy fixes * cargo clippy: inline format args * Add `clippy::uninlined_format_args` to cranky lints * Fix clippy on wasm * More clippy fixes --- .github/workflows/rust.yml | 10 ++--- Cranky.toml | 1 + clippy.toml | 2 +- crates/ecolor/Cargo.toml | 2 +- crates/eframe/Cargo.toml | 2 +- crates/eframe/src/native/run.rs | 2 +- crates/eframe/src/web/mod.rs | 2 +- crates/eframe/src/web/text_agent.rs | 7 ++- crates/eframe/src/web/web_painter_glow.rs | 2 +- crates/eframe/src/web/web_painter_wgpu.rs | 3 +- crates/egui-wgpu/Cargo.toml | 2 +- crates/egui-wgpu/src/renderer.rs | 5 +-- crates/egui-winit/Cargo.toml | 2 +- crates/egui/Cargo.toml | 2 +- crates/egui/src/context.rs | 19 ++++---- crates/egui/src/data/input.rs | 14 +++--- crates/egui/src/data/output.rs | 20 ++++----- crates/egui/src/input_state.rs | 43 +++++++++---------- crates/egui/src/input_state/touch_state.rs | 4 +- crates/egui/src/introspection.rs | 7 +-- crates/egui/src/painter.rs | 2 +- crates/egui/src/widgets/color_picker.rs | 8 ++-- crates/egui/src/widgets/drag_value.rs | 2 +- crates/egui/src/widgets/plot/items/mod.rs | 2 +- crates/egui/src/widgets/plot/items/values.rs | 4 +- crates/egui/src/widgets/plot/mod.rs | 4 +- crates/egui_demo_app/Cargo.toml | 2 +- crates/egui_demo_app/src/apps/http_app.rs | 2 +- crates/egui_demo_app/src/backend_panel.rs | 5 +-- crates/egui_demo_app/src/wrap_app.rs | 2 +- crates/egui_demo_lib/Cargo.toml | 2 +- crates/egui_demo_lib/src/demo/about.rs | 4 +- crates/egui_demo_lib/src/demo/code_example.rs | 2 +- .../src/demo/demo_app_windows.rs | 4 +- crates/egui_demo_lib/src/demo/layout_test.rs | 4 +- .../src/demo/misc_demo_window.rs | 2 +- crates/egui_demo_lib/src/demo/multi_touch.rs | 2 +- crates/egui_demo_lib/src/demo/plot_demo.rs | 13 +++--- crates/egui_demo_lib/src/demo/scrolling.rs | 7 ++- crates/egui_demo_lib/src/demo/tests.rs | 10 ++--- .../egui_demo_lib/src/demo/widget_gallery.rs | 8 ++-- .../src/easy_mark/easy_mark_viewer.rs | 2 +- crates/egui_extras/Cargo.toml | 2 +- crates/egui_extras/src/datepicker/popup.rs | 2 +- crates/egui_extras/src/image.rs | 2 +- crates/egui_glium/Cargo.toml | 2 +- crates/egui_glow/Cargo.toml | 2 +- crates/emath/Cargo.toml | 2 +- crates/emath/src/lib.rs | 8 ++-- crates/emath/src/pos2.rs | 4 +- crates/emath/src/rot2.rs | 5 +-- crates/emath/src/vec2.rs | 4 +- crates/epaint/Cargo.toml | 2 +- crates/epaint/src/mesh.rs | 3 +- crates/epaint/src/mutex.rs | 2 +- crates/epaint/src/stats.rs | 2 +- crates/epaint/src/text/font.rs | 3 +- crates/epaint/src/text/fonts.rs | 17 +++----- examples/confirm_exit/Cargo.toml | 2 +- examples/custom_3d_glow/Cargo.toml | 2 +- examples/custom_3d_glow/src/main.rs | 2 +- examples/custom_font/Cargo.toml | 2 +- examples/custom_font_style/Cargo.toml | 2 +- examples/custom_window_frame/Cargo.toml | 2 +- examples/download_image/Cargo.toml | 2 +- examples/download_image/src/main.rs | 3 +- examples/file_dialog/Cargo.toml | 2 +- examples/hello_world/Cargo.toml | 2 +- examples/hello_world_par/Cargo.toml | 2 +- examples/hello_world_par/src/main.rs | 2 +- examples/hello_world_simple/Cargo.toml | 2 +- examples/keyboard_events/Cargo.toml | 2 +- examples/puffin_profiler/Cargo.toml | 2 +- examples/puffin_profiler/src/main.rs | 2 +- examples/retained_image/Cargo.toml | 2 +- examples/save_plot/Cargo.toml | 2 +- examples/save_plot/src/main.rs | 2 +- examples/screenshot/Cargo.toml | 2 +- examples/serial_windows/Cargo.toml | 2 +- examples/svg/Cargo.toml | 2 +- examples/user_attention/Cargo.toml | 2 +- examples/user_attention/src/main.rs | 2 +- rust-toolchain | 2 +- scripts/clippy_wasm/clippy.toml | 2 +- 84 files changed, 166 insertions(+), 193 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 61fb36f79..cd73fd9d8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -19,7 +19,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.65.0 + toolchain: 1.67.0 - name: Install packages (Linux) if: runner.os == 'Linux' @@ -87,7 +87,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.65.0 + toolchain: 1.67.0 targets: wasm32-unknown-unknown - run: sudo apt-get update && sudo apt-get install libgtk-3-dev @@ -145,7 +145,7 @@ jobs: - uses: actions/checkout@v3 - uses: EmbarkStudios/cargo-deny-action@v1 with: - rust-version: "1.65.0" + rust-version: "1.67.0" log-level: error command: check arguments: --target ${{ matrix.target }} @@ -160,7 +160,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.65.0 + toolchain: 1.67.0 targets: aarch64-linux-android - name: Set up cargo cache @@ -178,7 +178,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.65.0 + toolchain: 1.67.0 - name: Set up cargo cache uses: Swatinem/rust-cache@v2 diff --git a/Cranky.toml b/Cranky.toml index 6fa6ca093..aaa2d8d6d 100644 --- a/Cranky.toml +++ b/Cranky.toml @@ -91,6 +91,7 @@ warn = [ "clippy::trailing_empty_array", "clippy::trait_duplication_in_bounds", "clippy::unimplemented", + "clippy::uninlined_format_args", "clippy::unnecessary_wraps", "clippy::unnested_or_patterns", "clippy::unused_peekable", diff --git a/clippy.toml b/clippy.toml index 31bbadb86..38feddcf0 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,6 +1,6 @@ # There is also a scripts/clippy_wasm/clippy.toml which forbids some mthods that are not available in wasm. -msrv = "1.65" +msrv = "1.67" # Allow-list of words for markdown in dosctrings https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown doc-valid-idents = [ diff --git a/crates/ecolor/Cargo.toml b/crates/ecolor/Cargo.toml index 6a2feb2ee..ea2f895fd 100644 --- a/crates/ecolor/Cargo.toml +++ b/crates/ecolor/Cargo.toml @@ -7,7 +7,7 @@ authors = [ ] description = "Color structs and color conversion utilities" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index 81b36d82a..8046394e8 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "egui framework - write GUI apps that compiles to web and/or natively" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/eframe" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 3672c9bf1..af8d3aed6 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -708,7 +708,7 @@ mod glow_integration { let painter = egui_glow::Painter::new(gl.clone(), "", self.native_options.shader_version) - .unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error)); + .unwrap_or_else(|err| panic!("An OpenGL error occurred: {err}\n")); let system_theme = system_theme(gl_window.window(), &self.native_options); let mut integration = epi_integration::EpiIntegration::new( diff --git a/crates/eframe/src/web/mod.rs b/crates/eframe/src/web/mod.rs index 5cea5d612..9c3920a50 100644 --- a/crates/eframe/src/web/mod.rs +++ b/crates/eframe/src/web/mod.rs @@ -104,7 +104,7 @@ pub fn canvas_element(canvas_id: &str) -> Option { pub fn canvas_element_or_die(canvas_id: &str) -> web_sys::HtmlCanvasElement { canvas_element(canvas_id) - .unwrap_or_else(|| panic!("Failed to find canvas with id {:?}", canvas_id)) + .unwrap_or_else(|| panic!("Failed to find canvas with id {canvas_id:?}")) } fn canvas_origin(canvas_id: &str) -> egui::Pos2 { diff --git a/crates/eframe/src/web/text_agent.rs b/crates/eframe/src/web/text_agent.rs index 579f98c79..1688163b3 100644 --- a/crates/eframe/src/web/text_agent.rs +++ b/crates/eframe/src/web/text_agent.rs @@ -104,8 +104,7 @@ pub fn install_text_agent(runner_ref: &WebRunner) -> Result<(), JsValue> { runner_ref.add_event_listener(&input, "focusout", move |_event: web_sys::MouseEvent, _| { // Delay 10 ms, and focus again. let func = js_sys::Function::new_no_args(&format!( - "document.getElementById('{}').focus()", - AGENT_ID + "document.getElementById('{AGENT_ID}').focus()" )); window .set_timeout_with_callback_and_timeout_and_arguments_0(&func, 10) @@ -221,8 +220,8 @@ pub fn move_text_cursor(cursor: Option, canvas_id: &str) -> Option<( let x = (x - canvas.offset_width() as f32 / 2.0) .min(canvas.client_width() as f32 - bounding_rect.width() as f32); style.set_property("position", "absolute").ok()?; - style.set_property("top", &format!("{}px", y)).ok()?; - style.set_property("left", &format!("{}px", x)).ok() + style.set_property("top", &format!("{y}px")).ok()?; + style.set_property("left", &format!("{x}px")).ok() }) } else { style.set_property("position", "absolute").ok()?; diff --git a/crates/eframe/src/web/web_painter_glow.rs b/crates/eframe/src/web/web_painter_glow.rs index 939ac8a0b..b12ac1cef 100644 --- a/crates/eframe/src/web/web_painter_glow.rs +++ b/crates/eframe/src/web/web_painter_glow.rs @@ -27,7 +27,7 @@ impl WebPainterGlow { let gl = std::sync::Arc::new(gl); let painter = egui_glow::Painter::new(gl, shader_prefix, None) - .map_err(|error| format!("Error starting glow painter: {}", error))?; + .map_err(|err| format!("Error starting glow painter: {err}"))?; Ok(Self { canvas, diff --git a/crates/eframe/src/web/web_painter_wgpu.rs b/crates/eframe/src/web/web_painter_wgpu.rs index 80abb5bf7..83510dc4f 100644 --- a/crates/eframe/src/web/web_painter_wgpu.rs +++ b/crates/eframe/src/web/web_painter_wgpu.rs @@ -87,8 +87,7 @@ impl WebPainterWgpu { } else { // Workaround for https://github.com/gfx-rs/wgpu/issues/3710: // Don't use `create_surface_from_canvas`, but `create_surface` instead! - let raw_window = - EguiWebWindow(egui::util::hash(&format!("egui on wgpu {canvas_id}")) as u32); + let raw_window = EguiWebWindow(egui::util::hash(("egui on wgpu", canvas_id)) as u32); canvas.set_attribute("data-raw-handle", &raw_window.0.to_string()); #[allow(unsafe_code)] diff --git a/crates/egui-wgpu/Cargo.toml b/crates/egui-wgpu/Cargo.toml index d1812dcb0..7df86b6aa 100644 --- a/crates/egui-wgpu/Cargo.toml +++ b/crates/egui-wgpu/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Emil Ernerfeldt ", ] edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/egui-wgpu" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/egui-wgpu/src/renderer.rs b/crates/egui-wgpu/src/renderer.rs index fe925857d..c3def5fce 100644 --- a/crates/egui-wgpu/src/renderer.rs +++ b/crates/egui-wgpu/src/renderer.rs @@ -560,7 +560,7 @@ impl Renderer { } else { // allocate a new texture // Use same label for all resources associated with this texture id (no point in retyping the type) - let label_str = format!("egui_texid_{:?}", id); + let label_str = format!("egui_texid_{id:?}"); let label = Some(label_str.as_str()); let texture = device.create_texture(&wgpu::TextureDescriptor { label, @@ -904,8 +904,7 @@ fn create_sampler( }; device.create_sampler(&wgpu::SamplerDescriptor { label: Some(&format!( - "egui sampler (mag: {:?}, min {:?})", - mag_filter, min_filter + "egui sampler (mag: {mag_filter:?}, min {min_filter:?})" )), mag_filter, min_filter, diff --git a/crates/egui-winit/Cargo.toml b/crates/egui-winit/Cargo.toml index 27a456da9..2d6833d91 100644 --- a/crates/egui-winit/Cargo.toml +++ b/crates/egui-winit/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "Bindings for using egui with winit" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/egui-winit" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/egui/Cargo.toml b/crates/egui/Cargo.toml index 913a17cd1..615195836 100644 --- a/crates/egui/Cargo.toml +++ b/crates/egui/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "An easy-to-use immediate mode GUI that runs on both web and native" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui" license = "MIT OR Apache-2.0" readme = "../../README.md" diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index bcb61d2c0..d8d5a0f5a 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -566,7 +566,7 @@ impl Context { } let show_error = |widget_rect: Rect, text: String| { - let text = format!("🔥 {}", text); + let text = format!("🔥 {text}"); let color = self.style().visuals.error_fg_color; let painter = self.debug_painter(); painter.rect_stroke(widget_rect, 0.0, (1.0, color)); @@ -612,10 +612,10 @@ impl Context { let id_str = id.short_debug_format(); if prev_rect.min.distance(new_rect.min) < 4.0 { - show_error(new_rect, format!("Double use of {} ID {}", what, id_str)); + show_error(new_rect, format!("Double use of {what} ID {id_str}")); } else { - show_error(prev_rect, format!("First use of {} ID {}", what, id_str)); - show_error(new_rect, format!("Second use of {} ID {}", what, id_str)); + show_error(prev_rect, format!("First use of {what} ID {id_str}")); + show_error(new_rect, format!("Second use of {what} ID {id_str}")); } } @@ -1574,14 +1574,14 @@ impl Context { let pointer_pos = self .pointer_hover_pos() - .map_or_else(String::new, |pos| format!("{:?}", pos)); - ui.label(format!("Pointer pos: {}", pointer_pos)); + .map_or_else(String::new, |pos| format!("{pos:?}")); + ui.label(format!("Pointer pos: {pointer_pos}")); let top_layer = self .pointer_hover_pos() .and_then(|pos| self.layer_id_at(pos)) .map_or_else(String::new, |layer| layer.short_debug_format()); - ui.label(format!("Top layer under mouse: {}", top_layer)); + ui.label(format!("Top layer under mouse: {top_layer}")); ui.add_space(16.0); @@ -1667,7 +1667,7 @@ impl Context { ui.image(texture_id, size); }); - ui.label(format!("{} x {}", w, h)); + ui.label(format!("{w} x {h}")); ui.label(format!("{:.3} MB", meta.bytes_used() as f64 * 1e-6)); ui.label(format!("{:?}", meta.name)); ui.end_row(); @@ -1688,8 +1688,7 @@ impl Context { let (num_state, num_serialized) = self.data(|d| (d.len(), d.count_serialized())); ui.label(format!( - "{} widget states stored (of which {} are serialized).", - num_state, num_serialized + "{num_state} widget states stored (of which {num_serialized} are serialized)." )); ui.horizontal(|ui| { diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 4bb9fdc06..bb1b9f6a9 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -937,25 +937,25 @@ impl RawInput { focused, } = self; - ui.label(format!("screen_rect: {:?} points", screen_rect)); - ui.label(format!("pixels_per_point: {:?}", pixels_per_point)) + ui.label(format!("screen_rect: {screen_rect:?} points")); + ui.label(format!("pixels_per_point: {pixels_per_point:?}")) .on_hover_text( "Also called HDPI factor.\nNumber of physical pixels per each logical pixel.", ); - ui.label(format!("max_texture_side: {:?}", max_texture_side)); + ui.label(format!("max_texture_side: {max_texture_side:?}")); if let Some(time) = time { - ui.label(format!("time: {:.3} s", time)); + ui.label(format!("time: {time:.3} s")); } else { ui.label("time: None"); } ui.label(format!("predicted_dt: {:.1} ms", 1e3 * predicted_dt)); - ui.label(format!("modifiers: {:#?}", modifiers)); + ui.label(format!("modifiers: {modifiers:#?}")); ui.label(format!("hovered_files: {}", hovered_files.len())); ui.label(format!("dropped_files: {}", dropped_files.len())); - ui.label(format!("focused: {}", focused)); + ui.label(format!("focused: {focused}")); ui.scope(|ui| { ui.set_min_height(150.0); - ui.label(format!("events: {:#?}", events)) + ui.label(format!("events: {events:#?}")) .on_hover_text("key presses etc"); }); } diff --git a/crates/egui/src/data/output.rs b/crates/egui/src/data/output.rs index cea031ed0..156a34928 100644 --- a/crates/egui/src/data/output.rs +++ b/crates/egui/src/data/output.rs @@ -100,7 +100,7 @@ impl PlatformOutput { /// This can be used by a text-to-speech system to describe the events (if any). pub fn events_description(&self) -> String { // only describe last event: - if let Some(event) = self.events.iter().rev().next() { + if let Some(event) = self.events.iter().next_back() { match event { OutputEvent::Clicked(widget_info) | OutputEvent::DoubleClicked(widget_info) @@ -417,12 +417,12 @@ impl OutputEvent { impl std::fmt::Debug for OutputEvent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Clicked(wi) => write!(f, "Clicked({:?})", wi), - Self::DoubleClicked(wi) => write!(f, "DoubleClicked({:?})", wi), - Self::TripleClicked(wi) => write!(f, "TripleClicked({:?})", wi), - Self::FocusGained(wi) => write!(f, "FocusGained({:?})", wi), - Self::TextSelectionChanged(wi) => write!(f, "TextSelectionChanged({:?})", wi), - Self::ValueChanged(wi) => write!(f, "ValueChanged({:?})", wi), + Self::Clicked(wi) => write!(f, "Clicked({wi:?})"), + Self::DoubleClicked(wi) => write!(f, "DoubleClicked({wi:?})"), + Self::TripleClicked(wi) => write!(f, "TripleClicked({wi:?})"), + Self::FocusGained(wi) => write!(f, "FocusGained({wi:?})"), + Self::TextSelectionChanged(wi) => write!(f, "TextSelectionChanged({wi:?})"), + Self::ValueChanged(wi) => write!(f, "ValueChanged({wi:?})"), } } } @@ -609,14 +609,14 @@ impl WidgetInfo { if let Some(selected) = selected { if *typ == WidgetType::Checkbox { let state = if *selected { "checked" } else { "unchecked" }; - description = format!("{} {}", state, description); + description = format!("{state} {description}"); } else { description += if *selected { "selected" } else { "" }; }; } if let Some(label) = label { - description = format!("{}: {}", label, description); + description = format!("{label}: {description}"); } if typ == &WidgetType::TextEdit { @@ -630,7 +630,7 @@ impl WidgetInfo { } else { text = "blank".into(); } - description = format!("{}: {}", text, description); + description = format!("{text}: {description}"); } if let Some(value) = value { diff --git a/crates/egui/src/input_state.rs b/crates/egui/src/input_state.rs index 1b49757bc..1c0fe22f6 100644 --- a/crates/egui/src/input_state.rs +++ b/crates/egui/src/input_state.rs @@ -990,30 +990,28 @@ impl InputState { }); } - ui.label(format!("scroll_delta: {:?} points", scroll_delta)); - ui.label(format!("zoom_factor_delta: {:4.2}x", zoom_factor_delta)); - ui.label(format!("screen_rect: {:?} points", screen_rect)); + 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!( - "{} physical pixels for each logical point", - pixels_per_point + "{pixels_per_point} physical pixels for each logical point" )); ui.label(format!( - "max texture size (on each side): {}", - max_texture_side + "max texture size (on each side): {max_texture_side}" )); - ui.label(format!("time: {:.3} s", time)); + ui.label(format!("time: {time:.3} s")); ui.label(format!( "time since previous frame: {:.1} ms", 1e3 * unstable_dt )); ui.label(format!("predicted_dt: {:.1} ms", 1e3 * predicted_dt)); ui.label(format!("stable_dt: {:.1} ms", 1e3 * stable_dt)); - ui.label(format!("focused: {}", focused)); - ui.label(format!("modifiers: {:#?}", modifiers)); - ui.label(format!("keys_down: {:?}", keys_down)); + ui.label(format!("focused: {focused}")); + ui.label(format!("modifiers: {modifiers:#?}")); + ui.label(format!("keys_down: {keys_down:?}")); ui.scope(|ui| { ui.set_min_height(150.0); - ui.label(format!("events: {:#?}", events)) + ui.label(format!("events: {events:#?}")) .on_hover_text("key presses etc"); }); } @@ -1037,22 +1035,21 @@ impl PointerState { pointer_events, } = self; - ui.label(format!("latest_pos: {:?}", latest_pos)); - ui.label(format!("interact_pos: {:?}", interact_pos)); - ui.label(format!("delta: {:?}", delta)); + ui.label(format!("latest_pos: {latest_pos:?}")); + ui.label(format!("interact_pos: {interact_pos:?}")); + ui.label(format!("delta: {delta:?}")); ui.label(format!( "velocity: [{:3.0} {:3.0}] points/sec", velocity.x, velocity.y )); - ui.label(format!("down: {:#?}", down)); - ui.label(format!("press_origin: {:?}", press_origin)); - ui.label(format!("press_start_time: {:?} s", press_start_time)); + ui.label(format!("down: {down:#?}")); + ui.label(format!("press_origin: {press_origin:?}")); + ui.label(format!("press_start_time: {press_start_time:?} s")); ui.label(format!( - "has_moved_too_much_for_a_click: {}", - has_moved_too_much_for_a_click + "has_moved_too_much_for_a_click: {has_moved_too_much_for_a_click}" )); - ui.label(format!("last_click_time: {:#?}", last_click_time)); - ui.label(format!("last_last_click_time: {:#?}", last_last_click_time)); - ui.label(format!("pointer_events: {:?}", pointer_events)); + ui.label(format!("last_click_time: {last_click_time:#?}")); + ui.label(format!("last_last_click_time: {last_last_click_time:#?}")); + ui.label(format!("pointer_events: {pointer_events:?}")); } } diff --git a/crates/egui/src/input_state/touch_state.rs b/crates/egui/src/input_state/touch_state.rs index becd0d527..37d418a53 100644 --- a/crates/egui/src/input_state/touch_state.rs +++ b/crates/egui/src/input_state/touch_state.rs @@ -286,7 +286,7 @@ impl TouchState { impl TouchState { pub fn ui(&self, ui: &mut crate::Ui) { - ui.label(format!("{:?}", self)); + ui.label(format!("{self:?}")); } } @@ -294,7 +294,7 @@ impl Debug for TouchState { // This outputs less clutter than `#[derive(Debug)]`: fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for (id, touch) in &self.active_touches { - f.write_fmt(format_args!("#{:?}: {:#?}\n", id, touch))?; + f.write_fmt(format_args!("#{id:?}: {touch:#?}\n"))?; } f.write_fmt(format_args!("gesture: {:#?}\n", self.gesture_state))?; Ok(()) diff --git a/crates/egui/src/introspection.rs b/crates/egui/src/introspection.rs index ae66cddb0..6f0cada78 100644 --- a/crates/egui/src/introspection.rs +++ b/crates/egui/src/introspection.rs @@ -31,10 +31,7 @@ pub(crate) fn font_texture_ui(ui: &mut Ui, [width, height]: [usize; 2]) -> Respo Color32::BLACK }; - ui.label(format!( - "Texture size: {} x {} (hover to zoom)", - width, height - )); + ui.label(format!("Texture size: {width} x {height} (hover to zoom)")); if width <= 1 || height <= 1 { return; } @@ -108,7 +105,7 @@ impl Widget for &epaint::stats::PaintStats { label(ui, shape_path, "paths"); label(ui, shape_mesh, "nested meshes"); label(ui, shape_vec, "nested shapes"); - ui.label(format!("{:6} callbacks", num_callbacks)); + ui.label(format!("{num_callbacks:6} callbacks")); ui.add_space(10.0); ui.label("Text shapes:"); diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index baf3b9212..17028e6cc 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -226,7 +226,7 @@ impl Painter { pub fn error(&self, pos: Pos2, text: impl std::fmt::Display) -> Rect { let color = self.ctx.style().visuals.error_fg_color; - self.debug_text(pos, Align2::LEFT_TOP, color, format!("🔥 {}", text)) + self.debug_text(pos, Align2::LEFT_TOP, color, format!("🔥 {text}")) } /// text with a background diff --git a/crates/egui/src/widgets/color_picker.rs b/crates/egui/src/widgets/color_picker.rs index da5f2867d..fcb701f47 100644 --- a/crates/egui/src/widgets/color_picker.rs +++ b/crates/egui/src/widgets/color_picker.rs @@ -234,17 +234,17 @@ fn color_text_ui(ui: &mut Ui, color: impl Into, alpha: Alpha) { if ui.button("📋").on_hover_text("Click to copy").clicked() { if alpha == Alpha::Opaque { - ui.output_mut(|o| o.copied_text = format!("{}, {}, {}", r, g, b)); + ui.output_mut(|o| o.copied_text = format!("{r}, {g}, {b}")); } else { - ui.output_mut(|o| o.copied_text = format!("{}, {}, {}, {}", r, g, b, a)); + ui.output_mut(|o| o.copied_text = format!("{r}, {g}, {b}, {a}")); } } if alpha == Alpha::Opaque { - ui.label(format!("rgb({}, {}, {})", r, g, b)) + ui.label(format!("rgb({r}, {g}, {b})")) .on_hover_text("Red Green Blue"); } else { - ui.label(format!("rgba({}, {}, {}, {})", r, g, b, a)) + ui.label(format!("rgba({r}, {g}, {b}, {a})")) .on_hover_text("Red Green Blue with premultiplied Alpha"); } }); diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 2b62c8d8f..0e1b54605 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -627,7 +627,7 @@ impl<'a> Widget for DragValue<'a> { // The value is exposed as a string by the text edit widget // when in edit mode. if !is_kb_editing { - let value_text = format!("{}{}{}", prefix, value_text, suffix); + let value_text = format!("{prefix}{value_text}{suffix}"); builder.set_value(value_text); } }); diff --git a/crates/egui/src/widgets/plot/items/mod.rs b/crates/egui/src/widgets/plot/items/mod.rs index f18f34aff..2cbcb26dd 100644 --- a/crates/egui/src/widgets/plot/items/mod.rs +++ b/crates/egui/src/widgets/plot/items/mod.rs @@ -1732,7 +1732,7 @@ pub(super) fn rulers_at_value( let mut prefix = String::new(); if !name.is_empty() { - prefix = format!("{}\n", name); + prefix = format!("{name}\n"); } let text = { diff --git a/crates/egui/src/widgets/plot/items/values.rs b/crates/egui/src/widgets/plot/items/values.rs index 739490dcf..52fceba7b 100644 --- a/crates/egui/src/widgets/plot/items/values.rs +++ b/crates/egui/src/widgets/plot/items/values.rs @@ -125,8 +125,8 @@ impl ToString for LineStyle { fn to_string(&self) -> String { match self { LineStyle::Solid => "Solid".into(), - LineStyle::Dotted { spacing } => format!("Dotted{}Px", spacing), - LineStyle::Dashed { length } => format!("Dashed{}Px", length), + LineStyle::Dotted { spacing } => format!("Dotted{spacing}Px"), + LineStyle::Dashed { length } => format!("Dashed{length}Px"), } } } diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 9eca796dc..ebc73d728 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1453,7 +1453,7 @@ impl PreparedPlot { let axis_range = match axis { 0 => bounds.range_x(), 1 => bounds.range_y(), - _ => panic!("Axis {} does not exist.", axis), + _ => panic!("Axis {axis} does not exist."), }; let font_id = TextStyle::Body.resolve(ui.style()); @@ -1676,7 +1676,7 @@ pub fn format_number(number: f64, num_decimals: usize) -> String { let is_integral = number as i64 as f64 == number; if is_integral { // perfect integer - show it as such: - format!("{:.0}", number) + format!("{number:.0}") } else { // make sure we tell the user it is not an integer by always showing a decimal or two: format!("{:.*}", num_decimals.at_least(1), number) diff --git a/crates/egui_demo_app/Cargo.toml b/crates/egui_demo_app/Cargo.toml index af3eef61f..79ae48746 100644 --- a/crates/egui_demo_app/Cargo.toml +++ b/crates/egui_demo_app/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false default-run = "egui_demo_app" diff --git a/crates/egui_demo_app/src/apps/http_app.rs b/crates/egui_demo_app/src/apps/http_app.rs index 4d87a3e29..e550c1dbc 100644 --- a/crates/egui_demo_app/src/apps/http_app.rs +++ b/crates/egui_demo_app/src/apps/http_app.rs @@ -133,7 +133,7 @@ fn ui_url(ui: &mut egui::Ui, frame: &mut eframe::Frame, url: &mut String) -> boo if ui.button("Random image").clicked() { let seed = ui.input(|i| i.time); let side = 640; - *url = format!("https://picsum.photos/seed/{}/{}", seed, side); + *url = format!("https://picsum.photos/seed/{seed}/{side}"); trigger_fetch = true; } }); diff --git a/crates/egui_demo_app/src/backend_panel.rs b/crates/egui_demo_app/src/backend_panel.rs index 33d1cc630..6480756f2 100644 --- a/crates/egui_demo_app/src/backend_panel.rs +++ b/crates/egui_demo_app/src/backend_panel.rs @@ -232,8 +232,7 @@ impl BackendPanel { if ui .add_enabled(enabled, egui::Button::new("Reset")) .on_hover_text(format!( - "Reset scale to native value ({:.1})", - native_pixels_per_point + "Reset scale to native value ({native_pixels_per_point:.1})" )) .clicked() { @@ -441,7 +440,7 @@ impl EguiWindows { .stick_to_bottom(true) .show(ui, |ui| { for event in output_event_history { - ui.label(format!("{:?}", event)); + ui.label(format!("{event:?}")); } }); }); diff --git a/crates/egui_demo_app/src/wrap_app.rs b/crates/egui_demo_app/src/wrap_app.rs index 3b2c09a79..69a23e7ab 100644 --- a/crates/egui_demo_app/src/wrap_app.rs +++ b/crates/egui_demo_app/src/wrap_app.rs @@ -354,7 +354,7 @@ impl WrapApp { { selected_anchor = anchor; if frame.is_web() { - ui.output_mut(|o| o.open_url(format!("#{}", anchor))); + ui.output_mut(|o| o.open_url(format!("#{anchor}"))); } } } diff --git a/crates/egui_demo_lib/Cargo.toml b/crates/egui_demo_lib/Cargo.toml index d8f7c688d..e86baca29 100644 --- a/crates/egui_demo_lib/Cargo.toml +++ b/crates/egui_demo_lib/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "Example library for egui" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/egui_demo_lib" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/egui_demo_lib/src/demo/about.rs b/crates/egui_demo_lib/src/demo/about.rs index 0fbb97642..4972b224b 100644 --- a/crates/egui_demo_lib/src/demo/about.rs +++ b/crates/egui_demo_lib/src/demo/about.rs @@ -83,11 +83,11 @@ fn about_immediate_mode(ui: &mut egui::Ui) { fn links(ui: &mut egui::Ui) { use egui::special_emojis::{GITHUB, TWITTER}; ui.hyperlink_to( - format!("{} egui on GitHub", GITHUB), + format!("{GITHUB} egui on GitHub"), "https://github.com/emilk/egui", ); ui.hyperlink_to( - format!("{} @ernerfeldt", TWITTER), + format!("{TWITTER} @ernerfeldt"), "https://twitter.com/ernerfeldt", ); ui.hyperlink_to("egui documentation", "https://docs.rs/egui/"); diff --git a/crates/egui_demo_lib/src/demo/code_example.rs b/crates/egui_demo_lib/src/demo/code_example.rs index c72fde221..7b1351476 100644 --- a/crates/egui_demo_lib/src/demo/code_example.rs +++ b/crates/egui_demo_lib/src/demo/code_example.rs @@ -121,7 +121,7 @@ impl CodeExample { ui.separator(); - code_view_ui(ui, &format!("{:#?}", self)); + code_view_ui(ui, &format!("{self:#?}")); ui.separator(); diff --git a/crates/egui_demo_lib/src/demo/demo_app_windows.rs b/crates/egui_demo_lib/src/demo/demo_app_windows.rs index 4ad6c2d95..354bb44e6 100644 --- a/crates/egui_demo_lib/src/demo/demo_app_windows.rs +++ b/crates/egui_demo_lib/src/demo/demo_app_windows.rs @@ -251,11 +251,11 @@ impl DemoWindows { use egui::special_emojis::{GITHUB, TWITTER}; ui.hyperlink_to( - format!("{} egui on GitHub", GITHUB), + format!("{GITHUB} egui on GitHub"), "https://github.com/emilk/egui", ); ui.hyperlink_to( - format!("{} @ernerfeldt", TWITTER), + format!("{TWITTER} @ernerfeldt"), "https://twitter.com/ernerfeldt", ); diff --git a/crates/egui_demo_lib/src/demo/layout_test.rs b/crates/egui_demo_lib/src/demo/layout_test.rs index 2d4fa8a82..8adf1bb6b 100644 --- a/crates/egui_demo_lib/src/demo/layout_test.rs +++ b/crates/egui_demo_lib/src/demo/layout_test.rs @@ -140,7 +140,7 @@ impl LayoutTest { Direction::TopDown, Direction::BottomUp, ] { - ui.radio_value(&mut self.layout.main_dir, dir, format!("{:?}", dir)); + ui.radio_value(&mut self.layout.main_dir, dir, format!("{dir:?}")); } }); @@ -162,7 +162,7 @@ impl LayoutTest { ui.horizontal(|ui| { ui.label("Cross Align:"); for &align in &[Align::Min, Align::Center, Align::Max] { - ui.radio_value(&mut self.layout.cross_align, align, format!("{:?}", align)); + ui.radio_value(&mut self.layout.cross_align, align, format!("{align:?}")); } }); diff --git a/crates/egui_demo_lib/src/demo/misc_demo_window.rs b/crates/egui_demo_lib/src/demo/misc_demo_window.rs index 61a6091e9..e4cf92644 100644 --- a/crates/egui_demo_lib/src/demo/misc_demo_window.rs +++ b/crates/egui_demo_lib/src/demo/misc_demo_window.rs @@ -455,7 +455,7 @@ impl Tree { .into_iter() .enumerate() .filter_map(|(i, mut tree)| { - if tree.ui_impl(ui, depth + 1, &format!("child #{}", i)) == Action::Keep { + if tree.ui_impl(ui, depth + 1, &format!("child #{i}")) == Action::Keep { Some(tree) } else { None diff --git a/crates/egui_demo_lib/src/demo/multi_touch.rs b/crates/egui_demo_lib/src/demo/multi_touch.rs index c358f6b21..1a3b29e8e 100644 --- a/crates/egui_demo_lib/src/demo/multi_touch.rs +++ b/crates/egui_demo_lib/src/demo/multi_touch.rs @@ -50,7 +50,7 @@ impl super::View for MultiTouch { ui.label("Try touch gestures Pinch/Stretch, Rotation, and Pressure with 2+ fingers."); let num_touches = ui.input(|i| i.multi_touch().map_or(0, |mt| mt.num_touches)); - ui.label(format!("Current touches: {}", num_touches)); + ui.label(format!("Current touches: {num_touches}")); let color = if ui.visuals().dark_mode { Color32::WHITE diff --git a/crates/egui_demo_lib/src/demo/plot_demo.rs b/crates/egui_demo_lib/src/demo/plot_demo.rs index 2f6180eae..8daf3c377 100644 --- a/crates/egui_demo_lib/src/demo/plot_demo.rs +++ b/crates/egui_demo_lib/src/demo/plot_demo.rs @@ -326,7 +326,7 @@ impl MarkerDemo { [5.0, 0.0 + y_offset], [6.0, 0.5 + y_offset], ]) - .name(format!("{:?}", marker)) + .name(format!("{marker:?}")) .filled(self.fill_markers) .radius(self.marker_radius) .shape(marker); @@ -416,7 +416,7 @@ impl LegendDemo { ui.label("Position:"); ui.horizontal(|ui| { Corner::all().for_each(|position| { - ui.selectable_value(&mut config.position, position, format!("{:?}", position)); + ui.selectable_value(&mut config.position, position, format!("{position:?}")); }); }); ui.end_row(); @@ -774,21 +774,18 @@ impl InteractionDemo { "origin in screen coordinates: x: {:.02}, y: {:.02}", screen_pos.x, screen_pos.y )); - ui.label(format!("plot hovered: {}", hovered)); + ui.label(format!("plot hovered: {hovered}")); let coordinate_text = if let Some(coordinate) = pointer_coordinate { format!("x: {:.02}, y: {:.02}", coordinate.x, coordinate.y) } else { "None".to_owned() }; - ui.label(format!("pointer coordinate: {}", coordinate_text)); + ui.label(format!("pointer coordinate: {coordinate_text}")); let coordinate_text = format!( "x: {:.02}, y: {:.02}", pointer_coordinate_drag_delta.x, pointer_coordinate_drag_delta.y ); - ui.label(format!( - "pointer coordinate drag delta: {}", - coordinate_text - )); + ui.label(format!("pointer coordinate drag delta: {coordinate_text}")); response } diff --git a/crates/egui_demo_lib/src/demo/scrolling.rs b/crates/egui_demo_lib/src/demo/scrolling.rs index b970b3264..f5833521b 100644 --- a/crates/egui_demo_lib/src/demo/scrolling.rs +++ b/crates/egui_demo_lib/src/demo/scrolling.rs @@ -232,10 +232,10 @@ impl super::View for ScrollTo { for item in 1..=50 { if track_item && item == self.track_item { let response = - ui.colored_label(Color32::YELLOW, format!("This is item {}", item)); + ui.colored_label(Color32::YELLOW, format!("This is item {item}")); response.scroll_to_me(self.tack_item_align); } else { - ui.label(format!("This is item {}", item)); + ui.label(format!("This is item {item}")); } } }); @@ -254,8 +254,7 @@ impl super::View for ScrollTo { ui.separator(); ui.label(format!( - "Scroll offset: {:.0}/{:.0} px", - current_scroll, max_scroll + "Scroll offset: {current_scroll:.0}/{max_scroll:.0} px" )); ui.separator(); diff --git a/crates/egui_demo_lib/src/demo/tests.rs b/crates/egui_demo_lib/src/demo/tests.rs index 83e798769..784b9525c 100644 --- a/crates/egui_demo_lib/src/demo/tests.rs +++ b/crates/egui_demo_lib/src/demo/tests.rs @@ -20,7 +20,7 @@ impl super::View for CursorTest { ui.heading("Hover to switch cursor icon:"); for &cursor_icon in &egui::CursorIcon::ALL { let _ = ui - .button(format!("{:?}", cursor_icon)) + .button(format!("{cursor_icon:?}")) .on_hover_cursor(cursor_icon); } ui.add(crate::egui_github_link_file!()); @@ -239,7 +239,7 @@ impl super::View for TableTest { for row in 0..self.num_rows { for col in 0..self.num_cols { if col == 0 { - ui.label(format!("row {}", row)); + ui.label(format!("row {row}")); } else { let word_idx = row * 3 + col * 5; let word_count = (row * 5 + col * 75) % 13; @@ -350,13 +350,13 @@ impl super::View for InputTest { use std::fmt::Write as _; if response.clicked_by(button) { - writeln!(new_info, "Clicked by {:?} button", button).ok(); + writeln!(new_info, "Clicked by {button:?} button").ok(); } if response.double_clicked_by(button) { - writeln!(new_info, "Double-clicked by {:?} button", button).ok(); + writeln!(new_info, "Double-clicked by {button:?} button").ok(); } if response.triple_clicked_by(button) { - writeln!(new_info, "Triple-clicked by {:?} button", button).ok(); + writeln!(new_info, "Triple-clicked by {button:?} button").ok(); } if response.dragged_by(button) { writeln!( diff --git a/crates/egui_demo_lib/src/demo/widget_gallery.rs b/crates/egui_demo_lib/src/demo/widget_gallery.rs index d91ae395e..eb424e9e3 100644 --- a/crates/egui_demo_lib/src/demo/widget_gallery.rs +++ b/crates/egui_demo_lib/src/demo/widget_gallery.rs @@ -126,7 +126,7 @@ impl WidgetGallery { ui.add(doc_link_label("Hyperlink", "Hyperlink")); use egui::special_emojis::GITHUB; ui.hyperlink_to( - format!("{} egui on GitHub", GITHUB), + format!("{GITHUB} egui on GitHub"), "https://github.com/emilk/egui", ); ui.end_row(); @@ -173,7 +173,7 @@ impl WidgetGallery { ui.add(doc_link_label("ComboBox", "ComboBox")); egui::ComboBox::from_label("Take your pick") - .selected_text(format!("{:?}", radio)) + .selected_text(format!("{radio:?}")) .show_ui(ui, |ui| { ui.style_mut().wrap = Some(false); ui.set_min_width(60.0); @@ -277,8 +277,8 @@ fn example_plot(ui: &mut egui::Ui) -> egui::Response { } fn doc_link_label<'a>(title: &'a str, search_term: &'a str) -> impl egui::Widget + 'a { - let label = format!("{}:", title); - let url = format!("https://docs.rs/egui?search={}", search_term); + let label = format!("{title}:"); + let url = format!("https://docs.rs/egui?search={search_term}"); move |ui: &mut egui::Ui| { ui.hyperlink_to(label, url).on_hover_ui(|ui| { ui.horizontal_wrapped(|ui| { diff --git a/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs b/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs index 44408ff2b..29be2d2ee 100644 --- a/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs +++ b/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs @@ -161,7 +161,7 @@ fn numbered_point(ui: &mut Ui, width: f32, number: &str) -> Response { let font_id = TextStyle::Body.resolve(ui.style()); let row_height = ui.fonts(|f| f.row_height(&font_id)); let (rect, response) = ui.allocate_exact_size(vec2(width, row_height), Sense::hover()); - let text = format!("{}.", number); + let text = format!("{number}."); let text_color = ui.visuals().strong_text_color(); ui.painter().text( rect.right_center(), diff --git a/crates/egui_extras/Cargo.toml b/crates/egui_extras/Cargo.toml index f5f4595aa..fe3bf8876 100644 --- a/crates/egui_extras/Cargo.toml +++ b/crates/egui_extras/Cargo.toml @@ -8,7 +8,7 @@ authors = [ ] description = "Extra functionality and widgets for the egui GUI library" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/egui_extras/src/datepicker/popup.rs b/crates/egui_extras/src/datepicker/popup.rs index 7da8cbc1a..d8dd46724 100644 --- a/crates/egui_extras/src/datepicker/popup.rs +++ b/crates/egui_extras/src/datepicker/popup.rs @@ -428,6 +428,6 @@ fn month_name(i: u32) -> &'static str { 10 => "October", 11 => "November", 12 => "December", - _ => panic!("Unknown month: {}", i), + _ => panic!("Unknown month: {i}"), } } diff --git a/crates/egui_extras/src/image.rs b/crates/egui_extras/src/image.rs index ba8acaf41..bec11d1ab 100644 --- a/crates/egui_extras/src/image.rs +++ b/crates/egui_extras/src/image.rs @@ -258,7 +258,7 @@ pub fn load_svg_bytes_with_size( }; let mut pixmap = tiny_skia::Pixmap::new(w, h) - .ok_or_else(|| format!("Failed to create SVG Pixmap of size {}x{}", w, h))?; + .ok_or_else(|| format!("Failed to create SVG Pixmap of size {w}x{h}"))?; resvg::render(&rtree, fit_to, Default::default(), pixmap.as_mut()) .ok_or_else(|| "Failed to render SVG".to_owned())?; diff --git a/crates/egui_glium/Cargo.toml b/crates/egui_glium/Cargo.toml index 9be5870dd..a4be314d4 100644 --- a/crates/egui_glium/Cargo.toml +++ b/crates/egui_glium/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "Bindings for using egui natively using the glium library" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/egui_glium" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/egui_glow/Cargo.toml b/crates/egui_glow/Cargo.toml index 1c1a797cb..dfd6e0de4 100644 --- a/crates/egui_glow/Cargo.toml +++ b/crates/egui_glow/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "Bindings for using egui natively using the glow library" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/egui_glow" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/emath/Cargo.toml b/crates/emath/Cargo.toml index d4eec7c7e..8fea677e3 100644 --- a/crates/emath/Cargo.toml +++ b/crates/emath/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "Minimal 2D math library for GUI work" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/emath" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crates/emath/src/lib.rs b/crates/emath/src/lib.rs index 25b3b9eac..8cfe16de0 100644 --- a/crates/emath/src/lib.rs +++ b/crates/emath/src/lib.rs @@ -183,9 +183,7 @@ where /// Round a value to the given number of decimal places. pub fn round_to_decimals(value: f64, decimal_places: usize) -> f64 { // This is a stupid way of doing this, but stupid works. - format!("{:.*}", decimal_places, value) - .parse() - .unwrap_or(value) + format!("{value:.decimal_places$}").parse().unwrap_or(value) } pub fn format_with_minimum_decimals(value: f64, decimals: usize) -> String { @@ -203,7 +201,7 @@ pub fn format_with_decimals_in_range(value: f64, decimal_range: RangeInclusive().unwrap(), value as f32, epsilon) { // Enough precision to show the value accurately - good! @@ -214,7 +212,7 @@ pub fn format_with_decimals_in_range(value: f64, decimal_range: RangeInclusive for Pos2 { match index { 0 => &self.x, 1 => &self.y, - _ => panic!("Pos2 index out of bounds: {}", index), + _ => panic!("Pos2 index out of bounds: {index}"), } } } @@ -217,7 +217,7 @@ impl std::ops::IndexMut for Pos2 { match index { 0 => &mut self.x, 1 => &mut self.y, - _ => panic!("Pos2 index out of bounds: {}", index), + _ => panic!("Pos2 index out of bounds: {index}"), } } } diff --git a/crates/emath/src/rot2.rs b/crates/emath/src/rot2.rs index e29f18f4e..b281ca58f 100644 --- a/crates/emath/src/rot2.rs +++ b/crates/emath/src/rot2.rs @@ -184,10 +184,7 @@ mod test { let expected = vec2(0.0, 3.0); assert!( (rotated - expected).length() < 1e-5, - "Expected {:?} to equal {:?}. rot: {:?}", - rotated, - expected, - rot, + "Expected {rotated:?} to equal {expected:?}. rot: {rot:?}", ); let undone = rot.inverse() * rot; diff --git a/crates/emath/src/vec2.rs b/crates/emath/src/vec2.rs index ac70f9b47..133c3fd3c 100644 --- a/crates/emath/src/vec2.rs +++ b/crates/emath/src/vec2.rs @@ -292,7 +292,7 @@ impl std::ops::Index for Vec2 { match index { 0 => &self.x, 1 => &self.y, - _ => panic!("Vec2 index out of bounds: {}", index), + _ => panic!("Vec2 index out of bounds: {index}"), } } } @@ -303,7 +303,7 @@ impl std::ops::IndexMut for Vec2 { match index { 0 => &mut self.x, 1 => &mut self.y, - _ => panic!("Vec2 index out of bounds: {}", index), + _ => panic!("Vec2 index out of bounds: {index}"), } } } diff --git a/crates/epaint/Cargo.toml b/crates/epaint/Cargo.toml index 094b6c45e..5a4c74242 100644 --- a/crates/epaint/Cargo.toml +++ b/crates/epaint/Cargo.toml @@ -4,7 +4,7 @@ version = "0.22.0" authors = ["Emil Ernerfeldt "] description = "Minimal 2D graphics library for GUI work" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" homepage = "https://github.com/emilk/egui/tree/master/crates/epaint" license = "(MIT OR Apache-2.0) AND OFL-1.1 AND LicenseRef-UFL-1.0" # OFL and UFL used by default_fonts. See https://github.com/emilk/egui/issues/2321 readme = "README.md" diff --git a/crates/epaint/src/mesh.rs b/crates/epaint/src/mesh.rs index 09025268a..62f0de21f 100644 --- a/crates/epaint/src/mesh.rs +++ b/crates/epaint/src/mesh.rs @@ -251,8 +251,7 @@ impl Mesh { assert!( index_cursor > span_start, - "One triangle spanned more than {} vertices", - MAX_SIZE + "One triangle spanned more than {MAX_SIZE} vertices" ); let mesh = Mesh16 { diff --git a/crates/epaint/src/mutex.rs b/crates/epaint/src/mutex.rs index cca86466e..ce2bf7c93 100644 --- a/crates/epaint/src/mutex.rs +++ b/crates/epaint/src/mutex.rs @@ -333,7 +333,7 @@ mod rw_lock_impl { fn format_backtrace(backtrace: &mut backtrace::Backtrace) -> String { backtrace.resolve(); - let stacktrace = format!("{:?}", backtrace); + let stacktrace = format!("{backtrace:?}"); // Remove irrelevant parts of the stacktrace: let end_offset = stacktrace diff --git a/crates/epaint/src/stats.rs b/crates/epaint/src/stats.rs index 24293aa7b..6723b61f4 100644 --- a/crates/epaint/src/stats.rs +++ b/crates/epaint/src/stats.rs @@ -106,7 +106,7 @@ impl AllocInfo { element_size: ElementSize::Homogeneous(element_size), num_allocs: 1, num_elements: slice.len(), - num_bytes: slice.len() * element_size, + num_bytes: std::mem::size_of_val(slice), } } diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs index 4cf26014f..dfcb52a11 100644 --- a/crates/epaint/src/text/font.rs +++ b/crates/epaint/src/text/font.rs @@ -367,8 +367,7 @@ impl Font { .or_else(|| slf.glyph_info_no_cache_or_fallback(FALLBACK_REPLACEMENT_CHAR)) .unwrap_or_else(|| { panic!( - "Failed to find replacement characters {:?} or {:?}", - PRIMARY_REPLACEMENT_CHAR, FALLBACK_REPLACEMENT_CHAR + "Failed to find replacement characters {PRIMARY_REPLACEMENT_CHAR:?} or {FALLBACK_REPLACEMENT_CHAR:?}" ) }); slf.replacement_glyph = replacement_glyph; diff --git a/crates/epaint/src/text/fonts.rs b/crates/epaint/src/text/fonts.rs index 829a593f6..474d6e70e 100644 --- a/crates/epaint/src/text/fonts.rs +++ b/crates/epaint/src/text/fonts.rs @@ -200,7 +200,7 @@ fn ab_glyph_font_from_font_data(name: &str, data: &FontData) -> ab_glyph::FontAr .map(ab_glyph::FontArc::from) } } - .unwrap_or_else(|err| panic!("Error parsing {:?} TTF/OTF font file: {}", name, err)) + .unwrap_or_else(|err| panic!("Error parsing {name:?} TTF/OTF font file: {err}")) } /// Describes the font data and the sizes to use. @@ -586,8 +586,7 @@ impl FontsImpl { ) -> Self { assert!( 0.0 < pixels_per_point && pixels_per_point < 100.0, - "pixels_per_point out of range: {}", - pixels_per_point + "pixels_per_point out of range: {pixels_per_point}" ); let texture_width = max_texture_side.at_most(8 * 1024); @@ -627,9 +626,8 @@ impl FontsImpl { .entry((HashableF32(*size), family.clone())) .or_insert_with(|| { let fonts = &self.definitions.families.get(family); - let fonts = fonts.unwrap_or_else(|| { - panic!("FontFamily::{:?} is not bound to any fonts", family) - }); + let fonts = fonts + .unwrap_or_else(|| panic!("FontFamily::{family:?} is not bound to any fonts")); let fonts: Vec> = fonts .iter() @@ -752,17 +750,14 @@ impl FontImplCache { let (tweak, ab_glyph_font) = self .ab_glyph_fonts .get(font_name) - .unwrap_or_else(|| panic!("No font data found for {:?}", font_name)) + .unwrap_or_else(|| panic!("No font data found for {font_name:?}")) .clone(); let scale_in_pixels = self.pixels_per_point * scale_in_points; // Scale the font properly (see https://github.com/emilk/egui/issues/2068). let units_per_em = ab_glyph_font.units_per_em().unwrap_or_else(|| { - panic!( - "The font unit size of {:?} exceeds the expected range (16..=16384)", - font_name - ) + panic!("The font unit size of {font_name:?} exceeds the expected range (16..=16384)") }); let font_scaling = ab_glyph_font.height_unscaled() / units_per_em; let scale_in_pixels = scale_in_pixels * font_scaling; diff --git a/examples/confirm_exit/Cargo.toml b/examples/confirm_exit/Cargo.toml index e4b193e33..08144e7f6 100644 --- a/examples/confirm_exit/Cargo.toml +++ b/examples/confirm_exit/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/custom_3d_glow/Cargo.toml b/examples/custom_3d_glow/Cargo.toml index 9dfa403c6..c75ee3c4d 100644 --- a/examples/custom_3d_glow/Cargo.toml +++ b/examples/custom_3d_glow/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/custom_3d_glow/src/main.rs b/examples/custom_3d_glow/src/main.rs index f72859d23..7cd954c39 100644 --- a/examples/custom_3d_glow/src/main.rs +++ b/examples/custom_3d_glow/src/main.rs @@ -144,7 +144,7 @@ impl RotatingTriangle { let shader = gl .create_shader(*shader_type) .expect("Cannot create shader"); - gl.shader_source(shader, &format!("{}\n{}", shader_version, shader_source)); + gl.shader_source(shader, &format!("{shader_version}\n{shader_source}")); gl.compile_shader(shader); assert!( gl.get_shader_compile_status(shader), diff --git a/examples/custom_font/Cargo.toml b/examples/custom_font/Cargo.toml index 78d0491d3..c7b212b5e 100644 --- a/examples/custom_font/Cargo.toml +++ b/examples/custom_font/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/custom_font_style/Cargo.toml b/examples/custom_font_style/Cargo.toml index 3eda5ee33..3c5e9600f 100644 --- a/examples/custom_font_style/Cargo.toml +++ b/examples/custom_font_style/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["tami5 "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/custom_window_frame/Cargo.toml b/examples/custom_window_frame/Cargo.toml index 1cad5da20..448d8c2bb 100644 --- a/examples/custom_window_frame/Cargo.toml +++ b/examples/custom_window_frame/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/download_image/Cargo.toml b/examples/download_image/Cargo.toml index 0097d9e33..5e4f28e1c 100644 --- a/examples/download_image/Cargo.toml +++ b/examples/download_image/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/download_image/src/main.rs b/examples/download_image/src/main.rs index 2a2c3540e..9a48c8951 100644 --- a/examples/download_image/src/main.rs +++ b/examples/download_image/src/main.rs @@ -58,8 +58,7 @@ fn parse_response(response: ehttp::Response) -> Result { RetainedImage::from_image_bytes(&response.url, &response.bytes) } else { Err(format!( - "Expected image, found content-type {:?}", - content_type + "Expected image, found content-type {content_type:?}" )) } } diff --git a/examples/file_dialog/Cargo.toml b/examples/file_dialog/Cargo.toml index 5447e6815..02045d624 100644 --- a/examples/file_dialog/Cargo.toml +++ b/examples/file_dialog/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml index 9dc377ce9..580fe04e0 100644 --- a/examples/hello_world/Cargo.toml +++ b/examples/hello_world/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/hello_world_par/Cargo.toml b/examples/hello_world_par/Cargo.toml index 9b02345f5..76c1ac88a 100644 --- a/examples/hello_world_par/Cargo.toml +++ b/examples/hello_world_par/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Maxim Osipenko "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/hello_world_par/src/main.rs b/examples/hello_world_par/src/main.rs index b9d03ba6a..8a568cb1f 100644 --- a/examples/hello_world_par/src/main.rs +++ b/examples/hello_world_par/src/main.rs @@ -63,7 +63,7 @@ fn new_worker( ) -> (JoinHandle<()>, mpsc::SyncSender) { let (show_tx, show_rc) = mpsc::sync_channel(0); let handle = std::thread::Builder::new() - .name(format!("EguiPanelWorker {}", thread_nr)) + .name(format!("EguiPanelWorker {thread_nr}")) .spawn(move || { let mut state = ThreadState::new(thread_nr); while let Ok(ctx) = show_rc.recv() { diff --git a/examples/hello_world_simple/Cargo.toml b/examples/hello_world_simple/Cargo.toml index 1c6bcfa40..be399552b 100644 --- a/examples/hello_world_simple/Cargo.toml +++ b/examples/hello_world_simple/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/keyboard_events/Cargo.toml b/examples/keyboard_events/Cargo.toml index 7e544a2e7..39a389f33 100644 --- a/examples/keyboard_events/Cargo.toml +++ b/examples/keyboard_events/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Jose Palazon "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/puffin_profiler/Cargo.toml b/examples/puffin_profiler/Cargo.toml index dbb048fea..90baa1acc 100644 --- a/examples/puffin_profiler/Cargo.toml +++ b/examples/puffin_profiler/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/puffin_profiler/src/main.rs b/examples/puffin_profiler/src/main.rs index 2cfc5e61d..f8d52e91c 100644 --- a/examples/puffin_profiler/src/main.rs +++ b/examples/puffin_profiler/src/main.rs @@ -62,7 +62,7 @@ fn start_puffin_server() { std::mem::forget(puffin_server); } Err(err) => { - eprintln!("Failed to start puffin server: {}", err); + eprintln!("Failed to start puffin server: {err}"); } }; } diff --git a/examples/retained_image/Cargo.toml b/examples/retained_image/Cargo.toml index abbe01fd8..a1df10396 100644 --- a/examples/retained_image/Cargo.toml +++ b/examples/retained_image/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/save_plot/Cargo.toml b/examples/save_plot/Cargo.toml index 83f919d79..2a12692f8 100644 --- a/examples/save_plot/Cargo.toml +++ b/examples/save_plot/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["hacknus "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false [dependencies] diff --git a/examples/save_plot/src/main.rs b/examples/save_plot/src/main.rs index 68c48182a..0d9de35cc 100644 --- a/examples/save_plot/src/main.rs +++ b/examples/save_plot/src/main.rs @@ -14,7 +14,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "My egui App with a plot", options, - Box::new(|_cc| Box::new(MyApp::default())), + Box::new(|_cc| Box::::default()), ) } diff --git a/examples/screenshot/Cargo.toml b/examples/screenshot/Cargo.toml index 692fc3678..3cc5887fb 100644 --- a/examples/screenshot/Cargo.toml +++ b/examples/screenshot/Cargo.toml @@ -7,7 +7,7 @@ authors = [ ] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/serial_windows/Cargo.toml b/examples/serial_windows/Cargo.toml index 089858dd3..39f5a0222 100644 --- a/examples/serial_windows/Cargo.toml +++ b/examples/serial_windows/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/svg/Cargo.toml b/examples/svg/Cargo.toml index fcf56e49f..219efd58c 100644 --- a/examples/svg/Cargo.toml +++ b/examples/svg/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Emil Ernerfeldt "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false diff --git a/examples/user_attention/Cargo.toml b/examples/user_attention/Cargo.toml index 8b4387936..3a7e49a13 100644 --- a/examples/user_attention/Cargo.toml +++ b/examples/user_attention/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["TicClick "] license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.67" publish = false [dependencies] diff --git a/examples/user_attention/src/main.rs b/examples/user_attention/src/main.rs index 4f7e521d2..8134062fd 100644 --- a/examples/user_attention/src/main.rs +++ b/examples/user_attention/src/main.rs @@ -19,7 +19,7 @@ fn main() -> eframe::Result<()> { } fn repr(attention: UserAttentionType) -> String { - format!("{:?}", attention) + format!("{attention:?}") } struct Application { diff --git a/rust-toolchain b/rust-toolchain index 0e334035e..5698c9e2d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -5,6 +5,6 @@ # to the user in the error, instead of "error: invalid channel name '[toolchain]'". [toolchain] -channel = "1.65.0" +channel = "1.67.0" components = [ "rustfmt", "clippy" ] targets = [ "wasm32-unknown-unknown" ] diff --git a/scripts/clippy_wasm/clippy.toml b/scripts/clippy_wasm/clippy.toml index e2ec8be96..436e1fb84 100644 --- a/scripts/clippy_wasm/clippy.toml +++ b/scripts/clippy_wasm/clippy.toml @@ -3,7 +3,7 @@ # We cannot forbid all these methods in the main `clippy.toml` because of # https://github.com/rust-lang/rust-clippy/issues/10406 -msrv = "1.65" +msrv = "1.67" # https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods disallowed-methods = [ From dd5285cccb58fb9f312838120ecb30b5b767dee9 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 11 Aug 2023 15:08:00 +0200 Subject: [PATCH 42/43] Support multi-threaded Wasm (#3236) Replace `atomic_refcell` with `parking_lot` on wasm32. `parking_lot` has had problems running on wasm32 before (https://github.com/emilk/egui/issues/1401) but it works these days. If we have problems again we can always switch to `std::sync::Mutex`. Closes https://github.com/emilk/egui/issues/3102 --- Cargo.lock | 7 --- crates/epaint/Cargo.toml | 6 +-- crates/epaint/src/mutex.rs | 104 +++++++------------------------------ 3 files changed, 19 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37dd41bc6..d7e47d1c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,12 +326,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "atomic_refcell" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d6dc922a2792b006573f60b2648076355daeae5ce9cb59507e5908c9625d31" - [[package]] name = "atspi" version = "0.10.1" @@ -1394,7 +1388,6 @@ version = "0.22.0" dependencies = [ "ab_glyph", "ahash 0.8.3", - "atomic_refcell", "backtrace", "bytemuck", "criterion", diff --git a/crates/epaint/Cargo.toml b/crates/epaint/Cargo.toml index 5a4c74242..747c69b15 100644 --- a/crates/epaint/Cargo.toml +++ b/crates/epaint/Cargo.toml @@ -79,6 +79,7 @@ ahash = { version = "0.8.1", default-features = false, features = [ "std", ] } nohash-hasher = "0.2" +parking_lot = "0.12" # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios. #! ### Optional dependencies bytemuck = { version = "1.7.2", optional = true, features = ["derive"] } @@ -94,11 +95,6 @@ serde = { version = "1", optional = true, features = ["derive", "rc"] } # native: [target.'cfg(not(target_arch = "wasm32"))'.dependencies] backtrace = { version = "0.3", optional = true } -parking_lot = "0.12" # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios. - -# web: -[target.'cfg(target_arch = "wasm32")'.dependencies] -atomic_refcell = "0.1" # Used instead of parking_lot on on wasm. See https://github.com/emilk/egui/issues/1401 [dev-dependencies] diff --git a/crates/epaint/src/mutex.rs b/crates/epaint/src/mutex.rs index ce2bf7c93..050fe9dfa 100644 --- a/crates/epaint/src/mutex.rs +++ b/crates/epaint/src/mutex.rs @@ -1,13 +1,14 @@ -//! Helper module that wraps some Mutex types with different implementations. +//! Helper module that adds extra checks when the `deadlock_detection` feature is turned on. // ---------------------------------------------------------------------------- -#[cfg(not(target_arch = "wasm32"))] -#[cfg(not(debug_assertions))] +#[cfg(not(feature = "deadlock_detection"))] mod mutex_impl { /// Provides interior mutability. /// - /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. + /// This is a thin wrapper around [`parking_lot::Mutex`], except if + /// the feature `deadlock_detection` is turned enabled, in which case + /// extra checks are added to detect deadlocks. #[derive(Default)] pub struct Mutex(parking_lot::Mutex); @@ -27,12 +28,13 @@ mod mutex_impl { } } -#[cfg(not(target_arch = "wasm32"))] -#[cfg(debug_assertions)] +#[cfg(feature = "deadlock_detection")] mod mutex_impl { /// Provides interior mutability. /// - /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. + /// This is a thin wrapper around [`parking_lot::Mutex`], except if + /// the feature `deadlock_detection` is turned enabled, in which case + /// extra checks are added to detect deadlocks. #[derive(Default)] pub struct Mutex(parking_lot::Mutex); @@ -115,7 +117,8 @@ mod mutex_impl { } } -#[cfg(not(target_arch = "wasm32"))] +// ---------------------------------------------------------------------------- + #[cfg(not(feature = "deadlock_detection"))] mod rw_lock_impl { /// The lock you get from [`RwLock::read`]. @@ -126,7 +129,9 @@ mod rw_lock_impl { /// Provides interior mutability. /// - /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. + /// This is a thin wrapper around [`parking_lot::RwLock`], except if + /// the feature `deadlock_detection` is turned enabled, in which case + /// extra checks are added to detect deadlocks. #[derive(Default)] pub struct RwLock(parking_lot::RwLock); @@ -148,7 +153,6 @@ mod rw_lock_impl { } } -#[cfg(not(target_arch = "wasm32"))] #[cfg(feature = "deadlock_detection")] mod rw_lock_impl { use std::{ @@ -246,7 +250,9 @@ mod rw_lock_impl { /// Provides interior mutability. /// - /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. + /// This is a thin wrapper around [`parking_lot::RwLock`], except if + /// the feature `deadlock_detection` is turned enabled, in which case + /// extra checks are added to detect deadlocks. #[derive(Default)] pub struct RwLock { lock: parking_lot::RwLock, @@ -352,80 +358,6 @@ mod rw_lock_impl { // ---------------------------------------------------------------------------- -#[cfg(target_arch = "wasm32")] -mod mutex_impl { - // `atomic_refcell` will panic if multiple threads try to access the same value - - /// Provides interior mutability. - /// - /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. - #[derive(Default)] - pub struct Mutex(atomic_refcell::AtomicRefCell); - - /// The lock you get from [`Mutex`]. - pub use atomic_refcell::AtomicRefMut as MutexGuard; - - impl Mutex { - #[inline(always)] - pub fn new(val: T) -> Self { - Self(atomic_refcell::AtomicRefCell::new(val)) - } - - /// Panics if already locked. - #[inline(always)] - pub fn lock(&self) -> MutexGuard<'_, T> { - self.0.borrow_mut() - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0.into_inner() - } - } -} - -#[cfg(target_arch = "wasm32")] -mod rw_lock_impl { - // `atomic_refcell` will panic if multiple threads try to access the same value - - /// The lock you get from [`RwLock::read`]. - pub use atomic_refcell::AtomicRef as RwLockReadGuard; - - /// The lock you get from [`RwLock::write`]. - pub use atomic_refcell::AtomicRefMut as RwLockWriteGuard; - - /// Provides interior mutability. - /// - /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. - #[derive(Default)] - pub struct RwLock(atomic_refcell::AtomicRefCell); - - impl RwLock { - #[inline(always)] - pub fn new(val: T) -> Self { - Self(atomic_refcell::AtomicRefCell::new(val)) - } - - #[inline(always)] - pub fn read(&self) -> RwLockReadGuard<'_, T> { - self.0.borrow() - } - - /// Panics if already locked. - #[inline(always)] - pub fn write(&self) -> RwLockWriteGuard<'_, T> { - self.0.borrow_mut() - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0.into_inner() - } - } -} - -// ---------------------------------------------------------------------------- - pub use mutex_impl::{Mutex, MutexGuard}; pub use rw_lock_impl::{RwLock, RwLockReadGuard, RwLockWriteGuard}; @@ -469,7 +401,7 @@ mod tests { let other_thread = { let one = Arc::clone(&one); std::thread::spawn(move || { - let _ = one.lock(); + let _lock = one.lock(); }) }; std::thread::sleep(Duration::from_millis(200)); From f78db80840c387f5f5fa6d1108db9791185450cd Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 11 Aug 2023 15:34:16 +0200 Subject: [PATCH 43/43] Update to wasm-bindgen 0.2.87 (#3237) * Update to wasm-bindgen 0.2.87 Required by the new `wgpu` version * Catch unknown arguments to build_demo_web.sh --- .github/workflows/rust.yml | 2 +- Cargo.lock | 20 ++++++++++---------- crates/eframe/Cargo.toml | 2 +- crates/egui_demo_app/Cargo.toml | 2 +- scripts/build_demo_web.sh | 3 ++- scripts/setup_web.sh | 2 +- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cd73fd9d8..b4920b3bf 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -112,7 +112,7 @@ jobs: - name: wasm-bindgen uses: jetli/wasm-bindgen-action@v0.1.0 with: - version: "0.2.86" + version: "0.2.87" - run: ./scripts/wasm_bindgen_check.sh --skip-setup diff --git a/Cargo.lock b/Cargo.lock index d7e47d1c9..ff260433d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3854,9 +3854,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3864,9 +3864,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", @@ -3891,9 +3891,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3901,9 +3901,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", @@ -3914,9 +3914,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wayland-client" diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index 8046394e8..d89f92d35 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -150,7 +150,7 @@ winapi = "0.3.9" bytemuck = "1.7" js-sys = "0.3" percent-encoding = "2.1" -wasm-bindgen = "0.2.86" +wasm-bindgen = "0.2.87" wasm-bindgen-futures = "0.4" web-sys = { version = "0.3.58", features = [ "BinaryType", diff --git a/crates/egui_demo_app/Cargo.toml b/crates/egui_demo_app/Cargo.toml index 79ae48746..2f6b185f2 100644 --- a/crates/egui_demo_app/Cargo.toml +++ b/crates/egui_demo_app/Cargo.toml @@ -65,6 +65,6 @@ env_logger = "0.10" # web: [target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-bindgen = "=0.2.86" +wasm-bindgen = "=0.2.87" wasm-bindgen-futures = "0.4" web-sys = "0.3" diff --git a/scripts/build_demo_web.sh b/scripts/build_demo_web.sh index d77279b7b..37abcffc6 100755 --- a/scripts/build_demo_web.sh +++ b/scripts/build_demo_web.sh @@ -55,7 +55,8 @@ while test $# -gt 0; do ;; *) - break + echo "Unknown option: $1" + exit 1 ;; esac done diff --git a/scripts/setup_web.sh b/scripts/setup_web.sh index f8d3d08a0..53896e989 100755 --- a/scripts/setup_web.sh +++ b/scripts/setup_web.sh @@ -7,4 +7,4 @@ cd "$script_path/.." rustup target add wasm32-unknown-unknown # For generating JS bindings: -cargo install wasm-bindgen-cli --version 0.2.86 +cargo install wasm-bindgen-cli --version 0.2.87