diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ac04f5..6189af21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed 🔧 +* `Arc` has been replaced with `CtxRef` everywhere. * Slight tweak of the default `Style` and font sizes. * `SidePanel::left` and `TopPanel::top` now takes `impl Hash` as first argument. * A `Window` may now cover an existing `CentralPanel`. diff --git a/egui/benches/benchmark.rs b/egui/benches/benchmark.rs index 7f833006..d0cb5e9f 100644 --- a/egui/benches/benchmark.rs +++ b/egui/benches/benchmark.rs @@ -4,7 +4,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { let raw_input = egui::RawInput::default(); { - let mut ctx = egui::Context::new(); + let mut ctx = egui::CtxRef::default(); let mut demo_windows = egui::demos::DemoWindows::default(); c.bench_function("demo_windows_minimal", |b| { @@ -17,7 +17,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { } { - let mut ctx = egui::Context::new(); + let mut ctx = egui::CtxRef::default(); ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything let mut demo_windows = egui::demos::DemoWindows::default(); @@ -31,7 +31,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { } { - let mut ctx = egui::Context::new(); + let mut ctx = egui::CtxRef::default(); ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything let mut demo_windows = egui::demos::DemoWindows::default(); ctx.begin_frame(raw_input.clone()); @@ -44,7 +44,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { } { - let mut ctx = egui::Context::new(); + let mut ctx = egui::CtxRef::default(); ctx.begin_frame(raw_input); egui::CentralPanel::default().show(&ctx, |ui| { c.bench_function("label", |b| { diff --git a/egui/src/app.rs b/egui/src/app.rs index 6ec595e5..1932d4fb 100644 --- a/egui/src/app.rs +++ b/egui/src/app.rs @@ -7,8 +7,6 @@ // TODO: move egui/src/app.rs to own crate, e.g. egui_framework ? -use crate::Context; - /// Implement this trait to write apps that can be compiled both natively using the [`egui_glium`](https://crates.io/crates/egui_glium) crate, /// and deployed as a web site using the [`egui_web`](https://crates.io/crates/egui_web) crate. pub trait App { @@ -24,15 +22,11 @@ pub trait App { /// Called once before the first frame. /// Allows you to do setup code and to call `ctx.set_fonts()`. /// Optional. - fn setup(&mut self, _ctx: &std::sync::Arc) {} + fn setup(&mut self, _ctx: &crate::CtxRef) {} /// Called each time the UI needs repainting, which may be many times per second. /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. - fn ui( - &mut self, - ctx: &std::sync::Arc, - integration_context: &mut IntegrationContext<'_>, - ); + fn ui(&mut self, ctx: &crate::CtxRef, integration_context: &mut IntegrationContext<'_>); /// Called once on shutdown. Allows you to save state. fn on_exit(&mut self, _storage: &mut dyn Storage) {} diff --git a/egui/src/containers/area.rs b/egui/src/containers/area.rs index b43beecf..010c7311 100644 --- a/egui/src/containers/area.rs +++ b/egui/src/containers/area.rs @@ -2,7 +2,7 @@ //! It has no frame or own size. It is potentially movable. //! It is the foundation for windows and popups. -use std::{fmt::Debug, hash::Hash, sync::Arc}; +use std::{fmt::Debug, hash::Hash}; use crate::*; @@ -103,7 +103,7 @@ pub(crate) struct Prepared { } impl Area { - pub(crate) fn begin(self, ctx: &Arc) -> Prepared { + pub(crate) fn begin(self, ctx: &CtxRef) -> Prepared { let Area { id, movable, @@ -131,7 +131,7 @@ impl Area { } } - pub fn show(self, ctx: &Arc, add_contents: impl FnOnce(&mut Ui)) -> Response { + pub fn show(self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui)) -> Response { let prepared = self.begin(ctx); let mut content_ui = prepared.content_ui(ctx); add_contents(&mut content_ui); @@ -148,7 +148,7 @@ impl Prepared { &mut self.state } - pub(crate) fn content_ui(&self, ctx: &Arc) -> Ui { + pub(crate) fn content_ui(&self, ctx: &CtxRef) -> Ui { let max_rect = Rect::from_min_size(self.state.pos, Vec2::infinity()); let clip_rect = max_rect .expand(ctx.style().visuals.clip_rect_margin) @@ -163,7 +163,7 @@ impl Prepared { } #[allow(clippy::needless_pass_by_value)] // intentional to swallow up `content_ui`. - pub(crate) fn end(self, ctx: &Arc, content_ui: Ui) -> Response { + pub(crate) fn end(self, ctx: &CtxRef, content_ui: Ui) -> Response { let Prepared { layer_id, mut state, diff --git a/egui/src/containers/panel.rs b/egui/src/containers/panel.rs index 0cc1d831..639f2f39 100644 --- a/egui/src/containers/panel.rs +++ b/egui/src/containers/panel.rs @@ -3,7 +3,6 @@ //! the only places where you can put you widgets. use crate::*; -use std::sync::Arc; // ---------------------------------------------------------------------------- @@ -27,11 +26,7 @@ impl SidePanel { } impl SidePanel { - pub fn show( - self, - ctx: &Arc, - add_contents: impl FnOnce(&mut Ui) -> R, - ) -> (R, Response) { + pub fn show(self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Response) { let Self { id, max_width } = self; let mut panel_rect = ctx.available_rect(); @@ -80,11 +75,7 @@ impl TopPanel { } impl TopPanel { - pub fn show( - self, - ctx: &Arc, - add_contents: impl FnOnce(&mut Ui) -> R, - ) -> (R, Response) { + pub fn show(self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Response) { let Self { id, max_height } = self; let max_height = max_height.unwrap_or_else(|| ctx.style().spacing.interact_size.y); @@ -122,11 +113,7 @@ impl TopPanel { pub struct CentralPanel {} impl CentralPanel { - pub fn show( - self, - ctx: &Arc, - add_contents: impl FnOnce(&mut Ui) -> R, - ) -> (R, Response) { + pub fn show(self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Response) { let Self {} = self; let panel_rect = ctx.available_rect(); diff --git a/egui/src/containers/popup.rs b/egui/src/containers/popup.rs index 0ea79756..0c3ae02e 100644 --- a/egui/src/containers/popup.rs +++ b/egui/src/containers/popup.rs @@ -1,9 +1,7 @@ -use std::sync::Arc; - use crate::*; /// Show a tooltip at the current mouse position (if any). -pub fn show_tooltip(ctx: &Arc, add_contents: impl FnOnce(&mut Ui)) { +pub fn show_tooltip(ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui)) { let tooltip_rect = ctx.memory().tooltip_rect; let window_pos = if let Some(tooltip_rect) = tooltip_rect { @@ -23,7 +21,7 @@ pub fn show_tooltip(ctx: &Arc, add_contents: impl FnOnce(&mut Ui)) { } /// Show a tooltip at the current mouse position (if any). -pub fn show_tooltip_text(ctx: &Arc, text: impl Into) { +pub fn show_tooltip_text(ctx: &CtxRef, text: impl Into) { show_tooltip(ctx, |ui| { ui.add(crate::widgets::Label::new(text)); }) @@ -31,7 +29,7 @@ pub fn show_tooltip_text(ctx: &Arc, text: impl Into) { /// Show a pop-over window. fn show_popup( - ctx: &Arc, + ctx: &CtxRef, id: Id, window_pos: Pos2, add_contents: impl FnOnce(&mut Ui), diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index 1ba1fedb..04913038 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -1,7 +1,5 @@ // WARNING: the code in here is horrible. It is a behemoth that needs breaking up into simpler parts. -use std::sync::Arc; - use crate::{paint::*, widgets::*, *}; use super::*; @@ -183,13 +181,13 @@ impl<'open> Window<'open> { } impl<'open> Window<'open> { - pub fn show(self, ctx: &Arc, add_contents: impl FnOnce(&mut Ui)) -> Option { + pub fn show(self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui)) -> Option { self.show_impl(ctx, Box::new(add_contents)) } fn show_impl<'c>( self, - ctx: &Arc, + ctx: &CtxRef, add_contents: Box, ) -> Option { let Window { diff --git a/egui/src/context.rs b/egui/src/context.rs index 4eac04db..e7f941cf 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -101,6 +101,236 @@ impl FrameState { // ---------------------------------------------------------------------------- +/// A wrapper around `CtxRef`. +/// This is how you will normally access a [`Context`]. +#[derive(Clone)] +pub struct CtxRef(std::sync::Arc); + +impl std::ops::Deref for CtxRef { + type Target = Context; + + fn deref(&self) -> &Context { + self.0.deref() + } +} + +impl AsRef for CtxRef { + fn as_ref(&self) -> &Context { + self.0.as_ref() + } +} + +impl std::borrow::Borrow for CtxRef { + fn borrow(&self) -> &Context { + self.0.borrow() + } +} + +impl std::cmp::PartialEq for CtxRef { + fn eq(&self, other: &CtxRef) -> bool { + Arc::ptr_eq(&self.0, &other.0) + } +} + +impl Default for CtxRef { + fn default() -> Self { + Self(Arc::new(Context { + // Start with painting an extra frame to compensate for some widgets + // that take two frames before they "settle": + repaint_requests: AtomicU32::new(1), + ..Context::default() + })) + } +} + +impl CtxRef { + /// Call at the start of every frame. + /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. + pub fn begin_frame(&mut self, new_input: RawInput) { + let mut self_: Context = (*self.0).clone(); + self_.begin_frame_mut(new_input); + *self = Self(Arc::new(self_)); + } + + // --------------------------------------------------------------------- + + /// If the given `Id` is not unique, an error will be printed at the given position. + /// Call this for `Id`:s that need interaction or persistence. + pub(crate) fn register_interaction_id(&self, id: Id, new_pos: Pos2) { + let prev_pos = self.memory().used_ids.insert(id, new_pos); + if let Some(prev_pos) = prev_pos { + if prev_pos.distance(new_pos) < 0.1 { + // Likely same Widget being interacted with twice, which is fine. + return; + } + + let show_error = |pos: Pos2, text: String| { + let painter = self.debug_painter(); + let rect = painter.error(pos, text); + if let Some(mouse_pos) = self.input.mouse.pos { + if rect.contains(mouse_pos) { + painter.error( + rect.left_bottom() + vec2(2.0, 4.0), + "ID clashes happens when things like Windows or CollpasingHeaders share names,\n\ + or when things like ScrollAreas and Resize areas aren't given unique id_source:s.", + ); + } + } + }; + + let id_str = id.short_debug_format(); + + if prev_pos.distance(new_pos) < 4.0 { + show_error(new_pos, format!("Double use of ID {}", id_str)); + } else { + show_error(prev_pos, format!("First use of ID {}", id_str)); + show_error(new_pos, format!("Second use of ID {}", id_str)); + } + + // TODO: a tooltip explaining this. + } + } + + // --------------------------------------------------------------------- + + /// Use `ui.interact` instead + pub(crate) fn interact( + &self, + layer_id: LayerId, + clip_rect: Rect, + item_spacing: Vec2, + rect: Rect, + id: Option, + sense: Sense, + ) -> Response { + let interact_rect = rect.expand2((0.5 * item_spacing).min(Vec2::splat(5.0))); // make it easier to click + let hovered = self.contains_mouse(layer_id, clip_rect, interact_rect); + let has_kb_focus = id.map(|id| self.memory().has_kb_focus(id)).unwrap_or(false); + + // If the the focus is lost after the call to interact, + // this will be `false`, so `TextEdit` also sets this manually. + let lost_kb_focus = id + .map(|id| self.memory().lost_kb_focus(id)) + .unwrap_or(false); + + if id.is_none() || sense == Sense::nothing() || !layer_id.allow_interaction() { + // Not interested or allowed input: + return Response { + ctx: self.clone(), + sense, + rect, + hovered, + clicked: false, + double_clicked: false, + active: false, + has_kb_focus, + lost_kb_focus, + }; + } + let id = id.unwrap(); + + self.register_interaction_id(id, rect.min); + + let mut memory = self.memory(); + + memory.interaction.click_interest |= hovered && sense.click; + memory.interaction.drag_interest |= hovered && sense.drag; + + let active = + memory.interaction.click_id == Some(id) || memory.interaction.drag_id == Some(id); + + if self.input.mouse.pressed { + if hovered { + let mut response = Response { + ctx: self.clone(), + sense, + rect, + hovered: true, + clicked: false, + double_clicked: false, + active: false, + has_kb_focus, + lost_kb_focus, + }; + + if sense.click && memory.interaction.click_id.is_none() { + // start of a click + memory.interaction.click_id = Some(id); + response.active = true; + } + + if sense.drag + && (memory.interaction.drag_id.is_none() || memory.interaction.drag_is_window) + { + // start of a drag + memory.interaction.drag_id = Some(id); + memory.interaction.drag_is_window = false; + memory.window_interaction = None; // HACK: stop moving windows (if any) + response.active = true; + } + + response + } else { + // miss + Response { + ctx: self.clone(), + sense, + rect, + hovered, + clicked: false, + double_clicked: false, + active: false, + has_kb_focus, + lost_kb_focus, + } + } + } else if self.input.mouse.released { + let clicked = hovered && active && self.input.mouse.could_be_click; + Response { + ctx: self.clone(), + sense, + rect, + hovered, + clicked, + double_clicked: clicked && self.input.mouse.double_click, + active, + has_kb_focus, + lost_kb_focus, + } + } else if self.input.mouse.down { + Response { + ctx: self.clone(), + sense, + rect, + hovered: hovered && active, + clicked: false, + double_clicked: false, + active, + has_kb_focus, + lost_kb_focus, + } + } else { + Response { + ctx: self.clone(), + sense, + rect, + hovered, + clicked: false, + double_clicked: false, + active, + has_kb_focus, + lost_kb_focus, + } + } + } + + pub fn debug_painter(&self) -> Painter { + Painter::new(self.clone(), LayerId::debug(), self.input.screen_rect()) + } +} + +// ---------------------------------------------------------------------------- + /// Thi is the first thing you need when working with Egui. /// /// Contains the input state, memory, options and output. @@ -149,13 +379,10 @@ impl Clone for Context { } impl Context { - pub fn new() -> Arc { - Arc::new(Self { - // Start with painting an extra frame to compensate for some widgets - // that take two frames before they "settle": - repaint_requests: AtomicU32::new(1), - ..Self::default() - }) + #[allow(clippy::new_ret_no_self)] + #[deprecated = "Use CtxRef::default() instead"] + pub fn new() -> CtxRef { + CtxRef::default() } /// How much space is still available after panels has been added. @@ -289,14 +516,6 @@ impl Context { // --------------------------------------------------------------------- - /// Call at the start of every frame. - /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. - pub fn begin_frame(self: &mut Arc, new_input: RawInput) { - let mut self_: Self = (**self).clone(); - self_.begin_frame_mut(new_input); - *self = Arc::new(self_); - } - fn begin_frame_mut(&mut self, new_raw_input: RawInput) { self.memory().begin_frame(&self.input, &new_raw_input); @@ -385,45 +604,6 @@ impl Context { // --------------------------------------------------------------------- - /// If the given `Id` is not unique, an error will be printed at the given position. - /// Call this for `Id`:s that need interaction or persistence. - pub(crate) fn register_interaction_id(self: &Arc, id: Id, new_pos: Pos2) { - let prev_pos = self.memory().used_ids.insert(id, new_pos); - if let Some(prev_pos) = prev_pos { - if prev_pos.distance(new_pos) < 0.1 { - // Likely same Widget being interacted with twice, which is fine. - return; - } - - let show_error = |pos: Pos2, text: String| { - let painter = self.debug_painter(); - let rect = painter.error(pos, text); - if let Some(mouse_pos) = self.input.mouse.pos { - if rect.contains(mouse_pos) { - painter.error( - rect.left_bottom() + vec2(2.0, 4.0), - "ID clashes happens when things like Windows or CollpasingHeaders share names,\n\ - or when things like ScrollAreas and Resize areas aren't given unique id_source:s.", - ); - } - } - }; - - let id_str = id.short_debug_format(); - - if prev_pos.distance(new_pos) < 4.0 { - show_error(new_pos, format!("Double use of ID {}", id_str)); - } else { - show_error(prev_pos, format!("First use of ID {}", id_str)); - show_error(new_pos, format!("Second use of ID {}", id_str)); - } - - // TODO: a tooltip explaining this. - } - } - - // --------------------------------------------------------------------- - /// Is the mouse over any Egui area? pub fn is_mouse_over_area(&self) -> bool { if let Some(mouse_pos) = self.input.mouse.pos { @@ -477,137 +657,6 @@ impl Context { false } } - - /// Use `ui.interact` instead - pub(crate) fn interact( - self: &Arc, - layer_id: LayerId, - clip_rect: Rect, - item_spacing: Vec2, - rect: Rect, - id: Option, - sense: Sense, - ) -> Response { - let interact_rect = rect.expand2((0.5 * item_spacing).min(Vec2::splat(5.0))); // make it easier to click - let hovered = self.contains_mouse(layer_id, clip_rect, interact_rect); - let has_kb_focus = id.map(|id| self.memory().has_kb_focus(id)).unwrap_or(false); - - // If the the focus is lost after the call to interact, - // this will be `false`, so `TextEdit` also sets this manually. - let lost_kb_focus = id - .map(|id| self.memory().lost_kb_focus(id)) - .unwrap_or(false); - - if id.is_none() || sense == Sense::nothing() || !layer_id.allow_interaction() { - // Not interested or allowed input: - return Response { - ctx: self.clone(), - sense, - rect, - hovered, - clicked: false, - double_clicked: false, - active: false, - has_kb_focus, - lost_kb_focus, - }; - } - let id = id.unwrap(); - - self.register_interaction_id(id, rect.min); - - let mut memory = self.memory(); - - memory.interaction.click_interest |= hovered && sense.click; - memory.interaction.drag_interest |= hovered && sense.drag; - - let active = - memory.interaction.click_id == Some(id) || memory.interaction.drag_id == Some(id); - - if self.input.mouse.pressed { - if hovered { - let mut response = Response { - ctx: self.clone(), - sense, - rect, - hovered: true, - clicked: false, - double_clicked: false, - active: false, - has_kb_focus, - lost_kb_focus, - }; - - if sense.click && memory.interaction.click_id.is_none() { - // start of a click - memory.interaction.click_id = Some(id); - response.active = true; - } - - if sense.drag - && (memory.interaction.drag_id.is_none() || memory.interaction.drag_is_window) - { - // start of a drag - memory.interaction.drag_id = Some(id); - memory.interaction.drag_is_window = false; - memory.window_interaction = None; // HACK: stop moving windows (if any) - response.active = true; - } - - response - } else { - // miss - Response { - ctx: self.clone(), - sense, - rect, - hovered, - clicked: false, - double_clicked: false, - active: false, - has_kb_focus, - lost_kb_focus, - } - } - } else if self.input.mouse.released { - let clicked = hovered && active && self.input.mouse.could_be_click; - Response { - ctx: self.clone(), - sense, - rect, - hovered, - clicked, - double_clicked: clicked && self.input.mouse.double_click, - active, - has_kb_focus, - lost_kb_focus, - } - } else if self.input.mouse.down { - Response { - ctx: self.clone(), - sense, - rect, - hovered: hovered && active, - clicked: false, - double_clicked: false, - active, - has_kb_focus, - lost_kb_focus, - } - } else { - Response { - ctx: self.clone(), - sense, - rect, - hovered, - clicked: false, - double_clicked: false, - active, - has_kb_focus, - lost_kb_focus, - } - } - } } /// ## Animation @@ -633,13 +682,6 @@ impl Context { } } -/// ## Painting -impl Context { - pub fn debug_painter(self: &Arc) -> Painter { - Painter::new(self.clone(), LayerId::debug(), self.input.screen_rect()) - } -} - impl Context { pub fn settings_ui(&self, ui: &mut Ui) { use crate::containers::*; diff --git a/egui/src/demos/app.rs b/egui/src/demos/app.rs index 51a8979d..4299b8cf 100644 --- a/egui/src/demos/app.rs +++ b/egui/src/demos/app.rs @@ -1,5 +1,4 @@ -use crate::{app, demos, util::History, Context, Ui}; -use std::sync::Arc; +use crate::{app, demos, util::History, CtxRef, Ui}; // ---------------------------------------------------------------------------- @@ -282,11 +281,7 @@ impl app::App for DemoApp { "Egui Demo" } - fn ui( - &mut self, - ctx: &Arc, - integration_context: &mut crate::app::IntegrationContext<'_>, - ) { + fn ui(&mut self, ctx: &CtxRef, integration_context: &mut crate::app::IntegrationContext<'_>) { self.frame_history .on_new_frame(ctx.input().time, integration_context.info.cpu_usage); diff --git a/egui/src/demos/dancing_strings.rs b/egui/src/demos/dancing_strings.rs index 19e48302..4e81c09f 100644 --- a/egui/src/demos/dancing_strings.rs +++ b/egui/src/demos/dancing_strings.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use crate::{containers::*, demos::*, *}; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -17,7 +15,7 @@ impl Demo for DancingStrings { "♫ Dancing Strings" } - fn show(&mut self, ctx: &Arc, open: &mut bool) { + fn show(&mut self, ctx: &CtxRef, open: &mut bool) { Window::new(self.name()) .open(open) .default_size(vec2(512.0, 256.0)) diff --git a/egui/src/demos/demo_windows.rs b/egui/src/demos/demo_windows.rs index 67b9d1d3..0f4e4644 100644 --- a/egui/src/demos/demo_windows.rs +++ b/egui/src/demos/demo_windows.rs @@ -1,9 +1,7 @@ -use std::sync::Arc; - use crate::{ app, demos::{self, Demo}, - Context, Resize, ScrollArea, Ui, Window, + CtxRef, Resize, ScrollArea, Ui, Window, }; // ---------------------------------------------------------------------------- @@ -52,7 +50,7 @@ impl Demos { } } - pub fn show(&mut self, ctx: &Arc) { + pub fn show(&mut self, ctx: &CtxRef) { for (ref mut open, demo) in &mut self.demos { demo.show(ctx, open); } @@ -87,7 +85,7 @@ impl DemoWindows { /// `sidebar_ui` can be used to optionally show some things in the sidebar pub fn ui( &mut self, - ctx: &Arc, + ctx: &CtxRef, env: &DemoEnvironment, tex_allocator: &mut Option<&mut dyn app::TextureAllocator>, sidebar_ui: impl FnOnce(&mut Ui), @@ -147,7 +145,7 @@ impl DemoWindows { /// Show the open windows. fn windows( &mut self, - ctx: &Arc, + ctx: &CtxRef, env: &DemoEnvironment, tex_allocator: &mut Option<&mut dyn app::TextureAllocator>, ) { @@ -206,7 +204,7 @@ impl DemoWindows { self.resize_windows(ctx); } - fn resize_windows(&mut self, ctx: &Arc) { + fn resize_windows(&mut self, ctx: &CtxRef) { let open = &mut self.open_windows.resize; Window::new("resizable") diff --git a/egui/src/demos/drag_and_drop.rs b/egui/src/demos/drag_and_drop.rs index d7b4efdd..29d4fd02 100644 --- a/egui/src/demos/drag_and_drop.rs +++ b/egui/src/demos/drag_and_drop.rs @@ -100,7 +100,7 @@ impl Demo for DragAndDropDemo { "✋ Drag and Drop" } - fn show(&mut self, ctx: &std::sync::Arc, open: &mut bool) { + fn show(&mut self, ctx: &CtxRef, open: &mut bool) { Window::new(self.name()) .open(open) .default_size(vec2(256.0, 256.0)) diff --git a/egui/src/demos/font_book.rs b/egui/src/demos/font_book.rs index a9dd5b73..bf2810d8 100644 --- a/egui/src/demos/font_book.rs +++ b/egui/src/demos/font_book.rs @@ -45,7 +45,7 @@ impl demos::Demo for FontBook { "🔤 Font Book" } - fn show(&mut self, ctx: &std::sync::Arc, open: &mut bool) { + fn show(&mut self, ctx: &crate::CtxRef, open: &mut bool) { Window::new(self.name()).open(open).show(ctx, |ui| { use demos::View; self.ui(ui); diff --git a/egui/src/demos/fractal_clock.rs b/egui/src/demos/fractal_clock.rs index 5edb8b2c..f2e14114 100644 --- a/egui/src/demos/fractal_clock.rs +++ b/egui/src/demos/fractal_clock.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use crate::{containers::*, widgets::*, *}; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -31,12 +29,7 @@ impl Default for FractalClock { } impl FractalClock { - pub fn window( - &mut self, - ctx: &Arc, - open: &mut bool, - seconds_since_midnight: Option, - ) { + pub fn window(&mut self, ctx: &CtxRef, open: &mut bool, seconds_since_midnight: Option) { Window::new("🕑 Fractal Clock") .open(open) .default_size(vec2(512.0, 512.0)) diff --git a/egui/src/demos/mod.rs b/egui/src/demos/mod.rs index 544485fd..bf877007 100644 --- a/egui/src/demos/mod.rs +++ b/egui/src/demos/mod.rs @@ -40,7 +40,7 @@ pub trait Demo { fn name(&self) -> &str; /// Show windows, etc - fn show(&mut self, ctx: &std::sync::Arc, open: &mut bool); + fn show(&mut self, ctx: &crate::CtxRef, open: &mut bool); } // ---------------------------------------------------------------------------- diff --git a/egui/src/demos/tests.rs b/egui/src/demos/tests.rs index 45cd60ad..7d163d89 100644 --- a/egui/src/demos/tests.rs +++ b/egui/src/demos/tests.rs @@ -8,7 +8,7 @@ impl demos::Demo for Tests { "📋 Tests" } - fn show(&mut self, ctx: &std::sync::Arc, open: &mut bool) { + fn show(&mut self, ctx: &crate::CtxRef, open: &mut bool) { Window::new(self.name()).open(open).show(ctx, |ui| { use demos::View; self.ui(ui); diff --git a/egui/src/lib.rs b/egui/src/lib.rs index f1387236..77e61ae2 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -8,7 +8,7 @@ //! Use one of `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. For instace: //! //! ``` -//! # let mut ctx = egui::Context::new(); +//! # let mut ctx = egui::CtxRef::default(); //! # ctx.begin_frame(Default::default()); //! egui::CentralPanel::default().show(&ctx, |ui| { //! ui.label("Hello"); @@ -19,7 +19,7 @@ //! To write your own integration for Egui you need to do this: //! //! ``` ignore -//! let mut egui_ctx = egui::Context::new(); +//! let mut egui_ctx = egui::CtxRef::default(); //! //! // Game loop: //! loop { @@ -96,7 +96,7 @@ pub mod widgets; pub use { align::Align, containers::*, - context::Context, + context::{Context, CtxRef}, demos::DemoApp, id::Id, input::*, @@ -129,7 +129,7 @@ pub(crate) fn has_debug_assertions() -> bool { #[test] fn test_egui_e2e() { let mut demo_windows = crate::demos::DemoWindows::default(); - let mut ctx = crate::Context::new(); + let mut ctx = crate::CtxRef::default(); let raw_input = crate::RawInput::default(); const NUM_FRAMES: usize = 5; diff --git a/egui/src/painter.rs b/egui/src/painter.rs index 1c7359d9..8969d70f 100644 --- a/egui/src/painter.rs +++ b/egui/src/painter.rs @@ -1,19 +1,17 @@ -use std::sync::Arc; - use crate::{ align::{anchor_rect, Align, LEFT_TOP}, color, layers::PaintCmdIdx, math::{Pos2, Rect, Vec2}, paint::{Fonts, Galley, PaintCmd, Stroke, TextStyle}, - Context, LayerId, Srgba, + CtxRef, LayerId, Srgba, }; /// Helper to paint shapes and text to a specific region on a specific layer. #[derive(Clone)] pub struct Painter { /// Source of fonts and destination of paint commands - ctx: Arc, + ctx: CtxRef, /// Where we paint layer_id: LayerId, @@ -24,7 +22,7 @@ pub struct Painter { } impl Painter { - pub fn new(ctx: Arc, layer_id: LayerId, clip_rect: Rect) -> Self { + pub fn new(ctx: CtxRef, layer_id: LayerId, clip_rect: Rect) -> Self { Self { ctx, layer_id, @@ -61,7 +59,7 @@ impl Painter { /// ## Accessors etc impl Painter { - pub(crate) fn ctx(&self) -> &Arc { + pub(crate) fn ctx(&self) -> &CtxRef { &self.ctx } diff --git a/egui/src/types.rs b/egui/src/types.rs index 06d224cf..a7ed462f 100644 --- a/egui/src/types.rs +++ b/egui/src/types.rs @@ -1,6 +1,4 @@ -use std::sync::Arc; - -use crate::{math::Rect, Context, Ui}; +use crate::{math::Rect, CtxRef, Ui}; // ---------------------------------------------------------------------------- @@ -57,7 +55,7 @@ impl Default for CursorIcon { pub struct Response { // CONTEXT: /// Used for optionally showing a tooltip - pub ctx: Arc, + pub ctx: CtxRef, // IN: /// The area of the screen we are talking about @@ -143,7 +141,7 @@ impl Response { /// A logical "or" operation. /// For instance `a.union(b).hovered` means "was either a or b hovered?". pub fn union(&self, other: Self) -> Self { - assert!(Arc::ptr_eq(&self.ctx, &other.ctx)); + assert!(self.ctx == other.ctx); Self { ctx: other.ctx, rect: self.rect.union(other.rect), diff --git a/egui/src/ui.rs b/egui/src/ui.rs index 5f0db349..be4da4c2 100644 --- a/egui/src/ui.rs +++ b/egui/src/ui.rs @@ -41,13 +41,7 @@ impl Ui { // ------------------------------------------------------------------------ // Creation: - pub fn new( - ctx: Arc, - layer_id: LayerId, - id: Id, - max_rect: Rect, - clip_rect: Rect, - ) -> Self { + pub fn new(ctx: CtxRef, layer_id: LayerId, id: Id, max_rect: Rect, clip_rect: Rect) -> Self { let style = ctx.style(); let layout = Layout::default(); let region = layout.region_from_max_rect(max_rect); @@ -77,7 +71,7 @@ impl Ui { /// Empty `Ui` for use in tests. pub fn __test() -> Self { - let mut ctx = Context::new(); + let mut ctx = CtxRef::default(); ctx.begin_frame(Default::default()); let id = Id::new("__test"); let layer_id = LayerId::new(Order::Middle, id); @@ -106,7 +100,7 @@ impl Ui { self.style = style.into(); } - pub fn ctx(&self) -> &Arc { + pub fn ctx(&self) -> &CtxRef { self.painter.ctx() } diff --git a/egui_glium/src/backend.rs b/egui_glium/src/backend.rs index 35d00126..20d1805a 100644 --- a/egui_glium/src/backend.rs +++ b/egui_glium/src/backend.rs @@ -72,7 +72,7 @@ pub fn run(mut storage: Box, mut app: Box) -> ! let repaint_signal = std::sync::Arc::new(GliumRepaintSignal(event_loop.create_proxy())); - let mut ctx = egui::Context::new(); + let mut ctx = egui::CtxRef::default(); *ctx.memory() = egui::app::get_value(storage.as_ref(), EGUI_MEMORY_KEY).unwrap_or_default(); app.setup(&ctx); diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index 00a58f81..65070d32 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -8,7 +8,7 @@ pub use egui::{ // ---------------------------------------------------------------------------- pub struct WebBackend { - ctx: Arc, + ctx: egui::CtxRef, painter: webgl::Painter, previous_frame_time: Option, frame_start: Option, @@ -17,7 +17,7 @@ pub struct WebBackend { impl WebBackend { pub fn new(canvas_id: &str) -> Result { - let ctx = egui::Context::new(); + let ctx = egui::CtxRef::default(); load_memory(&ctx); Ok(Self { ctx, diff --git a/example_glium/src/example_app.rs b/example_glium/src/example_app.rs index 4ae55768..7d22b4eb 100644 --- a/example_glium/src/example_app.rs +++ b/example_glium/src/example_app.rs @@ -21,11 +21,7 @@ impl egui::app::App for ExampleApp { /// Called each time the UI needs repainting, which may be many times per second. /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. - fn ui( - &mut self, - ctx: &std::sync::Arc, - integration_context: &mut egui::app::IntegrationContext, - ) { + fn ui(&mut self, ctx: &egui::CtxRef, integration_context: &mut egui::app::IntegrationContext) { let ExampleApp { name, age } = self; // Example used in `README.md`. diff --git a/example_web/src/example_app.rs b/example_web/src/example_app.rs index 1bf7cf96..cd1700aa 100644 --- a/example_web/src/example_app.rs +++ b/example_web/src/example_app.rs @@ -45,11 +45,7 @@ impl egui::app::App for ExampleApp { /// Called each time the UI needs repainting, which may be many times per second. /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. - fn ui( - &mut self, - ctx: &std::sync::Arc, - integration_context: &mut egui::app::IntegrationContext, - ) { + fn ui(&mut self, ctx: &egui::CtxRef, integration_context: &mut egui::app::IntegrationContext) { if let Some(receiver) = &mut self.in_progress { // Are we there yet? if let Ok(result) = receiver.try_recv() {