egui/
context.rs

1#![warn(missing_docs)] // Let's keep `Context` well-documented.
2
3use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration};
4
5use containers::area::AreaState;
6use epaint::{
7    emath::{self, TSTransform},
8    mutex::RwLock,
9    pos2,
10    stats::PaintStats,
11    tessellator,
12    text::{FontInsert, FontPriority, Fonts},
13    util::OrderedFloat,
14    vec2, ClippedPrimitive, ClippedShape, Color32, ImageData, ImageDelta, Pos2, Rect,
15    TessellationOptions, TextureAtlas, TextureId, Vec2,
16};
17
18use crate::{
19    animation_manager::AnimationManager,
20    containers,
21    data::output::PlatformOutput,
22    epaint, hit_test,
23    input_state::{InputState, MultiTouchInfo, PointerEvent},
24    interaction,
25    layers::GraphicLayers,
26    load,
27    load::{Bytes, Loaders, SizedTexture},
28    memory::{Options, Theme},
29    menu,
30    os::OperatingSystem,
31    output::FullOutput,
32    pass_state::PassState,
33    resize, scroll_area,
34    util::IdTypeMap,
35    viewport::ViewportClass,
36    Align2, CursorIcon, DeferredViewportUiCallback, FontDefinitions, Grid, Id, ImmediateViewport,
37    ImmediateViewportRendererCallback, Key, KeyboardShortcut, Label, LayerId, Memory,
38    ModifierNames, NumExt, Order, Painter, RawInput, Response, RichText, ScrollArea, Sense, Style,
39    TextStyle, TextureHandle, TextureOptions, Ui, ViewportBuilder, ViewportCommand, ViewportId,
40    ViewportIdMap, ViewportIdPair, ViewportIdSet, ViewportOutput, Widget, WidgetRect, WidgetText,
41};
42
43#[cfg(feature = "accesskit")]
44use crate::IdMap;
45
46use self::{hit_test::WidgetHits, interaction::InteractionSnapshot};
47
48/// Information given to the backend about when it is time to repaint the ui.
49///
50/// This is given in the callback set by [`Context::set_request_repaint_callback`].
51#[derive(Clone, Copy, Debug)]
52pub struct RequestRepaintInfo {
53    /// This is used to specify what viewport that should repaint.
54    pub viewport_id: ViewportId,
55
56    /// Repaint after this duration. If zero, repaint as soon as possible.
57    pub delay: Duration,
58
59    /// The number of fully completed passes, of the entire lifetime of the [`Context`].
60    ///
61    /// This can be compared to [`Context::cumulative_pass_nr`] to see if we we still
62    /// need another repaint (ui pass / frame), or if one has already happened.
63    pub current_cumulative_pass_nr: u64,
64}
65
66// ----------------------------------------------------------------------------
67
68thread_local! {
69    static IMMEDIATE_VIEWPORT_RENDERER: RefCell<Option<Box<ImmediateViewportRendererCallback>>> = Default::default();
70}
71
72// ----------------------------------------------------------------------------
73
74struct WrappedTextureManager(Arc<RwLock<epaint::TextureManager>>);
75
76impl Default for WrappedTextureManager {
77    fn default() -> Self {
78        let mut tex_mngr = epaint::textures::TextureManager::default();
79
80        // Will be filled in later
81        let font_id = tex_mngr.alloc(
82            "egui_font_texture".into(),
83            epaint::FontImage::new([0, 0]).into(),
84            Default::default(),
85        );
86        assert_eq!(font_id, TextureId::default());
87
88        Self(Arc::new(RwLock::new(tex_mngr)))
89    }
90}
91
92// ----------------------------------------------------------------------------
93
94/// Generic event callback.
95pub type ContextCallback = Arc<dyn Fn(&Context) + Send + Sync>;
96
97#[derive(Clone)]
98struct NamedContextCallback {
99    debug_name: &'static str,
100    callback: ContextCallback,
101}
102
103/// Callbacks that users can register
104#[derive(Clone, Default)]
105struct Plugins {
106    pub on_begin_pass: Vec<NamedContextCallback>,
107    pub on_end_pass: Vec<NamedContextCallback>,
108}
109
110impl Plugins {
111    fn call(ctx: &Context, _cb_name: &str, callbacks: &[NamedContextCallback]) {
112        profiling::scope!("plugins", _cb_name);
113        for NamedContextCallback {
114            debug_name: _name,
115            callback,
116        } in callbacks
117        {
118            profiling::scope!("plugin", _name);
119            (callback)(ctx);
120        }
121    }
122
123    fn on_begin_pass(&self, ctx: &Context) {
124        Self::call(ctx, "on_begin_pass", &self.on_begin_pass);
125    }
126
127    fn on_end_pass(&self, ctx: &Context) {
128        Self::call(ctx, "on_end_pass", &self.on_end_pass);
129    }
130}
131
132// ----------------------------------------------------------------------------
133
134/// Repaint-logic
135impl ContextImpl {
136    /// This is where we update the repaint logic.
137    fn begin_pass_repaint_logic(&mut self, viewport_id: ViewportId) {
138        let viewport = self.viewports.entry(viewport_id).or_default();
139
140        std::mem::swap(
141            &mut viewport.repaint.prev_causes,
142            &mut viewport.repaint.causes,
143        );
144        viewport.repaint.causes.clear();
145
146        viewport.repaint.prev_pass_paint_delay = viewport.repaint.repaint_delay;
147
148        if viewport.repaint.outstanding == 0 {
149            // We are repainting now, so we can wait a while for the next repaint.
150            viewport.repaint.repaint_delay = Duration::MAX;
151        } else {
152            viewport.repaint.repaint_delay = Duration::ZERO;
153            viewport.repaint.outstanding -= 1;
154            if let Some(callback) = &self.request_repaint_callback {
155                (callback)(RequestRepaintInfo {
156                    viewport_id,
157                    delay: Duration::ZERO,
158                    current_cumulative_pass_nr: viewport.repaint.cumulative_pass_nr,
159                });
160            }
161        }
162    }
163
164    fn request_repaint(&mut self, viewport_id: ViewportId, cause: RepaintCause) {
165        self.request_repaint_after(Duration::ZERO, viewport_id, cause);
166    }
167
168    fn request_repaint_after(
169        &mut self,
170        mut delay: Duration,
171        viewport_id: ViewportId,
172        cause: RepaintCause,
173    ) {
174        let viewport = self.viewports.entry(viewport_id).or_default();
175
176        if delay == Duration::ZERO {
177            // Each request results in two repaints, just to give some things time to settle.
178            // This solves some corner-cases of missing repaints on frame-delayed responses.
179            viewport.repaint.outstanding = 1;
180        } else {
181            // For non-zero delays, we only repaint once, because
182            // otherwise we would just schedule an immediate repaint _now_,
183            // which would then clear the delay and repaint again.
184            // Hovering a tooltip is a good example of a case where we want to repaint after a delay.
185        }
186
187        if let Ok(predicted_frame_time) = Duration::try_from_secs_f32(viewport.input.predicted_dt) {
188            // Make it less likely we over-shoot the target:
189            delay = delay.saturating_sub(predicted_frame_time);
190        }
191
192        viewport.repaint.causes.push(cause);
193
194        // We save some CPU time by only calling the callback if we need to.
195        // If the new delay is greater or equal to the previous lowest,
196        // it means we have already called the callback, and don't need to do it again.
197        if delay < viewport.repaint.repaint_delay {
198            viewport.repaint.repaint_delay = delay;
199
200            if let Some(callback) = &self.request_repaint_callback {
201                (callback)(RequestRepaintInfo {
202                    viewport_id,
203                    delay,
204                    current_cumulative_pass_nr: viewport.repaint.cumulative_pass_nr,
205                });
206            }
207        }
208    }
209
210    #[must_use]
211    fn requested_immediate_repaint_prev_pass(&self, viewport_id: &ViewportId) -> bool {
212        self.viewports
213            .get(viewport_id)
214            .map_or(false, |v| v.repaint.requested_immediate_repaint_prev_pass())
215    }
216
217    #[must_use]
218    fn has_requested_repaint(&self, viewport_id: &ViewportId) -> bool {
219        self.viewports.get(viewport_id).map_or(false, |v| {
220            0 < v.repaint.outstanding || v.repaint.repaint_delay < Duration::MAX
221        })
222    }
223}
224
225// ----------------------------------------------------------------------------
226
227/// State stored per viewport.
228///
229/// Mostly for internal use.
230/// Things here may move and change without warning.
231#[derive(Default)]
232pub struct ViewportState {
233    /// The type of viewport.
234    ///
235    /// This will never be [`ViewportClass::Embedded`],
236    /// since those don't result in real viewports.
237    pub class: ViewportClass,
238
239    /// The latest delta
240    pub builder: ViewportBuilder,
241
242    /// The user-code that shows the GUI, used for deferred viewports.
243    ///
244    /// `None` for immediate viewports.
245    pub viewport_ui_cb: Option<Arc<DeferredViewportUiCallback>>,
246
247    pub input: InputState,
248
249    /// State that is collected during a pass and then cleared.
250    pub this_pass: PassState,
251
252    /// The final [`PassState`] from last pass.
253    ///
254    /// Only read from.
255    pub prev_pass: PassState,
256
257    /// Has this viewport been updated this pass?
258    pub used: bool,
259
260    /// State related to repaint scheduling.
261    repaint: ViewportRepaintInfo,
262
263    // ----------------------
264    // Updated at the start of the pass:
265    //
266    /// Which widgets are under the pointer?
267    pub hits: WidgetHits,
268
269    /// What widgets are being interacted with this pass?
270    ///
271    /// Based on the widgets from last pass, and input in this pass.
272    pub interact_widgets: InteractionSnapshot,
273
274    // ----------------------
275    // The output of a pass:
276    //
277    pub graphics: GraphicLayers,
278    // Most of the things in `PlatformOutput` are not actually viewport dependent.
279    pub output: PlatformOutput,
280    pub commands: Vec<ViewportCommand>,
281
282    // ----------------------
283    // Cross-frame statistics:
284    pub num_multipass_in_row: usize,
285}
286
287/// What called [`Context::request_repaint`] or [`Context::request_discard`]?
288#[derive(Clone, PartialEq, Eq, Hash)]
289pub struct RepaintCause {
290    /// What file had the call that requested the repaint?
291    pub file: &'static str,
292
293    /// What line number of the call that requested the repaint?
294    pub line: u32,
295
296    /// Explicit reason; human readable.
297    pub reason: Cow<'static, str>,
298}
299
300impl std::fmt::Debug for RepaintCause {
301    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302        write!(f, "{}:{} {}", self.file, self.line, self.reason)
303    }
304}
305
306impl std::fmt::Display for RepaintCause {
307    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308        write!(f, "{}:{} {}", self.file, self.line, self.reason)
309    }
310}
311
312impl RepaintCause {
313    /// Capture the file and line number of the call site.
314    #[allow(clippy::new_without_default)]
315    #[track_caller]
316    pub fn new() -> Self {
317        let caller = Location::caller();
318        Self {
319            file: caller.file(),
320            line: caller.line(),
321            reason: "".into(),
322        }
323    }
324
325    /// Capture the file and line number of the call site,
326    /// as well as add a reason.
327    #[allow(clippy::new_without_default)]
328    #[track_caller]
329    pub fn new_reason(reason: impl Into<Cow<'static, str>>) -> Self {
330        let caller = Location::caller();
331        Self {
332            file: caller.file(),
333            line: caller.line(),
334            reason: reason.into(),
335        }
336    }
337}
338
339/// Per-viewport state related to repaint scheduling.
340struct ViewportRepaintInfo {
341    /// Monotonically increasing counter.
342    cumulative_pass_nr: u64,
343
344    /// The duration which the backend will poll for new events
345    /// before forcing another egui update, even if there's no new events.
346    ///
347    /// Also used to suppress multiple calls to the repaint callback during the same pass.
348    ///
349    /// This is also returned in [`crate::ViewportOutput`].
350    repaint_delay: Duration,
351
352    /// While positive, keep requesting repaints. Decrement at the start of each pass.
353    outstanding: u8,
354
355    /// What caused repaints during this pass?
356    causes: Vec<RepaintCause>,
357
358    /// What triggered a repaint the previous pass?
359    /// (i.e: why are we updating now?)
360    prev_causes: Vec<RepaintCause>,
361
362    /// What was the output of `repaint_delay` on the previous pass?
363    ///
364    /// If this was zero, we are repainting as quickly as possible
365    /// (as far as we know).
366    prev_pass_paint_delay: Duration,
367}
368
369impl Default for ViewportRepaintInfo {
370    fn default() -> Self {
371        Self {
372            cumulative_pass_nr: 0,
373
374            // We haven't scheduled a repaint yet.
375            repaint_delay: Duration::MAX,
376
377            // Let's run a couple of frames at the start, because why not.
378            outstanding: 1,
379
380            causes: Default::default(),
381            prev_causes: Default::default(),
382
383            prev_pass_paint_delay: Duration::MAX,
384        }
385    }
386}
387
388impl ViewportRepaintInfo {
389    pub fn requested_immediate_repaint_prev_pass(&self) -> bool {
390        self.prev_pass_paint_delay == Duration::ZERO
391    }
392}
393
394// ----------------------------------------------------------------------------
395
396#[derive(Default)]
397struct ContextImpl {
398    /// Since we could have multiple viewports across multiple monitors with
399    /// different `pixels_per_point`, we need a `Fonts` instance for each unique
400    /// `pixels_per_point`.
401    /// This is because the `Fonts` depend on `pixels_per_point` for the font atlas
402    /// as well as kerning, font sizes, etc.
403    fonts: std::collections::BTreeMap<OrderedFloat<f32>, Fonts>,
404    font_definitions: FontDefinitions,
405
406    memory: Memory,
407    animation_manager: AnimationManager,
408
409    plugins: Plugins,
410
411    /// All viewports share the same texture manager and texture namespace.
412    ///
413    /// In all viewports, [`TextureId::default`] is special, and points to the font atlas.
414    /// The font-atlas texture _may_ be different across viewports, as they may have different
415    /// `pixels_per_point`, so we do special book-keeping for that.
416    /// See <https://github.com/emilk/egui/issues/3664>.
417    tex_manager: WrappedTextureManager,
418
419    /// Set during the pass, becomes active at the start of the next pass.
420    new_zoom_factor: Option<f32>,
421
422    os: OperatingSystem,
423
424    /// How deeply nested are we?
425    viewport_stack: Vec<ViewportIdPair>,
426
427    /// What is the last viewport rendered?
428    last_viewport: ViewportId,
429
430    paint_stats: PaintStats,
431
432    request_repaint_callback: Option<Box<dyn Fn(RequestRepaintInfo) + Send + Sync>>,
433
434    viewport_parents: ViewportIdMap<ViewportId>,
435    viewports: ViewportIdMap<ViewportState>,
436
437    embed_viewports: bool,
438
439    #[cfg(feature = "accesskit")]
440    is_accesskit_enabled: bool,
441
442    loaders: Arc<Loaders>,
443}
444
445impl ContextImpl {
446    fn begin_pass(&mut self, mut new_raw_input: RawInput) {
447        let viewport_id = new_raw_input.viewport_id;
448        let parent_id = new_raw_input
449            .viewports
450            .get(&viewport_id)
451            .and_then(|v| v.parent)
452            .unwrap_or_default();
453        let ids = ViewportIdPair::from_self_and_parent(viewport_id, parent_id);
454
455        let is_outermost_viewport = self.viewport_stack.is_empty(); // not necessarily root, just outermost immediate viewport
456        self.viewport_stack.push(ids);
457
458        self.begin_pass_repaint_logic(viewport_id);
459
460        let viewport = self.viewports.entry(viewport_id).or_default();
461
462        if is_outermost_viewport {
463            if let Some(new_zoom_factor) = self.new_zoom_factor.take() {
464                let ratio = self.memory.options.zoom_factor / new_zoom_factor;
465                self.memory.options.zoom_factor = new_zoom_factor;
466
467                let input = &viewport.input;
468                // This is a bit hacky, but is required to avoid jitter:
469                let mut rect = input.screen_rect;
470                rect.min = (ratio * rect.min.to_vec2()).to_pos2();
471                rect.max = (ratio * rect.max.to_vec2()).to_pos2();
472                new_raw_input.screen_rect = Some(rect);
473                // We should really scale everything else in the input too,
474                // but the `screen_rect` is the most important part.
475            }
476        }
477        let native_pixels_per_point = new_raw_input
478            .viewport()
479            .native_pixels_per_point
480            .unwrap_or(1.0);
481        let pixels_per_point = self.memory.options.zoom_factor * native_pixels_per_point;
482
483        let all_viewport_ids: ViewportIdSet = self.all_viewport_ids();
484
485        let viewport = self.viewports.entry(self.viewport_id()).or_default();
486
487        self.memory.begin_pass(&new_raw_input, &all_viewport_ids);
488
489        viewport.input = std::mem::take(&mut viewport.input).begin_pass(
490            new_raw_input,
491            viewport.repaint.requested_immediate_repaint_prev_pass(),
492            pixels_per_point,
493            &self.memory.options,
494        );
495
496        let screen_rect = viewport.input.screen_rect;
497
498        viewport.this_pass.begin_pass(screen_rect);
499
500        {
501            let mut layers: Vec<LayerId> = viewport.prev_pass.widgets.layer_ids().collect();
502            layers.sort_by(|&a, &b| self.memory.areas().compare_order(a, b));
503
504            viewport.hits = if let Some(pos) = viewport.input.pointer.interact_pos() {
505                let interact_radius = self.memory.options.style().interaction.interact_radius;
506
507                crate::hit_test::hit_test(
508                    &viewport.prev_pass.widgets,
509                    &layers,
510                    &self.memory.to_global,
511                    pos,
512                    interact_radius,
513                )
514            } else {
515                WidgetHits::default()
516            };
517
518            viewport.interact_widgets = crate::interaction::interact(
519                &viewport.interact_widgets,
520                &viewport.prev_pass.widgets,
521                &viewport.hits,
522                &viewport.input,
523                self.memory.interaction_mut(),
524            );
525        }
526
527        // Ensure we register the background area so panels and background ui can catch clicks:
528        self.memory.areas_mut().set_state(
529            LayerId::background(),
530            AreaState {
531                pivot_pos: Some(screen_rect.left_top()),
532                pivot: Align2::LEFT_TOP,
533                size: Some(screen_rect.size()),
534                interactable: true,
535                last_became_visible_at: None,
536            },
537        );
538
539        #[cfg(feature = "accesskit")]
540        if self.is_accesskit_enabled {
541            profiling::scope!("accesskit");
542            use crate::pass_state::AccessKitPassState;
543            let id = crate::accesskit_root_id();
544            let mut root_node = accesskit::Node::new(accesskit::Role::Window);
545            let pixels_per_point = viewport.input.pixels_per_point();
546            root_node.set_transform(accesskit::Affine::scale(pixels_per_point.into()));
547            let mut nodes = IdMap::default();
548            nodes.insert(id, root_node);
549            viewport.this_pass.accesskit_state = Some(AccessKitPassState {
550                nodes,
551                parent_stack: vec![id],
552            });
553        }
554
555        self.update_fonts_mut();
556    }
557
558    /// Load fonts unless already loaded.
559    fn update_fonts_mut(&mut self) {
560        profiling::function_scope!();
561        let input = &self.viewport().input;
562        let pixels_per_point = input.pixels_per_point();
563        let max_texture_side = input.max_texture_side;
564
565        if let Some(font_definitions) = self.memory.new_font_definitions.take() {
566            // New font definition loaded, so we need to reload all fonts.
567            self.fonts.clear();
568            self.font_definitions = font_definitions;
569            #[cfg(feature = "log")]
570            log::trace!("Loading new font definitions");
571        }
572
573        if !self.memory.add_fonts.is_empty() {
574            let fonts = self.memory.add_fonts.drain(..);
575            for font in fonts {
576                self.fonts.clear(); // recreate all the fonts
577                for family in font.families {
578                    let fam = self
579                        .font_definitions
580                        .families
581                        .entry(family.family)
582                        .or_default();
583                    match family.priority {
584                        FontPriority::Highest => fam.insert(0, font.name.clone()),
585                        FontPriority::Lowest => fam.push(font.name.clone()),
586                    }
587                }
588                self.font_definitions
589                    .font_data
590                    .insert(font.name, Arc::new(font.data));
591            }
592
593            #[cfg(feature = "log")]
594            log::trace!("Adding new fonts");
595        }
596
597        let mut is_new = false;
598
599        let fonts = self
600            .fonts
601            .entry(pixels_per_point.into())
602            .or_insert_with(|| {
603                #[cfg(feature = "log")]
604                log::trace!("Creating new Fonts for pixels_per_point={pixels_per_point}");
605
606                is_new = true;
607                profiling::scope!("Fonts::new");
608                Fonts::new(
609                    pixels_per_point,
610                    max_texture_side,
611                    self.font_definitions.clone(),
612                )
613            });
614
615        {
616            profiling::scope!("Fonts::begin_pass");
617            fonts.begin_pass(pixels_per_point, max_texture_side);
618        }
619
620        if is_new && self.memory.options.preload_font_glyphs {
621            profiling::scope!("preload_font_glyphs");
622            // Preload the most common characters for the most common fonts.
623            // This is not very important to do, but may save a few GPU operations.
624            for font_id in self.memory.options.style().text_styles.values() {
625                fonts.lock().fonts.font(font_id).preload_common_characters();
626            }
627        }
628    }
629
630    #[cfg(feature = "accesskit")]
631    fn accesskit_node_builder(&mut self, id: Id) -> &mut accesskit::Node {
632        let state = self.viewport().this_pass.accesskit_state.as_mut().unwrap();
633        let builders = &mut state.nodes;
634        if let std::collections::hash_map::Entry::Vacant(entry) = builders.entry(id) {
635            entry.insert(Default::default());
636            let parent_id = state.parent_stack.last().unwrap();
637            let parent_builder = builders.get_mut(parent_id).unwrap();
638            parent_builder.push_child(id.accesskit_id());
639        }
640        builders.get_mut(&id).unwrap()
641    }
642
643    fn pixels_per_point(&mut self) -> f32 {
644        self.viewport().input.pixels_per_point
645    }
646
647    /// Return the `ViewportId` of the current viewport.
648    ///
649    /// For the root viewport this will return [`ViewportId::ROOT`].
650    pub(crate) fn viewport_id(&self) -> ViewportId {
651        self.viewport_stack.last().copied().unwrap_or_default().this
652    }
653
654    /// Return the `ViewportId` of his parent.
655    ///
656    /// For the root viewport this will return [`ViewportId::ROOT`].
657    pub(crate) fn parent_viewport_id(&self) -> ViewportId {
658        let viewport_id = self.viewport_id();
659        *self
660            .viewport_parents
661            .get(&viewport_id)
662            .unwrap_or(&ViewportId::ROOT)
663    }
664
665    fn all_viewport_ids(&self) -> ViewportIdSet {
666        self.viewports
667            .keys()
668            .copied()
669            .chain([ViewportId::ROOT])
670            .collect()
671    }
672
673    /// The current active viewport
674    pub(crate) fn viewport(&mut self) -> &mut ViewportState {
675        self.viewports.entry(self.viewport_id()).or_default()
676    }
677
678    fn viewport_for(&mut self, viewport_id: ViewportId) -> &mut ViewportState {
679        self.viewports.entry(viewport_id).or_default()
680    }
681}
682
683// ----------------------------------------------------------------------------
684
685/// Your handle to egui.
686///
687/// This is the first thing you need when working with egui.
688/// Contains the [`InputState`], [`Memory`], [`PlatformOutput`], and more.
689///
690/// [`Context`] is cheap to clone, and any clones refers to the same mutable data
691/// ([`Context`] uses refcounting internally).
692///
693/// ## Locking
694/// All methods are marked `&self`; [`Context`] has interior mutability protected by an [`RwLock`].
695///
696/// To access parts of a `Context` you need to use some of the helper functions that take closures:
697///
698/// ```
699/// # let ctx = egui::Context::default();
700/// if ctx.input(|i| i.key_pressed(egui::Key::A)) {
701///     ctx.output_mut(|o| o.copied_text = "Hello!".to_string());
702/// }
703/// ```
704///
705/// Within such a closure you may NOT recursively lock the same [`Context`], as that can lead to a deadlock.
706/// Therefore it is important that any lock of [`Context`] is short-lived.
707///
708/// These are effectively transactional accesses.
709///
710/// [`Ui`] has many of the same accessor functions, and the same applies there.
711///
712/// ## Example:
713///
714/// ``` no_run
715/// # fn handle_platform_output(_: egui::PlatformOutput) {}
716/// # fn paint(textures_delta: egui::TexturesDelta, _: Vec<egui::ClippedPrimitive>) {}
717/// let mut ctx = egui::Context::default();
718///
719/// // Game loop:
720/// loop {
721///     let raw_input = egui::RawInput::default();
722///     let full_output = ctx.run(raw_input, |ctx| {
723///         egui::CentralPanel::default().show(&ctx, |ui| {
724///             ui.label("Hello world!");
725///             if ui.button("Click me").clicked() {
726///                 // take some action here
727///             }
728///         });
729///     });
730///     handle_platform_output(full_output.platform_output);
731///     let clipped_primitives = ctx.tessellate(full_output.shapes, full_output.pixels_per_point);
732///     paint(full_output.textures_delta, clipped_primitives);
733/// }
734/// ```
735#[derive(Clone)]
736pub struct Context(Arc<RwLock<ContextImpl>>);
737
738impl std::fmt::Debug for Context {
739    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
740        f.debug_struct("Context").finish_non_exhaustive()
741    }
742}
743
744impl std::cmp::PartialEq for Context {
745    fn eq(&self, other: &Self) -> bool {
746        Arc::ptr_eq(&self.0, &other.0)
747    }
748}
749
750impl Default for Context {
751    fn default() -> Self {
752        let ctx_impl = ContextImpl {
753            embed_viewports: true,
754            ..Default::default()
755        };
756        let ctx = Self(Arc::new(RwLock::new(ctx_impl)));
757
758        // Register built-in plugins:
759        crate::debug_text::register(&ctx);
760        crate::text_selection::LabelSelectionState::register(&ctx);
761        crate::DragAndDrop::register(&ctx);
762
763        ctx
764    }
765}
766
767impl Context {
768    /// Do read-only (shared access) transaction on Context
769    fn read<R>(&self, reader: impl FnOnce(&ContextImpl) -> R) -> R {
770        reader(&self.0.read())
771    }
772
773    /// Do read-write (exclusive access) transaction on Context
774    fn write<R>(&self, writer: impl FnOnce(&mut ContextImpl) -> R) -> R {
775        writer(&mut self.0.write())
776    }
777
778    /// Run the ui code for one 1.
779    ///
780    /// At most [`Options::max_passes`] calls will be issued to `run_ui`,
781    /// and only on the rare occasion that [`Context::request_discard`] is called.
782    /// Usually, it `run_ui` will only be called once.
783    ///
784    /// Put your widgets into a [`crate::SidePanel`], [`crate::TopBottomPanel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`].
785    ///
786    /// Instead of calling `run`, you can alternatively use [`Self::begin_pass`] and [`Context::end_pass`].
787    ///
788    /// ```
789    /// // One egui context that you keep reusing:
790    /// let mut ctx = egui::Context::default();
791    ///
792    /// // Each frame:
793    /// let input = egui::RawInput::default();
794    /// let full_output = ctx.run(input, |ctx| {
795    ///     egui::CentralPanel::default().show(&ctx, |ui| {
796    ///         ui.label("Hello egui!");
797    ///     });
798    /// });
799    /// // handle full_output
800    /// ```
801    #[must_use]
802    pub fn run(&self, mut new_input: RawInput, mut run_ui: impl FnMut(&Self)) -> FullOutput {
803        profiling::function_scope!();
804        let viewport_id = new_input.viewport_id;
805        let max_passes = self.write(|ctx| ctx.memory.options.max_passes.get());
806
807        let mut output = FullOutput::default();
808        debug_assert_eq!(output.platform_output.num_completed_passes, 0);
809
810        loop {
811            profiling::scope!(
812                "pass",
813                output
814                    .platform_output
815                    .num_completed_passes
816                    .to_string()
817                    .as_str()
818            );
819
820            // We must move the `num_passes` (back) to the viewport output so that [`Self::will_discard`]
821            // has access to the latest pass count.
822            self.write(|ctx| {
823                let viewport = ctx.viewport_for(viewport_id);
824                viewport.output.num_completed_passes =
825                    std::mem::take(&mut output.platform_output.num_completed_passes);
826                output.platform_output.request_discard_reasons.clear();
827            });
828
829            self.begin_pass(new_input.take());
830            run_ui(self);
831            output.append(self.end_pass());
832            debug_assert!(0 < output.platform_output.num_completed_passes);
833
834            if !output.platform_output.requested_discard() {
835                break; // no need for another pass
836            }
837
838            if max_passes <= output.platform_output.num_completed_passes {
839                #[cfg(feature = "log")]
840                log::debug!("Ignoring call request_discard, because max_passes={max_passes}. Requested from {:?}", output.platform_output.request_discard_reasons);
841
842                break;
843            }
844        }
845
846        self.write(|ctx| {
847            let did_multipass = 1 < output.platform_output.num_completed_passes;
848            let viewport = ctx.viewport_for(viewport_id);
849            if did_multipass {
850                viewport.num_multipass_in_row += 1;
851            } else {
852                viewport.num_multipass_in_row = 0;
853            }
854        });
855
856        output
857    }
858
859    /// An alternative to calling [`Self::run`].
860    ///
861    /// It is usually better to use [`Self::run`], because
862    /// `run` supports multi-pass layout using [`Self::request_discard`].
863    ///
864    /// ```
865    /// // One egui context that you keep reusing:
866    /// let mut ctx = egui::Context::default();
867    ///
868    /// // Each frame:
869    /// let input = egui::RawInput::default();
870    /// ctx.begin_pass(input);
871    ///
872    /// egui::CentralPanel::default().show(&ctx, |ui| {
873    ///     ui.label("Hello egui!");
874    /// });
875    ///
876    /// let full_output = ctx.end_pass();
877    /// // handle full_output
878    /// ```
879    pub fn begin_pass(&self, new_input: RawInput) {
880        profiling::function_scope!();
881
882        self.write(|ctx| ctx.begin_pass(new_input));
883
884        // Plugins run just after the pass starts:
885        self.read(|ctx| ctx.plugins.clone()).on_begin_pass(self);
886    }
887
888    /// See [`Self::begin_pass`].
889    #[deprecated = "Renamed begin_pass"]
890    pub fn begin_frame(&self, new_input: RawInput) {
891        self.begin_pass(new_input);
892    }
893}
894
895/// ## Borrows parts of [`Context`]
896/// These functions all lock the [`Context`].
897/// Please see the documentation of [`Context`] for how locking works!
898impl Context {
899    /// Read-only access to [`InputState`].
900    ///
901    /// Note that this locks the [`Context`].
902    ///
903    /// ```
904    /// # let mut ctx = egui::Context::default();
905    /// ctx.input(|i| {
906    ///     // ⚠️ Using `ctx` (even from other `Arc` reference) again here will lead to a deadlock!
907    /// });
908    ///
909    /// if let Some(pos) = ctx.input(|i| i.pointer.hover_pos()) {
910    ///     // This is fine!
911    /// }
912    /// ```
913    #[inline]
914    pub fn input<R>(&self, reader: impl FnOnce(&InputState) -> R) -> R {
915        self.write(move |ctx| reader(&ctx.viewport().input))
916    }
917
918    /// This will create a `InputState::default()` if there is no input state for that viewport
919    #[inline]
920    pub fn input_for<R>(&self, id: ViewportId, reader: impl FnOnce(&InputState) -> R) -> R {
921        self.write(move |ctx| reader(&ctx.viewport_for(id).input))
922    }
923
924    /// Read-write access to [`InputState`].
925    #[inline]
926    pub fn input_mut<R>(&self, writer: impl FnOnce(&mut InputState) -> R) -> R {
927        self.input_mut_for(self.viewport_id(), writer)
928    }
929
930    /// This will create a `InputState::default()` if there is no input state for that viewport
931    #[inline]
932    pub fn input_mut_for<R>(&self, id: ViewportId, writer: impl FnOnce(&mut InputState) -> R) -> R {
933        self.write(move |ctx| writer(&mut ctx.viewport_for(id).input))
934    }
935
936    /// Read-only access to [`Memory`].
937    #[inline]
938    pub fn memory<R>(&self, reader: impl FnOnce(&Memory) -> R) -> R {
939        self.read(move |ctx| reader(&ctx.memory))
940    }
941
942    /// Read-write access to [`Memory`].
943    #[inline]
944    pub fn memory_mut<R>(&self, writer: impl FnOnce(&mut Memory) -> R) -> R {
945        self.write(move |ctx| writer(&mut ctx.memory))
946    }
947
948    /// Read-only access to [`IdTypeMap`], which stores superficial widget state.
949    #[inline]
950    pub fn data<R>(&self, reader: impl FnOnce(&IdTypeMap) -> R) -> R {
951        self.read(move |ctx| reader(&ctx.memory.data))
952    }
953
954    /// Read-write access to [`IdTypeMap`], which stores superficial widget state.
955    #[inline]
956    pub fn data_mut<R>(&self, writer: impl FnOnce(&mut IdTypeMap) -> R) -> R {
957        self.write(move |ctx| writer(&mut ctx.memory.data))
958    }
959
960    /// Read-write access to [`GraphicLayers`], where painted [`crate::Shape`]s are written to.
961    #[inline]
962    pub fn graphics_mut<R>(&self, writer: impl FnOnce(&mut GraphicLayers) -> R) -> R {
963        self.write(move |ctx| writer(&mut ctx.viewport().graphics))
964    }
965
966    /// Read-only access to [`GraphicLayers`], where painted [`crate::Shape`]s are written to.
967    #[inline]
968    pub fn graphics<R>(&self, reader: impl FnOnce(&GraphicLayers) -> R) -> R {
969        self.write(move |ctx| reader(&ctx.viewport().graphics))
970    }
971
972    /// Read-only access to [`PlatformOutput`].
973    ///
974    /// This is what egui outputs each pass and frame.
975    ///
976    /// ```
977    /// # let mut ctx = egui::Context::default();
978    /// ctx.output_mut(|o| o.cursor_icon = egui::CursorIcon::Progress);
979    /// ```
980    #[inline]
981    pub fn output<R>(&self, reader: impl FnOnce(&PlatformOutput) -> R) -> R {
982        self.write(move |ctx| reader(&ctx.viewport().output))
983    }
984
985    /// Read-write access to [`PlatformOutput`].
986    #[inline]
987    pub fn output_mut<R>(&self, writer: impl FnOnce(&mut PlatformOutput) -> R) -> R {
988        self.write(move |ctx| writer(&mut ctx.viewport().output))
989    }
990
991    /// Read-only access to [`PassState`].
992    ///
993    /// This is only valid during the call to [`Self::run`] (between [`Self::begin_pass`] and [`Self::end_pass`]).
994    #[inline]
995    pub(crate) fn pass_state<R>(&self, reader: impl FnOnce(&PassState) -> R) -> R {
996        self.write(move |ctx| reader(&ctx.viewport().this_pass))
997    }
998
999    /// Read-write access to [`PassState`].
1000    ///
1001    /// This is only valid during the call to [`Self::run`] (between [`Self::begin_pass`] and [`Self::end_pass`]).
1002    #[inline]
1003    pub(crate) fn pass_state_mut<R>(&self, writer: impl FnOnce(&mut PassState) -> R) -> R {
1004        self.write(move |ctx| writer(&mut ctx.viewport().this_pass))
1005    }
1006
1007    /// Read-only access to the [`PassState`] from the previous pass.
1008    ///
1009    /// This is swapped at the end of each pass.
1010    #[inline]
1011    pub(crate) fn prev_pass_state<R>(&self, reader: impl FnOnce(&PassState) -> R) -> R {
1012        self.write(move |ctx| reader(&ctx.viewport().prev_pass))
1013    }
1014
1015    /// Read-only access to [`Fonts`].
1016    ///
1017    /// Not valid until first call to [`Context::run()`].
1018    /// That's because since we don't know the proper `pixels_per_point` until then.
1019    #[inline]
1020    pub fn fonts<R>(&self, reader: impl FnOnce(&Fonts) -> R) -> R {
1021        self.write(move |ctx| {
1022            let pixels_per_point = ctx.pixels_per_point();
1023            reader(
1024                ctx.fonts
1025                    .get(&pixels_per_point.into())
1026                    .expect("No fonts available until first call to Context::run()"),
1027            )
1028        })
1029    }
1030
1031    /// Read-only access to [`Options`].
1032    #[inline]
1033    pub fn options<R>(&self, reader: impl FnOnce(&Options) -> R) -> R {
1034        self.read(move |ctx| reader(&ctx.memory.options))
1035    }
1036
1037    /// Read-write access to [`Options`].
1038    #[inline]
1039    pub fn options_mut<R>(&self, writer: impl FnOnce(&mut Options) -> R) -> R {
1040        self.write(move |ctx| writer(&mut ctx.memory.options))
1041    }
1042
1043    /// Read-only access to [`TessellationOptions`].
1044    #[inline]
1045    pub fn tessellation_options<R>(&self, reader: impl FnOnce(&TessellationOptions) -> R) -> R {
1046        self.read(move |ctx| reader(&ctx.memory.options.tessellation_options))
1047    }
1048
1049    /// Read-write access to [`TessellationOptions`].
1050    #[inline]
1051    pub fn tessellation_options_mut<R>(
1052        &self,
1053        writer: impl FnOnce(&mut TessellationOptions) -> R,
1054    ) -> R {
1055        self.write(move |ctx| writer(&mut ctx.memory.options.tessellation_options))
1056    }
1057
1058    /// If the given [`Id`] has been used previously the same pass at different position,
1059    /// then an error will be printed on screen.
1060    ///
1061    /// This function is already called for all widgets that do any interaction,
1062    /// but you can call this from widgets that store state but that does not interact.
1063    ///
1064    /// The given [`Rect`] should be approximately where the widget will be.
1065    /// The most important thing is that [`Rect::min`] is approximately correct,
1066    /// because that's where the warning will be painted. If you don't know what size to pick, just pick [`Vec2::ZERO`].
1067    pub fn check_for_id_clash(&self, id: Id, new_rect: Rect, what: &str) {
1068        let prev_rect = self.pass_state_mut(move |state| state.used_ids.insert(id, new_rect));
1069
1070        if !self.options(|opt| opt.warn_on_id_clash) {
1071            return;
1072        }
1073
1074        let Some(prev_rect) = prev_rect else { return };
1075
1076        // It is ok to reuse the same ID for e.g. a frame around a widget,
1077        // or to check for interaction with the same widget twice:
1078        let is_same_rect = prev_rect.expand(0.1).contains_rect(new_rect)
1079            || new_rect.expand(0.1).contains_rect(prev_rect);
1080        if is_same_rect {
1081            return;
1082        }
1083
1084        let show_error = |widget_rect: Rect, text: String| {
1085            let screen_rect = self.screen_rect();
1086
1087            let text = format!("🔥 {text}");
1088            let color = self.style().visuals.error_fg_color;
1089            let painter = self.debug_painter();
1090            painter.rect_stroke(widget_rect, 0.0, (1.0, color));
1091
1092            let below = widget_rect.bottom() + 32.0 < screen_rect.bottom();
1093
1094            let text_rect = if below {
1095                painter.debug_text(
1096                    widget_rect.left_bottom() + vec2(0.0, 2.0),
1097                    Align2::LEFT_TOP,
1098                    color,
1099                    text,
1100                )
1101            } else {
1102                painter.debug_text(
1103                    widget_rect.left_top() - vec2(0.0, 2.0),
1104                    Align2::LEFT_BOTTOM,
1105                    color,
1106                    text,
1107                )
1108            };
1109
1110            if let Some(pointer_pos) = self.pointer_hover_pos() {
1111                if text_rect.contains(pointer_pos) {
1112                    let tooltip_pos = if below {
1113                        text_rect.left_bottom() + vec2(2.0, 4.0)
1114                    } else {
1115                        text_rect.left_top() + vec2(2.0, -4.0)
1116                    };
1117
1118                    painter.error(
1119                        tooltip_pos,
1120                        format!("Widget is {} this text.\n\n\
1121                             ID clashes happens when things like Windows or CollapsingHeaders share names,\n\
1122                             or when things like Plot and Grid:s aren't given unique id_salt:s.\n\n\
1123                             Sometimes the solution is to use ui.push_id.",
1124                         if below { "above" } else { "below" })
1125                    );
1126                }
1127            }
1128        };
1129
1130        let id_str = id.short_debug_format();
1131
1132        if prev_rect.min.distance(new_rect.min) < 4.0 {
1133            show_error(new_rect, format!("Double use of {what} ID {id_str}"));
1134        } else {
1135            show_error(prev_rect, format!("First use of {what} ID {id_str}"));
1136            show_error(new_rect, format!("Second use of {what} ID {id_str}"));
1137        }
1138    }
1139
1140    // ---------------------------------------------------------------------
1141
1142    /// Create a widget and check for interaction.
1143    ///
1144    /// If this is not called, the widget doesn't exist.
1145    ///
1146    /// You should use [`Ui::interact`] instead.
1147    ///
1148    /// If the widget already exists, its state (sense, Rect, etc) will be updated.
1149    ///
1150    /// `allow_focus` should usually be true, unless you call this function multiple times with the
1151    /// same widget, then `allow_focus` should only be true once (like in [`Ui::new`] (true) and [`Ui::remember_min_rect`] (false)).
1152    #[allow(clippy::too_many_arguments)]
1153    pub(crate) fn create_widget(&self, w: WidgetRect, allow_focus: bool) -> Response {
1154        let interested_in_focus =
1155            w.enabled && w.sense.focusable && self.memory(|mem| mem.allows_interaction(w.layer_id));
1156
1157        // Remember this widget
1158        self.write(|ctx| {
1159            let viewport = ctx.viewport();
1160
1161            // We add all widgets here, even non-interactive ones,
1162            // because we need this list not only for checking for blocking widgets,
1163            // but also to know when we have reached the widget we are checking for cover.
1164            viewport.this_pass.widgets.insert(w.layer_id, w);
1165
1166            if allow_focus && interested_in_focus {
1167                ctx.memory.interested_in_focus(w.id, w.layer_id);
1168            }
1169        });
1170
1171        if allow_focus && !interested_in_focus {
1172            // Not interested or allowed input:
1173            self.memory_mut(|mem| mem.surrender_focus(w.id));
1174        }
1175
1176        if w.sense.interactive() || w.sense.focusable {
1177            self.check_for_id_clash(w.id, w.rect, "widget");
1178        }
1179
1180        #[allow(clippy::let_and_return)]
1181        let res = self.get_response(w);
1182
1183        #[cfg(feature = "accesskit")]
1184        if allow_focus && w.sense.focusable {
1185            // Make sure anything that can receive focus has an AccessKit node.
1186            // TODO(mwcampbell): For nodes that are filled from widget info,
1187            // some information is written to the node twice.
1188            self.accesskit_node_builder(w.id, |builder| res.fill_accesskit_node_common(builder));
1189        }
1190
1191        res
1192    }
1193
1194    /// Read the response of some widget, which may be called _before_ creating the widget (!).
1195    ///
1196    /// This is because widget interaction happens at the start of the pass, using the widget rects from the previous pass.
1197    ///
1198    /// If the widget was not visible the previous pass (or this pass), this will return `None`.
1199    pub fn read_response(&self, id: Id) -> Option<Response> {
1200        self.write(|ctx| {
1201            let viewport = ctx.viewport();
1202            viewport
1203                .this_pass
1204                .widgets
1205                .get(id)
1206                .or_else(|| viewport.prev_pass.widgets.get(id))
1207                .copied()
1208        })
1209        .map(|widget_rect| self.get_response(widget_rect))
1210    }
1211
1212    /// Returns `true` if the widget with the given `Id` contains the pointer.
1213    #[deprecated = "Use Response.contains_pointer or Context::read_response instead"]
1214    pub fn widget_contains_pointer(&self, id: Id) -> bool {
1215        self.read_response(id)
1216            .map_or(false, |response| response.contains_pointer)
1217    }
1218
1219    /// Do all interaction for an existing widget, without (re-)registering it.
1220    pub(crate) fn get_response(&self, widget_rect: WidgetRect) -> Response {
1221        let WidgetRect {
1222            id,
1223            layer_id,
1224            rect,
1225            interact_rect,
1226            sense,
1227            enabled,
1228        } = widget_rect;
1229
1230        // previous pass + "highlight next pass" == "highlight this pass"
1231        let highlighted = self.prev_pass_state(|fs| fs.highlight_next_pass.contains(&id));
1232
1233        let mut res = Response {
1234            ctx: self.clone(),
1235            layer_id,
1236            id,
1237            rect,
1238            interact_rect,
1239            sense,
1240            enabled,
1241            contains_pointer: false,
1242            hovered: false,
1243            highlighted,
1244            clicked: false,
1245            fake_primary_click: false,
1246            long_touched: false,
1247            drag_started: false,
1248            dragged: false,
1249            drag_stopped: false,
1250            is_pointer_button_down_on: false,
1251            interact_pointer_pos: None,
1252            changed: false,
1253            intrinsic_size: None,
1254        };
1255
1256        self.write(|ctx| {
1257            let viewport = ctx.viewports.entry(ctx.viewport_id()).or_default();
1258
1259            res.contains_pointer = viewport.interact_widgets.contains_pointer.contains(&id);
1260
1261            let input = &viewport.input;
1262            let memory = &mut ctx.memory;
1263
1264            if enabled
1265                && sense.click
1266                && memory.has_focus(id)
1267                && (input.key_pressed(Key::Space) || input.key_pressed(Key::Enter))
1268            {
1269                // Space/enter works like a primary click for e.g. selected buttons
1270                res.fake_primary_click = true;
1271            }
1272
1273            #[cfg(feature = "accesskit")]
1274            if enabled
1275                && sense.click
1276                && input.has_accesskit_action_request(id, accesskit::Action::Click)
1277            {
1278                res.fake_primary_click = true;
1279            }
1280
1281            if enabled && sense.click && Some(id) == viewport.interact_widgets.long_touched {
1282                res.long_touched = true;
1283            }
1284
1285            let interaction = memory.interaction();
1286
1287            res.is_pointer_button_down_on = interaction.potential_click_id == Some(id)
1288                || interaction.potential_drag_id == Some(id);
1289
1290            if res.enabled {
1291                res.hovered = viewport.interact_widgets.hovered.contains(&id);
1292                res.dragged = Some(id) == viewport.interact_widgets.dragged;
1293                res.drag_started = Some(id) == viewport.interact_widgets.drag_started;
1294                res.drag_stopped = Some(id) == viewport.interact_widgets.drag_stopped;
1295            }
1296
1297            let clicked = Some(id) == viewport.interact_widgets.clicked;
1298            let mut any_press = false;
1299
1300            for pointer_event in &input.pointer.pointer_events {
1301                match pointer_event {
1302                    PointerEvent::Moved(_) => {}
1303                    PointerEvent::Pressed { .. } => {
1304                        any_press = true;
1305                    }
1306                    PointerEvent::Released { click, .. } => {
1307                        if enabled && sense.click && clicked && click.is_some() {
1308                            res.clicked = true;
1309                        }
1310
1311                        res.is_pointer_button_down_on = false;
1312                        res.dragged = false;
1313                    }
1314                }
1315            }
1316
1317            // is_pointer_button_down_on is false when released, but we want interact_pointer_pos
1318            // to still work.
1319            let is_interacted_with =
1320                res.is_pointer_button_down_on || res.long_touched || clicked || res.drag_stopped;
1321            if is_interacted_with {
1322                res.interact_pointer_pos = input.pointer.interact_pos();
1323                if let (Some(to_global), Some(pos)) = (
1324                    memory.to_global.get(&res.layer_id),
1325                    &mut res.interact_pointer_pos,
1326                ) {
1327                    *pos = to_global.inverse() * *pos;
1328                }
1329            }
1330
1331            if input.pointer.any_down() && !is_interacted_with {
1332                // We don't hover widgets while interacting with *other* widgets:
1333                res.hovered = false;
1334            }
1335
1336            let pointer_pressed_elsewhere = any_press && !res.hovered;
1337            if pointer_pressed_elsewhere && memory.has_focus(id) {
1338                memory.surrender_focus(id);
1339            }
1340        });
1341
1342        res
1343    }
1344
1345    /// This is called by [`Response::widget_info`], but can also be called directly.
1346    ///
1347    /// With some debug flags it will store the widget info in [`crate::WidgetRects`] for later display.
1348    #[inline]
1349    pub fn register_widget_info(&self, id: Id, make_info: impl Fn() -> crate::WidgetInfo) {
1350        #[cfg(debug_assertions)]
1351        self.write(|ctx| {
1352            if ctx.memory.options.style().debug.show_interactive_widgets {
1353                ctx.viewport().this_pass.widgets.set_info(id, make_info());
1354            }
1355        });
1356
1357        #[cfg(not(debug_assertions))]
1358        {
1359            _ = (self, id, make_info);
1360        }
1361    }
1362
1363    /// Get a full-screen painter for a new or existing layer
1364    pub fn layer_painter(&self, layer_id: LayerId) -> Painter {
1365        let screen_rect = self.screen_rect();
1366        Painter::new(self.clone(), layer_id, screen_rect)
1367    }
1368
1369    /// Paint on top of everything else
1370    pub fn debug_painter(&self) -> Painter {
1371        Self::layer_painter(self, LayerId::debug())
1372    }
1373
1374    /// Print this text next to the cursor at the end of the pass.
1375    ///
1376    /// If you call this multiple times, the text will be appended.
1377    ///
1378    /// This only works if compiled with `debug_assertions`.
1379    ///
1380    /// ```
1381    /// # let ctx = egui::Context::default();
1382    /// # let state = true;
1383    /// ctx.debug_text(format!("State: {state:?}"));
1384    /// ```
1385    ///
1386    /// This is just a convenience for calling [`crate::debug_text::print`].
1387    #[track_caller]
1388    pub fn debug_text(&self, text: impl Into<WidgetText>) {
1389        crate::debug_text::print(self, text);
1390    }
1391
1392    /// What operating system are we running on?
1393    ///
1394    /// When compiling natively, this is
1395    /// figured out from the `target_os`.
1396    ///
1397    /// For web, this can be figured out from the user-agent,
1398    /// and is done so by [`eframe`](https://github.com/emilk/egui/tree/master/crates/eframe).
1399    pub fn os(&self) -> OperatingSystem {
1400        self.read(|ctx| ctx.os)
1401    }
1402
1403    /// Set the operating system we are running on.
1404    ///
1405    /// If you are writing wasm-based integration for egui you
1406    /// may want to set this based on e.g. the user-agent.
1407    pub fn set_os(&self, os: OperatingSystem) {
1408        self.write(|ctx| ctx.os = os);
1409    }
1410
1411    /// Set the cursor icon.
1412    ///
1413    /// Equivalent to:
1414    /// ```
1415    /// # let ctx = egui::Context::default();
1416    /// ctx.output_mut(|o| o.cursor_icon = egui::CursorIcon::PointingHand);
1417    /// ```
1418    pub fn set_cursor_icon(&self, cursor_icon: CursorIcon) {
1419        self.output_mut(|o| o.cursor_icon = cursor_icon);
1420    }
1421
1422    /// Open an URL in a browser.
1423    ///
1424    /// Equivalent to:
1425    /// ```
1426    /// # let ctx = egui::Context::default();
1427    /// # let open_url = egui::OpenUrl::same_tab("http://www.example.com");
1428    /// ctx.output_mut(|o| o.open_url = Some(open_url));
1429    /// ```
1430    pub fn open_url(&self, open_url: crate::OpenUrl) {
1431        self.output_mut(|o| o.open_url = Some(open_url));
1432    }
1433
1434    /// Copy the given text to the system clipboard.
1435    ///
1436    /// Empty strings are ignored.
1437    ///
1438    /// Note that in wasm applications, the clipboard is only accessible in secure contexts (e.g.,
1439    /// HTTPS or localhost). If this method is used outside of a secure context, it will log an
1440    /// error and do nothing. See <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts>.
1441    ///
1442    /// Equivalent to:
1443    /// ```
1444    /// # let ctx = egui::Context::default();
1445    /// ctx.output_mut(|o| o.copied_text = "Copy this".to_owned());
1446    /// ```
1447    pub fn copy_text(&self, text: String) {
1448        self.output_mut(|o| o.copied_text = text);
1449    }
1450
1451    /// Format the given shortcut in a human-readable way (e.g. `Ctrl+Shift+X`).
1452    ///
1453    /// Can be used to get the text for [`crate::Button::shortcut_text`].
1454    pub fn format_shortcut(&self, shortcut: &KeyboardShortcut) -> String {
1455        let os = self.os();
1456
1457        let is_mac = matches!(os, OperatingSystem::Mac | OperatingSystem::IOS);
1458
1459        let can_show_symbols = || {
1460            let ModifierNames {
1461                alt,
1462                ctrl,
1463                shift,
1464                mac_cmd,
1465                ..
1466            } = ModifierNames::SYMBOLS;
1467
1468            let font_id = TextStyle::Body.resolve(&self.style());
1469            self.fonts(|f| {
1470                let mut lock = f.lock();
1471                let font = lock.fonts.font(&font_id);
1472                font.has_glyphs(alt)
1473                    && font.has_glyphs(ctrl)
1474                    && font.has_glyphs(shift)
1475                    && font.has_glyphs(mac_cmd)
1476            })
1477        };
1478
1479        if is_mac && can_show_symbols() {
1480            shortcut.format(&ModifierNames::SYMBOLS, is_mac)
1481        } else {
1482            shortcut.format(&ModifierNames::NAMES, is_mac)
1483        }
1484    }
1485
1486    /// The total number of completed passes (usually there is one pass per rendered frame).
1487    ///
1488    /// Starts at zero, and is incremented for each completed pass inside of [`Self::run`] (usually once).
1489    pub fn cumulative_pass_nr(&self) -> u64 {
1490        self.cumulative_pass_nr_for(self.viewport_id())
1491    }
1492
1493    /// The total number of completed passes (usually there is one pass per rendered frame).
1494    ///
1495    /// Starts at zero, and is incremented for each completed pass inside of [`Self::run`] (usually once).
1496    pub fn cumulative_pass_nr_for(&self, id: ViewportId) -> u64 {
1497        self.read(|ctx| {
1498            ctx.viewports
1499                .get(&id)
1500                .map_or(0, |v| v.repaint.cumulative_pass_nr)
1501        })
1502    }
1503
1504    /// Call this if there is need to repaint the UI, i.e. if you are showing an animation.
1505    ///
1506    /// If this is called at least once in a frame, then there will be another frame right after this.
1507    /// Call as many times as you wish, only one repaint will be issued.
1508    ///
1509    /// To request repaint with a delay, use [`Self::request_repaint_after`].
1510    ///
1511    /// If called from outside the UI thread, the UI thread will wake up and run,
1512    /// provided the egui integration has set that up via [`Self::set_request_repaint_callback`]
1513    /// (this will work on `eframe`).
1514    ///
1515    /// This will repaint the current viewport.
1516    #[track_caller]
1517    pub fn request_repaint(&self) {
1518        self.request_repaint_of(self.viewport_id());
1519    }
1520
1521    /// Call this if there is need to repaint the UI, i.e. if you are showing an animation.
1522    ///
1523    /// If this is called at least once in a frame, then there will be another frame right after this.
1524    /// Call as many times as you wish, only one repaint will be issued.
1525    ///
1526    /// To request repaint with a delay, use [`Self::request_repaint_after_for`].
1527    ///
1528    /// If called from outside the UI thread, the UI thread will wake up and run,
1529    /// provided the egui integration has set that up via [`Self::set_request_repaint_callback`]
1530    /// (this will work on `eframe`).
1531    ///
1532    /// This will repaint the specified viewport.
1533    #[track_caller]
1534    pub fn request_repaint_of(&self, id: ViewportId) {
1535        let cause = RepaintCause::new();
1536        self.write(|ctx| ctx.request_repaint(id, cause));
1537    }
1538
1539    /// Request repaint after at most the specified duration elapses.
1540    ///
1541    /// The backend can chose to repaint sooner, for instance if some other code called
1542    /// this method with a lower duration, or if new events arrived.
1543    ///
1544    /// The function can be multiple times, but only the *smallest* duration will be considered.
1545    /// So, if the function is called two times with `1 second` and `2 seconds`, egui will repaint
1546    /// after `1 second`
1547    ///
1548    /// This is primarily useful for applications who would like to save battery by avoiding wasted
1549    /// redraws when the app is not in focus. But sometimes the GUI of the app might become stale
1550    /// and outdated if it is not updated for too long.
1551    ///
1552    /// Let's say, something like a stopwatch widget that displays the time in seconds. You would waste
1553    /// resources repainting multiple times within the same second (when you have no input),
1554    /// just calculate the difference of duration between current time and next second change,
1555    /// and call this function, to make sure that you are displaying the latest updated time, but
1556    /// not wasting resources on needless repaints within the same second.
1557    ///
1558    /// ### Quirk:
1559    /// Duration begins at the next frame. Let's say for example that it's a very inefficient app
1560    /// and takes 500 milliseconds per frame at 2 fps. The widget / user might want a repaint in
1561    /// next 500 milliseconds. Now, app takes 1000 ms per frame (1 fps) because the backend event
1562    /// timeout takes 500 milliseconds AFTER the vsync swap buffer.
1563    /// So, it's not that we are requesting repaint within X duration. We are rather timing out
1564    /// during app idle time where we are not receiving any new input events.
1565    ///
1566    /// This repaints the current viewport.
1567    #[track_caller]
1568    pub fn request_repaint_after(&self, duration: Duration) {
1569        self.request_repaint_after_for(duration, self.viewport_id());
1570    }
1571
1572    /// Repaint after this many seconds.
1573    ///
1574    /// See [`Self::request_repaint_after`] for details.
1575    #[track_caller]
1576    pub fn request_repaint_after_secs(&self, seconds: f32) {
1577        if let Ok(duration) = std::time::Duration::try_from_secs_f32(seconds) {
1578            self.request_repaint_after(duration);
1579        }
1580    }
1581
1582    /// Request repaint after at most the specified duration elapses.
1583    ///
1584    /// The backend can chose to repaint sooner, for instance if some other code called
1585    /// this method with a lower duration, or if new events arrived.
1586    ///
1587    /// The function can be multiple times, but only the *smallest* duration will be considered.
1588    /// So, if the function is called two times with `1 second` and `2 seconds`, egui will repaint
1589    /// after `1 second`
1590    ///
1591    /// This is primarily useful for applications who would like to save battery by avoiding wasted
1592    /// redraws when the app is not in focus. But sometimes the GUI of the app might become stale
1593    /// and outdated if it is not updated for too long.
1594    ///
1595    /// Let's say, something like a stopwatch widget that displays the time in seconds. You would waste
1596    /// resources repainting multiple times within the same second (when you have no input),
1597    /// just calculate the difference of duration between current time and next second change,
1598    /// and call this function, to make sure that you are displaying the latest updated time, but
1599    /// not wasting resources on needless repaints within the same second.
1600    ///
1601    /// ### Quirk:
1602    /// Duration begins at the next frame. Let's say for example that it's a very inefficient app
1603    /// and takes 500 milliseconds per frame at 2 fps. The widget / user might want a repaint in
1604    /// next 500 milliseconds. Now, app takes 1000 ms per frame (1 fps) because the backend event
1605    /// timeout takes 500 milliseconds AFTER the vsync swap buffer.
1606    /// So, it's not that we are requesting repaint within X duration. We are rather timing out
1607    /// during app idle time where we are not receiving any new input events.
1608    ///
1609    /// This repaints the specified viewport.
1610    #[track_caller]
1611    pub fn request_repaint_after_for(&self, duration: Duration, id: ViewportId) {
1612        let cause = RepaintCause::new();
1613        self.write(|ctx| ctx.request_repaint_after(duration, id, cause));
1614    }
1615
1616    /// Was a repaint requested last pass for the current viewport?
1617    #[must_use]
1618    pub fn requested_repaint_last_pass(&self) -> bool {
1619        self.requested_repaint_last_pass_for(&self.viewport_id())
1620    }
1621
1622    /// Was a repaint requested last pass for the given viewport?
1623    #[must_use]
1624    pub fn requested_repaint_last_pass_for(&self, viewport_id: &ViewportId) -> bool {
1625        self.read(|ctx| ctx.requested_immediate_repaint_prev_pass(viewport_id))
1626    }
1627
1628    /// Has a repaint been requested for the current viewport?
1629    #[must_use]
1630    pub fn has_requested_repaint(&self) -> bool {
1631        self.has_requested_repaint_for(&self.viewport_id())
1632    }
1633
1634    /// Has a repaint been requested for the given viewport?
1635    #[must_use]
1636    pub fn has_requested_repaint_for(&self, viewport_id: &ViewportId) -> bool {
1637        self.read(|ctx| ctx.has_requested_repaint(viewport_id))
1638    }
1639
1640    /// Why are we repainting?
1641    ///
1642    /// This can be helpful in debugging why egui is constantly repainting.
1643    pub fn repaint_causes(&self) -> Vec<RepaintCause> {
1644        self.read(|ctx| {
1645            ctx.viewports
1646                .get(&ctx.viewport_id())
1647                .map(|v| v.repaint.prev_causes.clone())
1648        })
1649        .unwrap_or_default()
1650    }
1651
1652    /// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`] or [`Self::request_repaint_after`].
1653    ///
1654    /// This lets you wake up a sleeping UI thread.
1655    ///
1656    /// Note that only one callback can be set. Any new call overrides the previous callback.
1657    pub fn set_request_repaint_callback(
1658        &self,
1659        callback: impl Fn(RequestRepaintInfo) + Send + Sync + 'static,
1660    ) {
1661        let callback = Box::new(callback);
1662        self.write(|ctx| ctx.request_repaint_callback = Some(callback));
1663    }
1664
1665    /// Request to discard the visual output of this pass,
1666    /// and to immediately do another one.
1667    ///
1668    /// This can be called to cover up visual glitches during a "sizing pass".
1669    /// For instance, when a [`crate::Grid`] is first shown we don't yet know the
1670    /// width and heights of its columns and rows. egui will do a best guess,
1671    /// but it will likely be wrong. Next pass it can read the sizes from the previous
1672    /// pass, and from there on the widths will be stable.
1673    /// This means the first pass will look glitchy, and ideally should not be shown to the user.
1674    /// So [`crate::Grid`] calls [`Self::request_discard`] to cover up this glitches.
1675    ///
1676    /// There is a limit to how many passes egui will perform, set by [`Options::max_passes`].
1677    /// Therefore, the request might be declined.
1678    ///
1679    /// You can check if the current pass will be discarded with [`Self::will_discard`].
1680    ///
1681    /// You should be very conservative with when you call [`Self::request_discard`],
1682    /// as it will cause an extra ui pass, potentially leading to extra CPU use and frame judder.
1683    ///
1684    /// The given reason should be a human-readable string that explains why `request_discard`
1685    /// was called. This will be shown in certain debug situations, to help you figure out
1686    /// why a pass was discarded.
1687    #[track_caller]
1688    pub fn request_discard(&self, reason: impl Into<Cow<'static, str>>) {
1689        let cause = RepaintCause::new_reason(reason);
1690        self.output_mut(|o| o.request_discard_reasons.push(cause));
1691
1692        #[cfg(feature = "log")]
1693        log::trace!(
1694            "request_discard: {}",
1695            if self.will_discard() {
1696                "allowed"
1697            } else {
1698                "denied"
1699            }
1700        );
1701    }
1702
1703    /// Will the visual output of this pass be discarded?
1704    ///
1705    /// If true, you can early-out from expensive graphics operations.
1706    ///
1707    /// See [`Self::request_discard`] for more.
1708    pub fn will_discard(&self) -> bool {
1709        self.write(|ctx| {
1710            let vp = ctx.viewport();
1711            // NOTE: `num_passes` is incremented
1712            vp.output.requested_discard()
1713                && vp.output.num_completed_passes + 1 < ctx.memory.options.max_passes.get()
1714        })
1715    }
1716}
1717
1718/// Callbacks
1719impl Context {
1720    /// Call the given callback at the start of each pass of each viewport.
1721    ///
1722    /// This can be used for egui _plugins_.
1723    /// See [`crate::debug_text`] for an example.
1724    pub fn on_begin_pass(&self, debug_name: &'static str, cb: ContextCallback) {
1725        let named_cb = NamedContextCallback {
1726            debug_name,
1727            callback: cb,
1728        };
1729        self.write(|ctx| ctx.plugins.on_begin_pass.push(named_cb));
1730    }
1731
1732    /// Call the given callback at the end of each pass of each viewport.
1733    ///
1734    /// This can be used for egui _plugins_.
1735    /// See [`crate::debug_text`] for an example.
1736    pub fn on_end_pass(&self, debug_name: &'static str, cb: ContextCallback) {
1737        let named_cb = NamedContextCallback {
1738            debug_name,
1739            callback: cb,
1740        };
1741        self.write(|ctx| ctx.plugins.on_end_pass.push(named_cb));
1742    }
1743}
1744
1745impl Context {
1746    /// Tell `egui` which fonts to use.
1747    ///
1748    /// The default `egui` fonts only support latin and cyrillic alphabets,
1749    /// but you can call this to install additional fonts that support e.g. korean characters.
1750    ///
1751    /// The new fonts will become active at the start of the next pass.
1752    /// This will overwrite the existing fonts.
1753    pub fn set_fonts(&self, font_definitions: FontDefinitions) {
1754        profiling::function_scope!();
1755
1756        let pixels_per_point = self.pixels_per_point();
1757
1758        let mut update_fonts = true;
1759
1760        self.read(|ctx| {
1761            if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) {
1762                // NOTE: this comparison is expensive since it checks TTF data for equality
1763                if current_fonts.lock().fonts.definitions() == &font_definitions {
1764                    update_fonts = false; // no need to update
1765                }
1766            }
1767        });
1768
1769        if update_fonts {
1770            self.memory_mut(|mem| mem.new_font_definitions = Some(font_definitions));
1771        }
1772    }
1773
1774    /// Tell `egui` which fonts to use.
1775    ///
1776    /// The default `egui` fonts only support latin and cyrillic alphabets,
1777    /// but you can call this to install additional fonts that support e.g. korean characters.
1778    ///
1779    /// The new font will become active at the start of the next pass.
1780    /// This will keep the existing fonts.
1781    pub fn add_font(&self, new_font: FontInsert) {
1782        profiling::function_scope!();
1783
1784        let pixels_per_point = self.pixels_per_point();
1785
1786        let mut update_fonts = true;
1787
1788        self.read(|ctx| {
1789            if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) {
1790                if current_fonts
1791                    .lock()
1792                    .fonts
1793                    .definitions()
1794                    .font_data
1795                    .contains_key(&new_font.name)
1796                {
1797                    update_fonts = false; // no need to update
1798                }
1799            }
1800        });
1801
1802        if update_fonts {
1803            self.memory_mut(|mem| mem.add_fonts.push(new_font));
1804        }
1805    }
1806
1807    /// Does the OS use dark or light mode?
1808    /// This is used when the theme preference is set to [`crate::ThemePreference::System`].
1809    pub fn system_theme(&self) -> Option<Theme> {
1810        self.memory(|mem| mem.options.system_theme)
1811    }
1812
1813    /// The [`Theme`] used to select the appropriate [`Style`] (dark or light)
1814    /// used by all subsequent windows, panels etc.
1815    pub fn theme(&self) -> Theme {
1816        self.options(|opt| opt.theme())
1817    }
1818
1819    /// The [`Theme`] used to select between dark and light [`Self::style`]
1820    /// as the active style used by all subsequent windows, panels etc.
1821    ///
1822    /// Example:
1823    /// ```
1824    /// # let mut ctx = egui::Context::default();
1825    /// ctx.set_theme(egui::Theme::Light); // Switch to light mode
1826    /// ```
1827    pub fn set_theme(&self, theme_preference: impl Into<crate::ThemePreference>) {
1828        self.options_mut(|opt| opt.theme_preference = theme_preference.into());
1829    }
1830
1831    /// The currently active [`Style`] used by all subsequent windows, panels etc.
1832    pub fn style(&self) -> Arc<Style> {
1833        self.options(|opt| opt.style().clone())
1834    }
1835
1836    /// Mutate the currently active [`Style`] used by all subsequent windows, panels etc.
1837    /// Use [`Self::all_styles_mut`] to mutate both dark and light mode styles.
1838    ///
1839    /// Example:
1840    /// ```
1841    /// # let mut ctx = egui::Context::default();
1842    /// ctx.style_mut(|style| {
1843    ///     style.spacing.item_spacing = egui::vec2(10.0, 20.0);
1844    /// });
1845    /// ```
1846    pub fn style_mut(&self, mutate_style: impl FnOnce(&mut Style)) {
1847        self.options_mut(|opt| mutate_style(Arc::make_mut(opt.style_mut())));
1848    }
1849
1850    /// The currently active [`Style`] used by all new windows, panels etc.
1851    ///
1852    /// Use [`Self::all_styles_mut`] to mutate both dark and light mode styles.
1853    ///
1854    /// You can also change this using [`Self::style_mut`].
1855    ///
1856    /// You can use [`Ui::style_mut`] to change the style of a single [`Ui`].
1857    pub fn set_style(&self, style: impl Into<Arc<Style>>) {
1858        self.options_mut(|opt| *opt.style_mut() = style.into());
1859    }
1860
1861    /// Mutate the [`Style`]s used by all subsequent windows, panels etc. in both dark and light mode.
1862    ///
1863    /// Example:
1864    /// ```
1865    /// # let mut ctx = egui::Context::default();
1866    /// ctx.all_styles_mut(|style| {
1867    ///     style.spacing.item_spacing = egui::vec2(10.0, 20.0);
1868    /// });
1869    /// ```
1870    pub fn all_styles_mut(&self, mut mutate_style: impl FnMut(&mut Style)) {
1871        self.options_mut(|opt| {
1872            mutate_style(Arc::make_mut(&mut opt.dark_style));
1873            mutate_style(Arc::make_mut(&mut opt.light_style));
1874        });
1875    }
1876
1877    /// The [`Style`] used by all subsequent windows, panels etc.
1878    pub fn style_of(&self, theme: Theme) -> Arc<Style> {
1879        self.options(|opt| match theme {
1880            Theme::Dark => opt.dark_style.clone(),
1881            Theme::Light => opt.light_style.clone(),
1882        })
1883    }
1884
1885    /// Mutate the [`Style`] used by all subsequent windows, panels etc.
1886    ///
1887    /// Example:
1888    /// ```
1889    /// # let mut ctx = egui::Context::default();
1890    /// ctx.style_mut_of(egui::Theme::Dark, |style| {
1891    ///     style.spacing.item_spacing = egui::vec2(10.0, 20.0);
1892    /// });
1893    /// ```
1894    pub fn style_mut_of(&self, theme: Theme, mutate_style: impl FnOnce(&mut Style)) {
1895        self.options_mut(|opt| match theme {
1896            Theme::Dark => mutate_style(Arc::make_mut(&mut opt.dark_style)),
1897            Theme::Light => mutate_style(Arc::make_mut(&mut opt.light_style)),
1898        });
1899    }
1900
1901    /// The [`Style`] used by all new windows, panels etc.
1902    /// Use [`Self::set_theme`] to choose between dark and light mode.
1903    ///
1904    /// You can also change this using [`Self::style_mut_of`].
1905    ///
1906    /// You can use [`Ui::style_mut`] to change the style of a single [`Ui`].
1907    pub fn set_style_of(&self, theme: Theme, style: impl Into<Arc<Style>>) {
1908        let style = style.into();
1909        self.options_mut(|opt| match theme {
1910            Theme::Dark => opt.dark_style = style,
1911            Theme::Light => opt.light_style = style,
1912        });
1913    }
1914
1915    /// The [`crate::Visuals`] used by all subsequent windows, panels etc.
1916    ///
1917    /// You can also use [`Ui::visuals_mut`] to change the visuals of a single [`Ui`].
1918    ///
1919    /// Example:
1920    /// ```
1921    /// # let mut ctx = egui::Context::default();
1922    /// ctx.set_visuals_of(egui::Theme::Dark, egui::Visuals { panel_fill: egui::Color32::RED, ..Default::default() });
1923    /// ```
1924    pub fn set_visuals_of(&self, theme: Theme, visuals: crate::Visuals) {
1925        self.style_mut_of(theme, |style| style.visuals = visuals);
1926    }
1927
1928    /// The [`crate::Visuals`] used by all subsequent windows, panels etc.
1929    ///
1930    /// You can also use [`Ui::visuals_mut`] to change the visuals of a single [`Ui`].
1931    ///
1932    /// Example:
1933    /// ```
1934    /// # let mut ctx = egui::Context::default();
1935    /// ctx.set_visuals(egui::Visuals { panel_fill: egui::Color32::RED, ..Default::default() });
1936    /// ```
1937    pub fn set_visuals(&self, visuals: crate::Visuals) {
1938        self.style_mut_of(self.theme(), |style| style.visuals = visuals);
1939    }
1940
1941    /// The number of physical pixels for each logical point.
1942    ///
1943    /// This is calculated as [`Self::zoom_factor`] * [`Self::native_pixels_per_point`]
1944    #[inline(always)]
1945    pub fn pixels_per_point(&self) -> f32 {
1946        self.input(|i| i.pixels_per_point)
1947    }
1948
1949    /// Set the number of physical pixels for each logical point.
1950    /// Will become active at the start of the next pass.
1951    ///
1952    /// This will actually translate to a call to [`Self::set_zoom_factor`].
1953    pub fn set_pixels_per_point(&self, pixels_per_point: f32) {
1954        if pixels_per_point != self.pixels_per_point() {
1955            self.set_zoom_factor(pixels_per_point / self.native_pixels_per_point().unwrap_or(1.0));
1956        }
1957    }
1958
1959    /// The number of physical pixels for each logical point on this monitor.
1960    ///
1961    /// This is given as input to egui via [`crate::ViewportInfo::native_pixels_per_point`]
1962    /// and cannot be changed.
1963    #[inline(always)]
1964    pub fn native_pixels_per_point(&self) -> Option<f32> {
1965        self.input(|i| i.viewport().native_pixels_per_point)
1966    }
1967
1968    /// Global zoom factor of the UI.
1969    ///
1970    /// This is used to calculate the `pixels_per_point`
1971    /// for the UI as `pixels_per_point = zoom_factor * native_pixels_per_point`.
1972    ///
1973    /// The default is 1.0.
1974    /// Make larger to make everything larger.
1975    #[inline(always)]
1976    pub fn zoom_factor(&self) -> f32 {
1977        self.options(|o| o.zoom_factor)
1978    }
1979
1980    /// Sets zoom factor of the UI.
1981    /// Will become active at the start of the next pass.
1982    ///
1983    /// Note that calling this will not update [`Self::zoom_factor`] until the end of the pass.
1984    ///
1985    /// This is used to calculate the `pixels_per_point`
1986    /// for the UI as `pixels_per_point = zoom_fator * native_pixels_per_point`.
1987    ///
1988    /// The default is 1.0.
1989    /// Make larger to make everything larger.
1990    ///
1991    /// It is better to call this than modifying
1992    /// [`Options::zoom_factor`].
1993    #[inline(always)]
1994    pub fn set_zoom_factor(&self, zoom_factor: f32) {
1995        let cause = RepaintCause::new();
1996        self.write(|ctx| {
1997            if ctx.memory.options.zoom_factor != zoom_factor {
1998                ctx.new_zoom_factor = Some(zoom_factor);
1999                for viewport_id in ctx.all_viewport_ids() {
2000                    ctx.request_repaint(viewport_id, cause.clone());
2001                }
2002            }
2003        });
2004    }
2005
2006    /// Useful for pixel-perfect rendering of lines that are one pixel wide (or any odd number of pixels).
2007    #[inline]
2008    pub(crate) fn round_to_pixel_center(&self, point: f32) -> f32 {
2009        let pixels_per_point = self.pixels_per_point();
2010        ((point * pixels_per_point - 0.5).round() + 0.5) / pixels_per_point
2011    }
2012
2013    /// Useful for pixel-perfect rendering of lines that are one pixel wide (or any odd number of pixels).
2014    #[inline]
2015    pub(crate) fn round_pos_to_pixel_center(&self, point: Pos2) -> Pos2 {
2016        pos2(
2017            self.round_to_pixel_center(point.x),
2018            self.round_to_pixel_center(point.y),
2019        )
2020    }
2021
2022    /// Useful for pixel-perfect rendering of filled shapes
2023    #[inline]
2024    pub(crate) fn round_to_pixel(&self, point: f32) -> f32 {
2025        let pixels_per_point = self.pixels_per_point();
2026        (point * pixels_per_point).round() / pixels_per_point
2027    }
2028
2029    /// Useful for pixel-perfect rendering of filled shapes
2030    #[inline]
2031    pub(crate) fn round_pos_to_pixels(&self, pos: Pos2) -> Pos2 {
2032        pos2(self.round_to_pixel(pos.x), self.round_to_pixel(pos.y))
2033    }
2034
2035    /// Useful for pixel-perfect rendering of filled shapes
2036    #[inline]
2037    pub(crate) fn round_vec_to_pixels(&self, vec: Vec2) -> Vec2 {
2038        vec2(self.round_to_pixel(vec.x), self.round_to_pixel(vec.y))
2039    }
2040
2041    /// Useful for pixel-perfect rendering of filled shapes
2042    #[inline]
2043    pub(crate) fn round_rect_to_pixels(&self, rect: Rect) -> Rect {
2044        Rect {
2045            min: self.round_pos_to_pixels(rect.min),
2046            max: self.round_pos_to_pixels(rect.max),
2047        }
2048    }
2049
2050    /// Allocate a texture.
2051    ///
2052    /// This is for advanced users.
2053    /// Most users should use [`crate::Ui::image`] or [`Self::try_load_texture`]
2054    /// instead.
2055    ///
2056    /// In order to display an image you must convert it to a texture using this function.
2057    /// The function will hand over the image data to the egui backend, which will
2058    /// upload it to the GPU.
2059    ///
2060    /// ⚠️ Make sure to only call this ONCE for each image, i.e. NOT in your main GUI code.
2061    /// The call is NOT immediate safe.
2062    ///
2063    /// The given name can be useful for later debugging, and will be visible if you call [`Self::texture_ui`].
2064    ///
2065    /// For how to load an image, see [`crate::ImageData`] and [`crate::ColorImage::from_rgba_unmultiplied`].
2066    ///
2067    /// ```
2068    /// struct MyImage {
2069    ///     texture: Option<egui::TextureHandle>,
2070    /// }
2071    ///
2072    /// impl MyImage {
2073    ///     fn ui(&mut self, ui: &mut egui::Ui) {
2074    ///         let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| {
2075    ///             // Load the texture only once.
2076    ///             ui.ctx().load_texture(
2077    ///                 "my-image",
2078    ///                 egui::ColorImage::example(),
2079    ///                 Default::default()
2080    ///             )
2081    ///         });
2082    ///
2083    ///         // Show the image:
2084    ///         ui.image((texture.id(), texture.size_vec2()));
2085    ///     }
2086    /// }
2087    /// ```
2088    ///
2089    /// See also [`crate::ImageData`], [`crate::Ui::image`] and [`crate::Image`].
2090    pub fn load_texture(
2091        &self,
2092        name: impl Into<String>,
2093        image: impl Into<ImageData>,
2094        options: TextureOptions,
2095    ) -> TextureHandle {
2096        let name = name.into();
2097        let image = image.into();
2098        let max_texture_side = self.input(|i| i.max_texture_side);
2099        debug_assert!(
2100            image.width() <= max_texture_side && image.height() <= max_texture_side,
2101            "Texture {:?} has size {}x{}, but the maximum texture side is {}",
2102            name,
2103            image.width(),
2104            image.height(),
2105            max_texture_side
2106        );
2107        let tex_mngr = self.tex_manager();
2108        let tex_id = tex_mngr.write().alloc(name, image, options);
2109        TextureHandle::new(tex_mngr, tex_id)
2110    }
2111
2112    /// Low-level texture manager.
2113    ///
2114    /// In general it is easier to use [`Self::load_texture`] and [`TextureHandle`].
2115    ///
2116    /// You can show stats about the allocated textures using [`Self::texture_ui`].
2117    pub fn tex_manager(&self) -> Arc<RwLock<epaint::textures::TextureManager>> {
2118        self.read(|ctx| ctx.tex_manager.0.clone())
2119    }
2120
2121    // ---------------------------------------------------------------------
2122
2123    /// Constrain the position of a window/area so it fits within the provided boundary.
2124    pub(crate) fn constrain_window_rect_to_area(&self, window: Rect, area: Rect) -> Rect {
2125        let mut pos = window.min;
2126
2127        // Constrain to screen, unless window is too large to fit:
2128        let margin_x = (window.width() - area.width()).at_least(0.0);
2129        let margin_y = (window.height() - area.height()).at_least(0.0);
2130
2131        pos.x = pos.x.at_most(area.right() + margin_x - window.width()); // move left if needed
2132        pos.x = pos.x.at_least(area.left() - margin_x); // move right if needed
2133        pos.y = pos.y.at_most(area.bottom() + margin_y - window.height()); // move right if needed
2134        pos.y = pos.y.at_least(area.top() - margin_y); // move down if needed
2135
2136        pos = self.round_pos_to_pixels(pos);
2137
2138        Rect::from_min_size(pos, window.size())
2139    }
2140}
2141
2142impl Context {
2143    /// Call at the end of each frame if you called [`Context::begin_pass`].
2144    #[must_use]
2145    pub fn end_pass(&self) -> FullOutput {
2146        profiling::function_scope!();
2147
2148        if self.options(|o| o.zoom_with_keyboard) {
2149            crate::gui_zoom::zoom_with_keyboard(self);
2150        }
2151
2152        // Plugins run just before the pass ends.
2153        self.read(|ctx| ctx.plugins.clone()).on_end_pass(self);
2154
2155        #[cfg(debug_assertions)]
2156        self.debug_painting();
2157
2158        self.write(|ctx| ctx.end_pass())
2159    }
2160
2161    /// Call at the end of each frame if you called [`Context::begin_pass`].
2162    #[must_use]
2163    #[deprecated = "Renamed end_pass"]
2164    pub fn end_frame(&self) -> FullOutput {
2165        self.end_pass()
2166    }
2167
2168    /// Called at the end of the pass.
2169    #[cfg(debug_assertions)]
2170    fn debug_painting(&self) {
2171        let paint_widget = |widget: &WidgetRect, text: &str, color: Color32| {
2172            let rect = widget.interact_rect;
2173            if rect.is_positive() {
2174                let painter = Painter::new(self.clone(), widget.layer_id, Rect::EVERYTHING);
2175                painter.debug_rect(rect, color, text);
2176            }
2177        };
2178
2179        let paint_widget_id = |id: Id, text: &str, color: Color32| {
2180            if let Some(widget) =
2181                self.write(|ctx| ctx.viewport().this_pass.widgets.get(id).copied())
2182            {
2183                paint_widget(&widget, text, color);
2184            }
2185        };
2186
2187        if self.style().debug.show_interactive_widgets {
2188            // Show all interactive widgets:
2189            let rects = self.write(|ctx| ctx.viewport().this_pass.widgets.clone());
2190            for (layer_id, rects) in rects.layers() {
2191                let painter = Painter::new(self.clone(), *layer_id, Rect::EVERYTHING);
2192                for rect in rects {
2193                    if rect.sense.interactive() {
2194                        let (color, text) = if rect.sense.click && rect.sense.drag {
2195                            (Color32::from_rgb(0x88, 0, 0x88), "click+drag")
2196                        } else if rect.sense.click {
2197                            (Color32::from_rgb(0x88, 0, 0), "click")
2198                        } else if rect.sense.drag {
2199                            (Color32::from_rgb(0, 0, 0x88), "drag")
2200                        } else {
2201                            // unreachable since we only show interactive
2202                            (Color32::from_rgb(0, 0, 0x88), "hover")
2203                        };
2204                        painter.debug_rect(rect.interact_rect, color, text);
2205                    }
2206                }
2207            }
2208
2209            // Show the ones actually interacted with:
2210            {
2211                let interact_widgets = self.write(|ctx| ctx.viewport().interact_widgets.clone());
2212                let InteractionSnapshot {
2213                    clicked,
2214                    long_touched: _,
2215                    drag_started: _,
2216                    dragged,
2217                    drag_stopped: _,
2218                    contains_pointer,
2219                    hovered,
2220                } = interact_widgets;
2221
2222                if true {
2223                    for &id in &contains_pointer {
2224                        paint_widget_id(id, "contains_pointer", Color32::BLUE);
2225                    }
2226
2227                    let widget_rects = self.write(|w| w.viewport().this_pass.widgets.clone());
2228
2229                    let mut contains_pointer: Vec<Id> = contains_pointer.iter().copied().collect();
2230                    contains_pointer.sort_by_key(|&id| {
2231                        widget_rects
2232                            .order(id)
2233                            .map(|(layer_id, order_in_layer)| (layer_id.order, order_in_layer))
2234                    });
2235
2236                    let mut debug_text = "Widgets in order:\n".to_owned();
2237                    for id in contains_pointer {
2238                        let mut widget_text = format!("{id:?}");
2239                        if let Some(rect) = widget_rects.get(id) {
2240                            widget_text +=
2241                                &format!(" {:?} {:?} {:?}", rect.layer_id, rect.rect, rect.sense);
2242                        }
2243                        if let Some(info) = widget_rects.info(id) {
2244                            widget_text += &format!(" {info:?}");
2245                        }
2246                        debug_text += &format!("{widget_text}\n");
2247                    }
2248                    self.debug_text(debug_text);
2249                }
2250                if true {
2251                    for widget in hovered {
2252                        paint_widget_id(widget, "hovered", Color32::WHITE);
2253                    }
2254                }
2255                if let Some(widget) = clicked {
2256                    paint_widget_id(widget, "clicked", Color32::RED);
2257                }
2258                if let Some(widget) = dragged {
2259                    paint_widget_id(widget, "dragged", Color32::GREEN);
2260                }
2261            }
2262        }
2263
2264        if self.style().debug.show_widget_hits {
2265            let hits = self.write(|ctx| ctx.viewport().hits.clone());
2266            let WidgetHits {
2267                close,
2268                contains_pointer,
2269                click,
2270                drag,
2271            } = hits;
2272
2273            if false {
2274                for widget in &close {
2275                    paint_widget(widget, "close", Color32::from_gray(70));
2276                }
2277            }
2278            if true {
2279                for widget in &contains_pointer {
2280                    paint_widget(widget, "contains_pointer", Color32::BLUE);
2281                }
2282            }
2283            if let Some(widget) = &click {
2284                paint_widget(widget, "click", Color32::RED);
2285            }
2286            if let Some(widget) = &drag {
2287                paint_widget(widget, "drag", Color32::GREEN);
2288            }
2289        }
2290
2291        if let Some(debug_rect) = self.pass_state_mut(|fs| fs.debug_rect.take()) {
2292            debug_rect.paint(&self.debug_painter());
2293        }
2294
2295        let num_multipass_in_row = self.viewport(|vp| vp.num_multipass_in_row);
2296        if 3 <= num_multipass_in_row {
2297            // If you see this message, it means we've been paying the cost of multi-pass for multiple frames in a row.
2298            // This is likely a bug. `request_discard` should only be called in rare situations, when some layout changes.
2299
2300            let mut warning = format!("egui PERF WARNING: request_discard has been called {num_multipass_in_row} frames in a row");
2301            self.viewport(|vp| {
2302                for reason in &vp.output.request_discard_reasons {
2303                    warning += &format!("\n  {reason}");
2304                }
2305            });
2306
2307            self.debug_painter()
2308                .debug_text(Pos2::ZERO, Align2::LEFT_TOP, Color32::RED, warning);
2309        }
2310    }
2311}
2312
2313impl ContextImpl {
2314    fn end_pass(&mut self) -> FullOutput {
2315        let ended_viewport_id = self.viewport_id();
2316        let viewport = self.viewports.entry(ended_viewport_id).or_default();
2317        let pixels_per_point = viewport.input.pixels_per_point;
2318
2319        viewport.repaint.cumulative_pass_nr += 1;
2320
2321        self.memory.end_pass(&viewport.this_pass.used_ids);
2322
2323        if let Some(fonts) = self.fonts.get(&pixels_per_point.into()) {
2324            let tex_mngr = &mut self.tex_manager.0.write();
2325            if let Some(font_image_delta) = fonts.font_image_delta() {
2326                // A partial font atlas update, e.g. a new glyph has been entered.
2327                tex_mngr.set(TextureId::default(), font_image_delta);
2328            }
2329
2330            if 1 < self.fonts.len() {
2331                // We have multiple different `pixels_per_point`,
2332                // e.g. because we have many viewports spread across
2333                // monitors with different DPI scaling.
2334                // All viewports share the same texture namespace and renderer,
2335                // so the all use `TextureId::default()` for the font texture.
2336                // This is a problem.
2337                // We solve this with a hack: we always upload the full font atlas
2338                // every frame, for all viewports.
2339                // This ensures it is up-to-date, solving
2340                // https://github.com/emilk/egui/issues/3664
2341                // at the cost of a lot of performance.
2342                // (This will override any smaller delta that was uploaded above.)
2343                profiling::scope!("full_font_atlas_update");
2344                let full_delta = ImageDelta::full(fonts.image(), TextureAtlas::texture_options());
2345                tex_mngr.set(TextureId::default(), full_delta);
2346            }
2347        }
2348
2349        // Inform the backend of all textures that have been updated (including font atlas).
2350        let textures_delta = self.tex_manager.0.write().take_delta();
2351
2352        #[cfg_attr(not(feature = "accesskit"), allow(unused_mut))]
2353        let mut platform_output: PlatformOutput = std::mem::take(&mut viewport.output);
2354
2355        #[cfg(feature = "accesskit")]
2356        {
2357            profiling::scope!("accesskit");
2358            let state = viewport.this_pass.accesskit_state.take();
2359            if let Some(state) = state {
2360                let root_id = crate::accesskit_root_id().accesskit_id();
2361                let nodes = {
2362                    state
2363                        .nodes
2364                        .into_iter()
2365                        .map(|(id, node)| (id.accesskit_id(), node))
2366                        .collect()
2367                };
2368                let focus_id = self
2369                    .memory
2370                    .focused()
2371                    .map_or(root_id, |id| id.accesskit_id());
2372                platform_output.accesskit_update = Some(accesskit::TreeUpdate {
2373                    nodes,
2374                    tree: Some(accesskit::Tree::new(root_id)),
2375                    focus: focus_id,
2376                });
2377            }
2378        }
2379
2380        let shapes = viewport
2381            .graphics
2382            .drain(self.memory.areas().order(), &self.memory.to_global);
2383
2384        let mut repaint_needed = false;
2385
2386        if self.memory.options.repaint_on_widget_change {
2387            profiling::scope!("compare-widget-rects");
2388            if viewport.prev_pass.widgets != viewport.this_pass.widgets {
2389                repaint_needed = true; // Some widget has moved
2390            }
2391        }
2392
2393        std::mem::swap(&mut viewport.prev_pass, &mut viewport.this_pass);
2394
2395        if repaint_needed {
2396            self.request_repaint(ended_viewport_id, RepaintCause::new());
2397        } else if let Some(delay) = viewport.input.wants_repaint_after() {
2398            self.request_repaint_after(delay, ended_viewport_id, RepaintCause::new());
2399        }
2400
2401        //  -------------------
2402
2403        let all_viewport_ids = self.all_viewport_ids();
2404
2405        self.last_viewport = ended_viewport_id;
2406
2407        self.viewports.retain(|&id, viewport| {
2408            let parent = *self.viewport_parents.entry(id).or_default();
2409
2410            if !all_viewport_ids.contains(&parent) {
2411                #[cfg(feature = "log")]
2412                log::debug!(
2413                    "Removing viewport {:?} ({:?}): the parent is gone",
2414                    id,
2415                    viewport.builder.title
2416                );
2417
2418                return false;
2419            }
2420
2421            let is_our_child = parent == ended_viewport_id && id != ViewportId::ROOT;
2422            if is_our_child {
2423                if !viewport.used {
2424                    #[cfg(feature = "log")]
2425                    log::debug!(
2426                        "Removing viewport {:?} ({:?}): it was never used this pass",
2427                        id,
2428                        viewport.builder.title
2429                    );
2430
2431                    return false; // Only keep children that have been updated this pass
2432                }
2433
2434                viewport.used = false; // reset so we can check again next pass
2435            }
2436
2437            true
2438        });
2439
2440        // If we are an immediate viewport, this will resume the previous viewport.
2441        self.viewport_stack.pop();
2442
2443        // The last viewport is not necessarily the root viewport,
2444        // just the top _immediate_ viewport.
2445        let is_last = self.viewport_stack.is_empty();
2446
2447        let viewport_output = self
2448            .viewports
2449            .iter_mut()
2450            .map(|(&id, viewport)| {
2451                let parent = *self.viewport_parents.entry(id).or_default();
2452                let commands = if is_last {
2453                    // Let the primary immediate viewport handle the commands of its children too.
2454                    // This can make things easier for the backend, as otherwise we may get commands
2455                    // that affect a viewport while its egui logic is running.
2456                    std::mem::take(&mut viewport.commands)
2457                } else {
2458                    vec![]
2459                };
2460
2461                (
2462                    id,
2463                    ViewportOutput {
2464                        parent,
2465                        class: viewport.class,
2466                        builder: viewport.builder.clone(),
2467                        viewport_ui_cb: viewport.viewport_ui_cb.clone(),
2468                        commands,
2469                        repaint_delay: viewport.repaint.repaint_delay,
2470                    },
2471                )
2472            })
2473            .collect();
2474
2475        if is_last {
2476            // Remove dead viewports:
2477            self.viewports.retain(|id, _| all_viewport_ids.contains(id));
2478            self.viewport_parents
2479                .retain(|id, _| all_viewport_ids.contains(id));
2480        } else {
2481            let viewport_id = self.viewport_id();
2482            self.memory.set_viewport_id(viewport_id);
2483        }
2484
2485        let active_pixels_per_point: std::collections::BTreeSet<OrderedFloat<f32>> = self
2486            .viewports
2487            .values()
2488            .map(|v| v.input.pixels_per_point.into())
2489            .collect();
2490        self.fonts.retain(|pixels_per_point, _| {
2491            if active_pixels_per_point.contains(pixels_per_point) {
2492                true
2493            } else {
2494                #[cfg(feature = "log")]
2495                log::trace!(
2496                    "Freeing Fonts with pixels_per_point={} because it is no longer needed",
2497                    pixels_per_point.into_inner()
2498                );
2499                false
2500            }
2501        });
2502
2503        platform_output.num_completed_passes += 1;
2504
2505        FullOutput {
2506            platform_output,
2507            textures_delta,
2508            shapes,
2509            pixels_per_point,
2510            viewport_output,
2511        }
2512    }
2513}
2514
2515impl Context {
2516    /// Tessellate the given shapes into triangle meshes.
2517    ///
2518    /// `pixels_per_point` is used for feathering (anti-aliasing).
2519    /// For this you can use [`FullOutput::pixels_per_point`], [`Self::pixels_per_point`],
2520    /// or whatever is appropriate for your viewport.
2521    pub fn tessellate(
2522        &self,
2523        shapes: Vec<ClippedShape>,
2524        pixels_per_point: f32,
2525    ) -> Vec<ClippedPrimitive> {
2526        profiling::function_scope!();
2527
2528        // A tempting optimization is to reuse the tessellation from last frame if the
2529        // shapes are the same, but just comparing the shapes takes about 50% of the time
2530        // it takes to tessellate them, so it is not a worth optimization.
2531
2532        self.write(|ctx| {
2533            let tessellation_options = ctx.memory.options.tessellation_options;
2534            let texture_atlas = if let Some(fonts) = ctx.fonts.get(&pixels_per_point.into()) {
2535                fonts.texture_atlas()
2536            } else {
2537                #[cfg(feature = "log")]
2538                log::warn!("No font size matching {pixels_per_point} pixels per point found.");
2539                ctx.fonts
2540                    .iter()
2541                    .next()
2542                    .expect("No fonts loaded")
2543                    .1
2544                    .texture_atlas()
2545            };
2546            let (font_tex_size, prepared_discs) = {
2547                let atlas = texture_atlas.lock();
2548                (atlas.size(), atlas.prepared_discs())
2549            };
2550
2551            let paint_stats = PaintStats::from_shapes(&shapes);
2552            let clipped_primitives = {
2553                profiling::scope!("tessellator::tessellate_shapes");
2554                tessellator::Tessellator::new(
2555                    pixels_per_point,
2556                    tessellation_options,
2557                    font_tex_size,
2558                    prepared_discs,
2559                )
2560                .tessellate_shapes(shapes)
2561            };
2562            ctx.paint_stats = paint_stats.with_clipped_primitives(&clipped_primitives);
2563            clipped_primitives
2564        })
2565    }
2566
2567    // ---------------------------------------------------------------------
2568
2569    /// Position and size of the egui area.
2570    pub fn screen_rect(&self) -> Rect {
2571        self.input(|i| i.screen_rect())
2572    }
2573
2574    /// How much space is still available after panels has been added.
2575    ///
2576    /// This is the "background" area, what egui doesn't cover with panels (but may cover with windows).
2577    /// This is also the area to which windows are constrained.
2578    pub fn available_rect(&self) -> Rect {
2579        self.pass_state(|s| s.available_rect())
2580    }
2581
2582    /// How much space is used by panels and windows.
2583    pub fn used_rect(&self) -> Rect {
2584        self.write(|ctx| {
2585            let mut used = ctx.viewport().this_pass.used_by_panels;
2586            for (_id, window) in ctx.memory.areas().visible_windows() {
2587                used = used.union(window.rect());
2588            }
2589            used
2590        })
2591    }
2592
2593    /// How much space is used by panels and windows.
2594    ///
2595    /// You can shrink your egui area to this size and still fit all egui components.
2596    pub fn used_size(&self) -> Vec2 {
2597        self.used_rect().max - Pos2::ZERO
2598    }
2599
2600    // ---------------------------------------------------------------------
2601
2602    /// Is the pointer (mouse/touch) over any egui area?
2603    pub fn is_pointer_over_area(&self) -> bool {
2604        let pointer_pos = self.input(|i| i.pointer.interact_pos());
2605        if let Some(pointer_pos) = pointer_pos {
2606            if let Some(layer) = self.layer_id_at(pointer_pos) {
2607                if layer.order == Order::Background {
2608                    !self.pass_state(|state| state.unused_rect.contains(pointer_pos))
2609                } else {
2610                    true
2611                }
2612            } else {
2613                false
2614            }
2615        } else {
2616            false
2617        }
2618    }
2619
2620    /// True if egui is currently interested in the pointer (mouse or touch).
2621    ///
2622    /// Could be the pointer is hovering over a [`crate::Window`] or the user is dragging a widget.
2623    /// If `false`, the pointer is outside of any egui area and so
2624    /// you may be interested in what it is doing (e.g. controlling your game).
2625    /// Returns `false` if a drag started outside of egui and then moved over an egui area.
2626    pub fn wants_pointer_input(&self) -> bool {
2627        self.is_using_pointer()
2628            || (self.is_pointer_over_area() && !self.input(|i| i.pointer.any_down()))
2629    }
2630
2631    /// Is egui currently using the pointer position (e.g. dragging a slider)?
2632    ///
2633    /// NOTE: this will return `false` if the pointer is just hovering over an egui area.
2634    pub fn is_using_pointer(&self) -> bool {
2635        self.memory(|m| m.interaction().is_using_pointer())
2636    }
2637
2638    /// If `true`, egui is currently listening on text input (e.g. typing text in a [`crate::TextEdit`]).
2639    pub fn wants_keyboard_input(&self) -> bool {
2640        self.memory(|m| m.focused().is_some())
2641    }
2642
2643    /// Highlight this widget, to make it look like it is hovered, even if it isn't.
2644    ///
2645    /// If you call this after the widget has been fully rendered,
2646    /// then it won't be highlighted until the next ui pass.
2647    ///
2648    /// See also [`Response::highlight`].
2649    pub fn highlight_widget(&self, id: Id) {
2650        self.pass_state_mut(|fs| fs.highlight_next_pass.insert(id));
2651    }
2652
2653    /// Is an egui context menu open?
2654    pub fn is_context_menu_open(&self) -> bool {
2655        self.data(|d| {
2656            d.get_temp::<crate::menu::BarState>(menu::CONTEXT_MENU_ID_STR.into())
2657                .map_or(false, |state| state.has_root())
2658        })
2659    }
2660}
2661
2662// Ergonomic methods to forward some calls often used in 'if let' without holding the borrow
2663impl Context {
2664    /// Latest reported pointer position.
2665    ///
2666    /// When tapping a touch screen, this will be `None`.
2667    #[inline(always)]
2668    pub fn pointer_latest_pos(&self) -> Option<Pos2> {
2669        self.input(|i| i.pointer.latest_pos())
2670    }
2671
2672    /// If it is a good idea to show a tooltip, where is pointer?
2673    #[inline(always)]
2674    pub fn pointer_hover_pos(&self) -> Option<Pos2> {
2675        self.input(|i| i.pointer.hover_pos())
2676    }
2677
2678    /// If you detect a click or drag and wants to know where it happened, use this.
2679    ///
2680    /// Latest position of the mouse, but ignoring any [`crate::Event::PointerGone`]
2681    /// if there were interactions this pass.
2682    /// When tapping a touch screen, this will be the location of the touch.
2683    #[inline(always)]
2684    pub fn pointer_interact_pos(&self) -> Option<Pos2> {
2685        self.input(|i| i.pointer.interact_pos())
2686    }
2687
2688    /// Calls [`InputState::multi_touch`].
2689    pub fn multi_touch(&self) -> Option<MultiTouchInfo> {
2690        self.input(|i| i.multi_touch())
2691    }
2692}
2693
2694impl Context {
2695    /// Transform the graphics of the given layer.
2696    ///
2697    /// This will also affect input.
2698    /// The direction of the given transform is "into the global coordinate system".
2699    ///
2700    /// This is a sticky setting, remembered from one frame to the next.
2701    ///
2702    /// Can be used to implement pan and zoom (see relevant demo).
2703    ///
2704    /// For a temporary transform, use [`Self::transform_layer_shapes`] instead.
2705    pub fn set_transform_layer(&self, layer_id: LayerId, transform: TSTransform) {
2706        self.memory_mut(|m| {
2707            if transform == TSTransform::IDENTITY {
2708                m.to_global.remove(&layer_id)
2709            } else {
2710                m.to_global.insert(layer_id, transform)
2711            }
2712        });
2713    }
2714
2715    /// Return how to transform the graphics of the given layer into the global coordinate system.
2716    ///
2717    /// Set this with [`Self::layer_transform_to_global`].
2718    pub fn layer_transform_to_global(&self, layer_id: LayerId) -> Option<TSTransform> {
2719        self.memory(|m| m.to_global.get(&layer_id).copied())
2720    }
2721
2722    /// Return how to transform the graphics of the global coordinate system into the local coordinate system of the given layer.
2723    ///
2724    /// This returns the inverse of [`Self::layer_transform_to_global`].
2725    pub fn layer_transform_from_global(&self, layer_id: LayerId) -> Option<TSTransform> {
2726        self.layer_transform_to_global(layer_id)
2727            .map(|t| t.inverse())
2728    }
2729
2730    /// Move all the graphics at the given layer.
2731    ///
2732    /// Is used to implement drag-and-drop preview.
2733    ///
2734    /// This only applied to the existing graphics at the layer, not to new graphics added later.
2735    ///
2736    /// For a persistent transform, use [`Self::set_transform_layer`] instead.
2737    #[deprecated = "Use `transform_layer_shapes` instead"]
2738    pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) {
2739        if delta != Vec2::ZERO {
2740            let transform = emath::TSTransform::from_translation(delta);
2741            self.transform_layer_shapes(layer_id, transform);
2742        }
2743    }
2744
2745    /// Transform all the graphics at the given layer.
2746    ///
2747    /// Is used to implement drag-and-drop preview.
2748    ///
2749    /// This only applied to the existing graphics at the layer, not to new graphics added later.
2750    ///
2751    /// For a persistent transform, use [`Self::set_transform_layer`] instead.
2752    pub fn transform_layer_shapes(&self, layer_id: LayerId, transform: TSTransform) {
2753        if transform != TSTransform::IDENTITY {
2754            self.graphics_mut(|g| g.entry(layer_id).transform(transform));
2755        }
2756    }
2757
2758    /// Top-most layer at the given position.
2759    pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> {
2760        self.memory(|mem| mem.layer_id_at(pos))
2761    }
2762
2763    /// Moves the given area to the top in its [`Order`].
2764    ///
2765    /// [`crate::Area`]:s and [`crate::Window`]:s also do this automatically when being clicked on or interacted with.
2766    pub fn move_to_top(&self, layer_id: LayerId) {
2767        self.memory_mut(|mem| mem.areas_mut().move_to_top(layer_id));
2768    }
2769
2770    /// Mark the `child` layer as a sublayer of `parent`.
2771    ///
2772    /// Sublayers are moved directly above the parent layer at the end of the frame. This is mainly
2773    /// intended for adding a new [`crate::Area`] inside a [`crate::Window`].
2774    ///
2775    /// This currently only supports one level of nesting. If `parent` is a sublayer of another
2776    /// layer, the behavior is unspecified.
2777    pub fn set_sublayer(&self, parent: LayerId, child: LayerId) {
2778        self.memory_mut(|mem| mem.areas_mut().set_sublayer(parent, child));
2779    }
2780
2781    /// Retrieve the [`LayerId`] of the top level windows.
2782    pub fn top_layer_id(&self) -> Option<LayerId> {
2783        self.memory(|mem| mem.areas().top_layer_id(Order::Middle))
2784    }
2785
2786    /// Does the given rectangle contain the mouse pointer?
2787    ///
2788    /// Will return false if some other area is covering the given layer.
2789    ///
2790    /// The given rectangle is assumed to have been clipped by its parent clip rect.
2791    ///
2792    /// See also [`Response::contains_pointer`].
2793    pub fn rect_contains_pointer(&self, layer_id: LayerId, rect: Rect) -> bool {
2794        let rect = if let Some(to_global) = self.layer_transform_to_global(layer_id) {
2795            to_global * rect
2796        } else {
2797            rect
2798        };
2799        if !rect.is_positive() {
2800            return false;
2801        }
2802
2803        let pointer_pos = self.input(|i| i.pointer.interact_pos());
2804        let Some(pointer_pos) = pointer_pos else {
2805            return false;
2806        };
2807
2808        if !rect.contains(pointer_pos) {
2809            return false;
2810        }
2811
2812        if self.layer_id_at(pointer_pos) != Some(layer_id) {
2813            return false;
2814        }
2815
2816        true
2817    }
2818
2819    // ---------------------------------------------------------------------
2820
2821    /// Whether or not to debug widget layout on hover.
2822    #[cfg(debug_assertions)]
2823    pub fn debug_on_hover(&self) -> bool {
2824        self.options(|opt| opt.style().debug.debug_on_hover)
2825    }
2826
2827    /// Turn on/off whether or not to debug widget layout on hover.
2828    #[cfg(debug_assertions)]
2829    pub fn set_debug_on_hover(&self, debug_on_hover: bool) {
2830        self.all_styles_mut(|style| style.debug.debug_on_hover = debug_on_hover);
2831    }
2832}
2833
2834/// ## Animation
2835impl Context {
2836    /// Returns a value in the range [0, 1], to indicate "how on" this thing is.
2837    ///
2838    /// The first time called it will return `if value { 1.0 } else { 0.0 }`
2839    /// Calling this with `value = true` will always yield a number larger than zero, quickly going towards one.
2840    /// Calling this with `value = false` will always yield a number less than one, quickly going towards zero.
2841    ///
2842    /// The function will call [`Self::request_repaint()`] when appropriate.
2843    ///
2844    /// The animation time is taken from [`Style::animation_time`].
2845    #[track_caller] // To track repaint cause
2846    pub fn animate_bool(&self, id: Id, value: bool) -> f32 {
2847        let animation_time = self.style().animation_time;
2848        self.animate_bool_with_time_and_easing(id, value, animation_time, emath::easing::linear)
2849    }
2850
2851    /// Like [`Self::animate_bool`], but uses an easing function that makes the value move
2852    /// quickly in the beginning and slow down towards the end.
2853    ///
2854    /// The exact easing function may come to change in future versions of egui.
2855    #[track_caller] // To track repaint cause
2856    pub fn animate_bool_responsive(&self, id: Id, value: bool) -> f32 {
2857        self.animate_bool_with_easing(id, value, emath::easing::cubic_out)
2858    }
2859
2860    /// Like [`Self::animate_bool`] but allows you to control the easing function.
2861    #[track_caller] // To track repaint cause
2862    pub fn animate_bool_with_easing(&self, id: Id, value: bool, easing: fn(f32) -> f32) -> f32 {
2863        let animation_time = self.style().animation_time;
2864        self.animate_bool_with_time_and_easing(id, value, animation_time, easing)
2865    }
2866
2867    /// Like [`Self::animate_bool`] but allows you to control the animation time.
2868    #[track_caller] // To track repaint cause
2869    pub fn animate_bool_with_time(&self, id: Id, target_value: bool, animation_time: f32) -> f32 {
2870        self.animate_bool_with_time_and_easing(
2871            id,
2872            target_value,
2873            animation_time,
2874            emath::easing::linear,
2875        )
2876    }
2877
2878    /// Like [`Self::animate_bool`] but allows you to control the animation time and easing function.
2879    ///
2880    /// Use e.g. [`emath::easing::quadratic_out`]
2881    /// for a responsive start and a slow end.
2882    ///
2883    /// The easing function flips when `target_value` is `false`,
2884    /// so that when going back towards 0.0, we get
2885    #[track_caller] // To track repaint cause
2886    pub fn animate_bool_with_time_and_easing(
2887        &self,
2888        id: Id,
2889        target_value: bool,
2890        animation_time: f32,
2891        easing: fn(f32) -> f32,
2892    ) -> f32 {
2893        let animated_value = self.write(|ctx| {
2894            ctx.animation_manager.animate_bool(
2895                &ctx.viewports.entry(ctx.viewport_id()).or_default().input,
2896                animation_time,
2897                id,
2898                target_value,
2899            )
2900        });
2901
2902        let animation_in_progress = 0.0 < animated_value && animated_value < 1.0;
2903        if animation_in_progress {
2904            self.request_repaint();
2905        }
2906
2907        if target_value {
2908            easing(animated_value)
2909        } else {
2910            1.0 - easing(1.0 - animated_value)
2911        }
2912    }
2913
2914    /// Smoothly animate an `f32` value.
2915    ///
2916    /// At the first call the value is written to memory.
2917    /// When it is called with a new value, it linearly interpolates to it in the given time.
2918    #[track_caller] // To track repaint cause
2919    pub fn animate_value_with_time(&self, id: Id, target_value: f32, animation_time: f32) -> f32 {
2920        let animated_value = self.write(|ctx| {
2921            ctx.animation_manager.animate_value(
2922                &ctx.viewports.entry(ctx.viewport_id()).or_default().input,
2923                animation_time,
2924                id,
2925                target_value,
2926            )
2927        });
2928        let animation_in_progress = animated_value != target_value;
2929        if animation_in_progress {
2930            self.request_repaint();
2931        }
2932
2933        animated_value
2934    }
2935
2936    /// Clear memory of any animations.
2937    pub fn clear_animations(&self) {
2938        self.write(|ctx| ctx.animation_manager = Default::default());
2939    }
2940}
2941
2942impl Context {
2943    /// Show a ui for settings (style and tessellation options).
2944    pub fn settings_ui(&self, ui: &mut Ui) {
2945        let prev_options = self.options(|o| o.clone());
2946        let mut options = prev_options.clone();
2947
2948        ui.collapsing("🔠 Font tweak", |ui| {
2949            self.fonts_tweak_ui(ui);
2950        });
2951
2952        options.ui(ui);
2953
2954        if options != prev_options {
2955            self.options_mut(move |o| *o = options);
2956        }
2957    }
2958
2959    fn fonts_tweak_ui(&self, ui: &mut Ui) {
2960        let mut font_definitions = self.write(|ctx| ctx.font_definitions.clone());
2961        let mut changed = false;
2962
2963        for (name, data) in &mut font_definitions.font_data {
2964            ui.collapsing(name, |ui| {
2965                let mut tweak = data.tweak;
2966                if tweak.ui(ui).changed() {
2967                    Arc::make_mut(data).tweak = tweak;
2968                    changed = true;
2969                }
2970            });
2971        }
2972
2973        if changed {
2974            self.set_fonts(font_definitions);
2975        }
2976    }
2977
2978    /// Show the state of egui, including its input and output.
2979    pub fn inspection_ui(&self, ui: &mut Ui) {
2980        use crate::containers::CollapsingHeader;
2981
2982        ui.label(format!("Is using pointer: {}", self.is_using_pointer()))
2983            .on_hover_text(
2984                "Is egui currently using the pointer actively (e.g. dragging a slider)?",
2985            );
2986        ui.label(format!("Wants pointer input: {}", self.wants_pointer_input()))
2987            .on_hover_text("Is egui currently interested in the location of the pointer (either because it is in use, or because it is hovering over a window).");
2988        ui.label(format!(
2989            "Wants keyboard input: {}",
2990            self.wants_keyboard_input()
2991        ))
2992        .on_hover_text("Is egui currently listening for text input?");
2993        ui.label(format!(
2994            "Keyboard focus widget: {}",
2995            self.memory(|m| m.focused())
2996                .as_ref()
2997                .map(Id::short_debug_format)
2998                .unwrap_or_default()
2999        ))
3000        .on_hover_text("Is egui currently listening for text input?");
3001
3002        let pointer_pos = self
3003            .pointer_hover_pos()
3004            .map_or_else(String::new, |pos| format!("{pos:?}"));
3005        ui.label(format!("Pointer pos: {pointer_pos}"));
3006
3007        let top_layer = self
3008            .pointer_hover_pos()
3009            .and_then(|pos| self.layer_id_at(pos))
3010            .map_or_else(String::new, |layer| layer.short_debug_format());
3011        ui.label(format!("Top layer under mouse: {top_layer}"));
3012
3013        ui.add_space(16.0);
3014
3015        ui.label(format!(
3016            "There are {} text galleys in the layout cache",
3017            self.fonts(|f| f.num_galleys_in_cache())
3018        ))
3019        .on_hover_text("This is approximately the number of text strings on screen");
3020        ui.add_space(16.0);
3021
3022        CollapsingHeader::new("🔃 Repaint Causes")
3023            .default_open(false)
3024            .show(ui, |ui| {
3025                ui.set_min_height(120.0);
3026                ui.label("What caused egui to repaint:");
3027                ui.add_space(8.0);
3028                let causes = ui.ctx().repaint_causes();
3029                for cause in causes {
3030                    ui.label(cause.to_string());
3031                }
3032            });
3033
3034        CollapsingHeader::new("📥 Input")
3035            .default_open(false)
3036            .show(ui, |ui| {
3037                let input = ui.input(|i| i.clone());
3038                input.ui(ui);
3039            });
3040
3041        CollapsingHeader::new("📊 Paint stats")
3042            .default_open(false)
3043            .show(ui, |ui| {
3044                let paint_stats = self.read(|ctx| ctx.paint_stats);
3045                paint_stats.ui(ui);
3046            });
3047
3048        CollapsingHeader::new("🖼 Textures")
3049            .default_open(false)
3050            .show(ui, |ui| {
3051                self.texture_ui(ui);
3052            });
3053
3054        CollapsingHeader::new("🔠 Font texture")
3055            .default_open(false)
3056            .show(ui, |ui| {
3057                let font_image_size = self.fonts(|f| f.font_image_size());
3058                crate::introspection::font_texture_ui(ui, font_image_size);
3059            });
3060
3061        CollapsingHeader::new("Label text selection state")
3062            .default_open(false)
3063            .show(ui, |ui| {
3064                ui.label(format!(
3065                    "{:#?}",
3066                    crate::text_selection::LabelSelectionState::load(ui.ctx())
3067                ));
3068            });
3069
3070        CollapsingHeader::new("Interaction")
3071            .default_open(false)
3072            .show(ui, |ui| {
3073                let interact_widgets = self.write(|ctx| ctx.viewport().interact_widgets.clone());
3074                interact_widgets.ui(ui);
3075            });
3076    }
3077
3078    /// Show stats about the allocated textures.
3079    pub fn texture_ui(&self, ui: &mut crate::Ui) {
3080        let tex_mngr = self.tex_manager();
3081        let tex_mngr = tex_mngr.read();
3082
3083        let mut textures: Vec<_> = tex_mngr.allocated().collect();
3084        textures.sort_by_key(|(id, _)| *id);
3085
3086        let mut bytes = 0;
3087        for (_, tex) in &textures {
3088            bytes += tex.bytes_used();
3089        }
3090
3091        ui.label(format!(
3092            "{} allocated texture(s), using {:.1} MB",
3093            textures.len(),
3094            bytes as f64 * 1e-6
3095        ));
3096        let max_preview_size = vec2(48.0, 32.0);
3097
3098        ui.group(|ui| {
3099            ScrollArea::vertical()
3100                .max_height(300.0)
3101                .auto_shrink([false, true])
3102                .show(ui, |ui| {
3103                    ui.style_mut().override_text_style = Some(TextStyle::Monospace);
3104                    Grid::new("textures")
3105                        .striped(true)
3106                        .num_columns(4)
3107                        .spacing(vec2(16.0, 2.0))
3108                        .min_row_height(max_preview_size.y)
3109                        .show(ui, |ui| {
3110                            for (&texture_id, meta) in textures {
3111                                let [w, h] = meta.size;
3112
3113                                let mut size = vec2(w as f32, h as f32);
3114                                size *= (max_preview_size.x / size.x).min(1.0);
3115                                size *= (max_preview_size.y / size.y).min(1.0);
3116                                ui.image(SizedTexture::new(texture_id, size))
3117                                    .on_hover_ui(|ui| {
3118                                        // show larger on hover
3119                                        let max_size = 0.5 * ui.ctx().screen_rect().size();
3120                                        let mut size = vec2(w as f32, h as f32);
3121                                        size *= max_size.x / size.x.max(max_size.x);
3122                                        size *= max_size.y / size.y.max(max_size.y);
3123                                        ui.image(SizedTexture::new(texture_id, size));
3124                                    });
3125
3126                                ui.label(format!("{w} x {h}"));
3127                                ui.label(format!("{:.3} MB", meta.bytes_used() as f64 * 1e-6));
3128                                ui.label(format!("{:?}", meta.name));
3129                                ui.end_row();
3130                            }
3131                        });
3132                });
3133        });
3134    }
3135
3136    /// Shows the contents of [`Self::memory`].
3137    pub fn memory_ui(&self, ui: &mut crate::Ui) {
3138        if ui
3139            .button("Reset all")
3140            .on_hover_text("Reset all egui state")
3141            .clicked()
3142        {
3143            self.memory_mut(|mem| *mem = Default::default());
3144        }
3145
3146        let (num_state, num_serialized) = self.data(|d| (d.len(), d.count_serialized()));
3147        ui.label(format!(
3148            "{num_state} widget states stored (of which {num_serialized} are serialized)."
3149        ));
3150
3151        ui.horizontal(|ui| {
3152            ui.label(format!(
3153                "{} areas (panels, windows, popups, …)",
3154                self.memory(|mem| mem.areas().count())
3155            ));
3156            if ui.button("Reset").clicked() {
3157                self.memory_mut(|mem| *mem.areas_mut() = Default::default());
3158            }
3159        });
3160        ui.indent("layers", |ui| {
3161            ui.label("Layers, ordered back to front.");
3162            let layers_ids: Vec<LayerId> = self.memory(|mem| mem.areas().order().to_vec());
3163            for layer_id in layers_ids {
3164                if let Some(area) = AreaState::load(self, layer_id.id) {
3165                    let is_visible = self.memory(|mem| mem.areas().is_visible(&layer_id));
3166                    if !is_visible {
3167                        continue;
3168                    }
3169                    let text = format!("{} - {:?}", layer_id.short_debug_format(), area.rect(),);
3170                    // TODO(emilk): `Sense::hover_highlight()`
3171                    let response =
3172                        ui.add(Label::new(RichText::new(text).monospace()).sense(Sense::click()));
3173                    if response.hovered && is_visible {
3174                        ui.ctx()
3175                            .debug_painter()
3176                            .debug_rect(area.rect(), Color32::RED, "");
3177                    }
3178                } else {
3179                    ui.monospace(layer_id.short_debug_format());
3180                }
3181            }
3182        });
3183
3184        ui.horizontal(|ui| {
3185            ui.label(format!(
3186                "{} collapsing headers",
3187                self.data(|d| d.count::<containers::collapsing_header::InnerState>())
3188            ));
3189            if ui.button("Reset").clicked() {
3190                self.data_mut(|d| d.remove_by_type::<containers::collapsing_header::InnerState>());
3191            }
3192        });
3193
3194        ui.horizontal(|ui| {
3195            ui.label(format!(
3196                "{} menu bars",
3197                self.data(|d| d.count::<menu::BarState>())
3198            ));
3199            if ui.button("Reset").clicked() {
3200                self.data_mut(|d| d.remove_by_type::<menu::BarState>());
3201            }
3202        });
3203
3204        ui.horizontal(|ui| {
3205            ui.label(format!(
3206                "{} scroll areas",
3207                self.data(|d| d.count::<scroll_area::State>())
3208            ));
3209            if ui.button("Reset").clicked() {
3210                self.data_mut(|d| d.remove_by_type::<scroll_area::State>());
3211            }
3212        });
3213
3214        ui.horizontal(|ui| {
3215            ui.label(format!(
3216                "{} resize areas",
3217                self.data(|d| d.count::<resize::State>())
3218            ));
3219            if ui.button("Reset").clicked() {
3220                self.data_mut(|d| d.remove_by_type::<resize::State>());
3221            }
3222        });
3223
3224        ui.shrink_width_to_current(); // don't let the text below grow this window wider
3225        ui.label("NOTE: the position of this window cannot be reset from within itself.");
3226
3227        ui.collapsing("Interaction", |ui| {
3228            let interaction = self.memory(|mem| mem.interaction().clone());
3229            interaction.ui(ui);
3230        });
3231    }
3232}
3233
3234impl Context {
3235    /// Edit the [`Style`].
3236    pub fn style_ui(&self, ui: &mut Ui, theme: Theme) {
3237        let mut style: Style = (*self.style_of(theme)).clone();
3238        style.ui(ui);
3239        self.set_style_of(theme, style);
3240    }
3241}
3242
3243/// ## Accessibility
3244impl Context {
3245    /// Call the provided function with the given ID pushed on the stack of
3246    /// parent IDs for accessibility purposes. If the `accesskit` feature
3247    /// is disabled or if AccessKit support is not active for this frame,
3248    /// the function is still called, but with no other effect.
3249    ///
3250    /// No locks are held while the given closure is called.
3251    #[allow(clippy::unused_self, clippy::let_and_return)]
3252    #[inline]
3253    pub fn with_accessibility_parent<R>(&self, _id: Id, f: impl FnOnce() -> R) -> R {
3254        // TODO(emilk): this isn't thread-safe - another thread can call this function between the push/pop calls
3255        #[cfg(feature = "accesskit")]
3256        self.pass_state_mut(|fs| {
3257            if let Some(state) = fs.accesskit_state.as_mut() {
3258                state.parent_stack.push(_id);
3259            }
3260        });
3261
3262        let result = f();
3263
3264        #[cfg(feature = "accesskit")]
3265        self.pass_state_mut(|fs| {
3266            if let Some(state) = fs.accesskit_state.as_mut() {
3267                assert_eq!(state.parent_stack.pop(), Some(_id));
3268            }
3269        });
3270
3271        result
3272    }
3273
3274    /// If AccessKit support is active for the current frame, get or create
3275    /// a node builder with the specified ID and return a mutable reference to it.
3276    /// For newly created nodes, the parent is the node with the ID at the top
3277    /// of the stack managed by [`Context::with_accessibility_parent`].
3278    ///
3279    /// The `Context` lock is held while the given closure is called!
3280    ///
3281    /// Returns `None` if acesskit is off.
3282    // TODO(emilk): consider making both read-only and read-write versions
3283    #[cfg(feature = "accesskit")]
3284    pub fn accesskit_node_builder<R>(
3285        &self,
3286        id: Id,
3287        writer: impl FnOnce(&mut accesskit::Node) -> R,
3288    ) -> Option<R> {
3289        self.write(|ctx| {
3290            ctx.viewport()
3291                .this_pass
3292                .accesskit_state
3293                .is_some()
3294                .then(|| ctx.accesskit_node_builder(id))
3295                .map(writer)
3296        })
3297    }
3298
3299    /// Enable generation of AccessKit tree updates in all future frames.
3300    #[cfg(feature = "accesskit")]
3301    pub fn enable_accesskit(&self) {
3302        self.write(|ctx| ctx.is_accesskit_enabled = true);
3303    }
3304
3305    /// Disable generation of AccessKit tree updates in all future frames.
3306    #[cfg(feature = "accesskit")]
3307    pub fn disable_accesskit(&self) {
3308        self.write(|ctx| ctx.is_accesskit_enabled = false);
3309    }
3310}
3311
3312/// ## Image loading
3313impl Context {
3314    /// Associate some static bytes with a `uri`.
3315    ///
3316    /// The same `uri` may be passed to [`Ui::image`] later to load the bytes as an image.
3317    ///
3318    /// By convention, the `uri` should start with `bytes://`.
3319    /// Following that convention will lead to better error messages.
3320    pub fn include_bytes(&self, uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) {
3321        self.loaders().include.insert(uri, bytes);
3322    }
3323
3324    /// Returns `true` if the chain of bytes, image, or texture loaders
3325    /// contains a loader with the given `id`.
3326    pub fn is_loader_installed(&self, id: &str) -> bool {
3327        let loaders = self.loaders();
3328
3329        loaders.bytes.lock().iter().any(|l| l.id() == id)
3330            || loaders.image.lock().iter().any(|l| l.id() == id)
3331            || loaders.texture.lock().iter().any(|l| l.id() == id)
3332    }
3333
3334    /// Add a new bytes loader.
3335    ///
3336    /// It will be tried first, before any already installed loaders.
3337    ///
3338    /// See [`load`] for more information.
3339    pub fn add_bytes_loader(&self, loader: Arc<dyn load::BytesLoader + Send + Sync + 'static>) {
3340        self.loaders().bytes.lock().push(loader);
3341    }
3342
3343    /// Add a new image loader.
3344    ///
3345    /// It will be tried first, before any already installed loaders.
3346    ///
3347    /// See [`load`] for more information.
3348    pub fn add_image_loader(&self, loader: Arc<dyn load::ImageLoader + Send + Sync + 'static>) {
3349        self.loaders().image.lock().push(loader);
3350    }
3351
3352    /// Add a new texture loader.
3353    ///
3354    /// It will be tried first, before any already installed loaders.
3355    ///
3356    /// See [`load`] for more information.
3357    pub fn add_texture_loader(&self, loader: Arc<dyn load::TextureLoader + Send + Sync + 'static>) {
3358        self.loaders().texture.lock().push(loader);
3359    }
3360
3361    /// Release all memory and textures related to the given image URI.
3362    ///
3363    /// If you attempt to load the image again, it will be reloaded from scratch.
3364    pub fn forget_image(&self, uri: &str) {
3365        use load::BytesLoader as _;
3366
3367        profiling::function_scope!();
3368
3369        let loaders = self.loaders();
3370
3371        loaders.include.forget(uri);
3372        for loader in loaders.bytes.lock().iter() {
3373            loader.forget(uri);
3374        }
3375        for loader in loaders.image.lock().iter() {
3376            loader.forget(uri);
3377        }
3378        for loader in loaders.texture.lock().iter() {
3379            loader.forget(uri);
3380        }
3381    }
3382
3383    /// Release all memory and textures related to images used in [`Ui::image`] or [`crate::Image`].
3384    ///
3385    /// If you attempt to load any images again, they will be reloaded from scratch.
3386    pub fn forget_all_images(&self) {
3387        use load::BytesLoader as _;
3388
3389        profiling::function_scope!();
3390
3391        let loaders = self.loaders();
3392
3393        loaders.include.forget_all();
3394        for loader in loaders.bytes.lock().iter() {
3395            loader.forget_all();
3396        }
3397        for loader in loaders.image.lock().iter() {
3398            loader.forget_all();
3399        }
3400        for loader in loaders.texture.lock().iter() {
3401            loader.forget_all();
3402        }
3403    }
3404
3405    /// Try loading the bytes from the given uri using any available bytes loaders.
3406    ///
3407    /// Loaders are expected to cache results, so that this call is immediate-mode safe.
3408    ///
3409    /// This calls the loaders one by one in the order in which they were registered.
3410    /// If a loader returns [`LoadError::NotSupported`][not_supported],
3411    /// then the next loader is called. This process repeats until all loaders have
3412    /// been exhausted, at which point this returns [`LoadError::NotSupported`][not_supported].
3413    ///
3414    /// # Errors
3415    /// This may fail with:
3416    /// - [`LoadError::NotSupported`][not_supported] if none of the registered loaders support loading the given `uri`.
3417    /// - [`LoadError::Loading`][custom] if one of the loaders _does_ support loading the `uri`, but the loading process failed.
3418    ///
3419    /// ⚠ May deadlock if called from within a `BytesLoader`!
3420    ///
3421    /// [not_supported]: crate::load::LoadError::NotSupported
3422    /// [custom]: crate::load::LoadError::Loading
3423    pub fn try_load_bytes(&self, uri: &str) -> load::BytesLoadResult {
3424        profiling::function_scope!(uri);
3425
3426        let loaders = self.loaders();
3427        let bytes_loaders = loaders.bytes.lock();
3428
3429        // Try most recently added loaders first (hence `.rev()`)
3430        for loader in bytes_loaders.iter().rev() {
3431            match loader.load(self, uri) {
3432                Err(load::LoadError::NotSupported) => continue,
3433                result => return result,
3434            }
3435        }
3436
3437        Err(load::LoadError::NoMatchingBytesLoader)
3438    }
3439
3440    /// Try loading the image from the given uri using any available image loaders.
3441    ///
3442    /// Loaders are expected to cache results, so that this call is immediate-mode safe.
3443    ///
3444    /// This calls the loaders one by one in the order in which they were registered.
3445    /// If a loader returns [`LoadError::NotSupported`][not_supported],
3446    /// then the next loader is called. This process repeats until all loaders have
3447    /// been exhausted, at which point this returns [`LoadError::NotSupported`][not_supported].
3448    ///
3449    /// # Errors
3450    /// This may fail with:
3451    /// - [`LoadError::NoImageLoaders`][no_image_loaders] if tbere are no registered image loaders.
3452    /// - [`LoadError::NotSupported`][not_supported] if none of the registered loaders support loading the given `uri`.
3453    /// - [`LoadError::Loading`][custom] if one of the loaders _does_ support loading the `uri`, but the loading process failed.
3454    ///
3455    /// ⚠ May deadlock if called from within an `ImageLoader`!
3456    ///
3457    /// [no_image_loaders]: crate::load::LoadError::NoImageLoaders
3458    /// [not_supported]: crate::load::LoadError::NotSupported
3459    /// [custom]: crate::load::LoadError::Loading
3460    pub fn try_load_image(&self, uri: &str, size_hint: load::SizeHint) -> load::ImageLoadResult {
3461        profiling::function_scope!(uri);
3462
3463        let loaders = self.loaders();
3464        let image_loaders = loaders.image.lock();
3465        if image_loaders.is_empty() {
3466            return Err(load::LoadError::NoImageLoaders);
3467        }
3468
3469        let mut format = None;
3470
3471        // Try most recently added loaders first (hence `.rev()`)
3472        for loader in image_loaders.iter().rev() {
3473            match loader.load(self, uri, size_hint) {
3474                Err(load::LoadError::NotSupported) => continue,
3475                Err(load::LoadError::FormatNotSupported { detected_format }) => {
3476                    format = format.or(detected_format);
3477                    continue;
3478                }
3479                result => return result,
3480            }
3481        }
3482
3483        Err(load::LoadError::NoMatchingImageLoader {
3484            detected_format: format,
3485        })
3486    }
3487
3488    /// Try loading the texture from the given uri using any available texture loaders.
3489    ///
3490    /// Loaders are expected to cache results, so that this call is immediate-mode safe.
3491    ///
3492    /// This calls the loaders one by one in the order in which they were registered.
3493    /// If a loader returns [`LoadError::NotSupported`][not_supported],
3494    /// then the next loader is called. This process repeats until all loaders have
3495    /// been exhausted, at which point this returns [`LoadError::NotSupported`][not_supported].
3496    ///
3497    /// # Errors
3498    /// This may fail with:
3499    /// - [`LoadError::NotSupported`][not_supported] if none of the registered loaders support loading the given `uri`.
3500    /// - [`LoadError::Loading`][custom] if one of the loaders _does_ support loading the `uri`, but the loading process failed.
3501    ///
3502    /// ⚠ May deadlock if called from within a `TextureLoader`!
3503    ///
3504    /// [not_supported]: crate::load::LoadError::NotSupported
3505    /// [custom]: crate::load::LoadError::Loading
3506    pub fn try_load_texture(
3507        &self,
3508        uri: &str,
3509        texture_options: TextureOptions,
3510        size_hint: load::SizeHint,
3511    ) -> load::TextureLoadResult {
3512        profiling::function_scope!(uri);
3513
3514        let loaders = self.loaders();
3515        let texture_loaders = loaders.texture.lock();
3516
3517        // Try most recently added loaders first (hence `.rev()`)
3518        for loader in texture_loaders.iter().rev() {
3519            match loader.load(self, uri, texture_options, size_hint) {
3520                Err(load::LoadError::NotSupported) => continue,
3521                result => return result,
3522            }
3523        }
3524
3525        Err(load::LoadError::NoMatchingTextureLoader)
3526    }
3527
3528    /// The loaders of bytes, images, and textures.
3529    pub fn loaders(&self) -> Arc<Loaders> {
3530        profiling::function_scope!();
3531        self.read(|this| this.loaders.clone())
3532    }
3533}
3534
3535/// ## Viewports
3536impl Context {
3537    /// Return the `ViewportId` of the current viewport.
3538    ///
3539    /// If this is the root viewport, this will return [`ViewportId::ROOT`].
3540    ///
3541    /// Don't use this outside of `Self::run`, or after `Self::end_pass`.
3542    pub fn viewport_id(&self) -> ViewportId {
3543        self.read(|ctx| ctx.viewport_id())
3544    }
3545
3546    /// Return the `ViewportId` of his parent.
3547    ///
3548    /// If this is the root viewport, this will return [`ViewportId::ROOT`].
3549    ///
3550    /// Don't use this outside of `Self::run`, or after `Self::end_pass`.
3551    pub fn parent_viewport_id(&self) -> ViewportId {
3552        self.read(|ctx| ctx.parent_viewport_id())
3553    }
3554
3555    /// Read the state of the current viewport.
3556    pub fn viewport<R>(&self, reader: impl FnOnce(&ViewportState) -> R) -> R {
3557        self.write(|ctx| reader(ctx.viewport()))
3558    }
3559
3560    /// Read the state of a specific current viewport.
3561    pub fn viewport_for<R>(
3562        &self,
3563        viewport_id: ViewportId,
3564        reader: impl FnOnce(&ViewportState) -> R,
3565    ) -> R {
3566        self.write(|ctx| reader(ctx.viewport_for(viewport_id)))
3567    }
3568
3569    /// For integrations: Set this to render a sync viewport.
3570    ///
3571    /// This will only set the callback for the current thread,
3572    /// which most likely should be the main thread.
3573    ///
3574    /// When an immediate viewport is created with [`Self::show_viewport_immediate`] it will be rendered by this function.
3575    ///
3576    /// When called, the integration needs to:
3577    /// * Check if there already is a window for this viewport id, and if not open one
3578    /// * Set the window attributes (position, size, …) based on [`ImmediateViewport::builder`].
3579    /// * Call [`Context::run`] with [`ImmediateViewport::viewport_ui_cb`].
3580    /// * Handle the output from [`Context::run`], including rendering
3581    #[allow(clippy::unused_self)]
3582    pub fn set_immediate_viewport_renderer(
3583        callback: impl for<'a> Fn(&Self, ImmediateViewport<'a>) + 'static,
3584    ) {
3585        let callback = Box::new(callback);
3586        IMMEDIATE_VIEWPORT_RENDERER.with(|render_sync| {
3587            render_sync.replace(Some(callback));
3588        });
3589    }
3590
3591    /// If `true`, [`Self::show_viewport_deferred`] and [`Self::show_viewport_immediate`] will
3592    /// embed the new viewports inside the existing one, instead of spawning a new native window.
3593    ///
3594    /// `eframe` sets this to `false` on supported platforms, but the default value is `true`.
3595    pub fn embed_viewports(&self) -> bool {
3596        self.read(|ctx| ctx.embed_viewports)
3597    }
3598
3599    /// If `true`, [`Self::show_viewport_deferred`] and [`Self::show_viewport_immediate`] will
3600    /// embed the new viewports inside the existing one, instead of spawning a new native window.
3601    ///
3602    /// `eframe` sets this to `false` on supported platforms, but the default value is `true`.
3603    pub fn set_embed_viewports(&self, value: bool) {
3604        self.write(|ctx| ctx.embed_viewports = value);
3605    }
3606
3607    /// Send a command to the current viewport.
3608    ///
3609    /// This lets you affect the current viewport, e.g. resizing the window.
3610    pub fn send_viewport_cmd(&self, command: ViewportCommand) {
3611        self.send_viewport_cmd_to(self.viewport_id(), command);
3612    }
3613
3614    /// Send a command to a specific viewport.
3615    ///
3616    /// This lets you affect another viewport, e.g. resizing its window.
3617    pub fn send_viewport_cmd_to(&self, id: ViewportId, command: ViewportCommand) {
3618        self.request_repaint_of(id);
3619
3620        if command.requires_parent_repaint() {
3621            self.request_repaint_of(self.parent_viewport_id());
3622        }
3623
3624        self.write(|ctx| ctx.viewport_for(id).commands.push(command));
3625    }
3626
3627    /// Show a deferred viewport, creating a new native window, if possible.
3628    ///
3629    /// The given id must be unique for each viewport.
3630    ///
3631    /// You need to call this each pass when the child viewport should exist.
3632    ///
3633    /// You can check if the user wants to close the viewport by checking the
3634    /// [`crate::ViewportInfo::close_requested`] flags found in [`crate::InputState::viewport`].
3635    ///
3636    /// The given callback will be called whenever the child viewport needs repainting,
3637    /// e.g. on an event or when [`Self::request_repaint`] is called.
3638    /// This means it may be called multiple times, for instance while the
3639    /// parent viewport (the caller) is sleeping but the child viewport is animating.
3640    ///
3641    /// You will need to wrap your viewport state in an `Arc<RwLock<T>>` or `Arc<Mutex<T>>`.
3642    /// When this is called again with the same id in `ViewportBuilder` the render function for that viewport will be updated.
3643    ///
3644    /// You can also use [`Self::show_viewport_immediate`], which uses a simpler `FnOnce`
3645    /// with no need for `Send` or `Sync`. The downside is that it will require
3646    /// the parent viewport (the caller) to repaint anytime the child is repainted,
3647    /// and vice versa.
3648    ///
3649    /// If [`Context::embed_viewports`] is `true` (e.g. if the current egui
3650    /// backend does not support multiple viewports), the given callback
3651    /// will be called immediately, embedding the new viewport in the current one.
3652    /// You can check this with the [`ViewportClass`] given in the callback.
3653    /// If you find [`ViewportClass::Embedded`], you need to create a new [`crate::Window`] for you content.
3654    ///
3655    /// See [`crate::viewport`] for more information about viewports.
3656    pub fn show_viewport_deferred(
3657        &self,
3658        new_viewport_id: ViewportId,
3659        viewport_builder: ViewportBuilder,
3660        viewport_ui_cb: impl Fn(&Self, ViewportClass) + Send + Sync + 'static,
3661    ) {
3662        profiling::function_scope!();
3663
3664        if self.embed_viewports() {
3665            viewport_ui_cb(self, ViewportClass::Embedded);
3666        } else {
3667            self.write(|ctx| {
3668                ctx.viewport_parents
3669                    .insert(new_viewport_id, ctx.viewport_id());
3670
3671                let viewport = ctx.viewports.entry(new_viewport_id).or_default();
3672                viewport.class = ViewportClass::Deferred;
3673                viewport.builder = viewport_builder;
3674                viewport.used = true;
3675                viewport.viewport_ui_cb = Some(Arc::new(move |ctx| {
3676                    (viewport_ui_cb)(ctx, ViewportClass::Deferred);
3677                }));
3678            });
3679        }
3680    }
3681
3682    /// Show an immediate viewport, creating a new native window, if possible.
3683    ///
3684    /// This is the easier type of viewport to use, but it is less performant
3685    /// at it requires both parent and child to repaint if any one of them needs repainting,
3686    /// which effectively produce double work for two viewports, and triple work for three viewports, etc.
3687    /// To avoid this, use [`Self::show_viewport_deferred`] instead.
3688    ///
3689    /// The given id must be unique for each viewport.
3690    ///
3691    /// You need to call this each pass when the child viewport should exist.
3692    ///
3693    /// You can check if the user wants to close the viewport by checking the
3694    /// [`crate::ViewportInfo::close_requested`] flags found in [`crate::InputState::viewport`].
3695    ///
3696    /// The given ui function will be called immediately.
3697    /// This may only be called on the main thread.
3698    /// This call will pause the current viewport and render the child viewport in its own window.
3699    /// This means that the child viewport will not be repainted when the parent viewport is repainted, and vice versa.
3700    ///
3701    /// If [`Context::embed_viewports`] is `true` (e.g. if the current egui
3702    /// backend does not support multiple viewports), the given callback
3703    /// will be called immediately, embedding the new viewport in the current one.
3704    /// You can check this with the [`ViewportClass`] given in the callback.
3705    /// If you find [`ViewportClass::Embedded`], you need to create a new [`crate::Window`] for you content.
3706    ///
3707    /// See [`crate::viewport`] for more information about viewports.
3708    pub fn show_viewport_immediate<T>(
3709        &self,
3710        new_viewport_id: ViewportId,
3711        builder: ViewportBuilder,
3712        mut viewport_ui_cb: impl FnMut(&Self, ViewportClass) -> T,
3713    ) -> T {
3714        profiling::function_scope!();
3715
3716        if self.embed_viewports() {
3717            return viewport_ui_cb(self, ViewportClass::Embedded);
3718        }
3719
3720        IMMEDIATE_VIEWPORT_RENDERER.with(|immediate_viewport_renderer| {
3721            let immediate_viewport_renderer = immediate_viewport_renderer.borrow();
3722            let Some(immediate_viewport_renderer) = immediate_viewport_renderer.as_ref() else {
3723                // This egui backend does not support multiple viewports.
3724                return viewport_ui_cb(self, ViewportClass::Embedded);
3725            };
3726
3727            let ids = self.write(|ctx| {
3728                let parent_viewport_id = ctx.viewport_id();
3729
3730                ctx.viewport_parents
3731                    .insert(new_viewport_id, parent_viewport_id);
3732
3733                let viewport = ctx.viewports.entry(new_viewport_id).or_default();
3734                viewport.builder = builder.clone();
3735                viewport.used = true;
3736                viewport.viewport_ui_cb = None; // it is immediate
3737
3738                ViewportIdPair::from_self_and_parent(new_viewport_id, parent_viewport_id)
3739            });
3740
3741            let mut out = None;
3742            {
3743                let out = &mut out;
3744
3745                let viewport = ImmediateViewport {
3746                    ids,
3747                    builder,
3748                    viewport_ui_cb: Box::new(move |context| {
3749                        *out = Some(viewport_ui_cb(context, ViewportClass::Immediate));
3750                    }),
3751                };
3752
3753                immediate_viewport_renderer(self, viewport);
3754            }
3755
3756            out.expect(
3757                "egui backend is implemented incorrectly - the user callback was never called",
3758            )
3759        })
3760    }
3761}
3762
3763/// ## Interaction
3764impl Context {
3765    /// Read you what widgets are currently being interacted with.
3766    pub fn interaction_snapshot<R>(&self, reader: impl FnOnce(&InteractionSnapshot) -> R) -> R {
3767        self.write(|w| reader(&w.viewport().interact_widgets))
3768    }
3769
3770    /// The widget currently being dragged, if any.
3771    ///
3772    /// For widgets that sense both clicks and drags, this will
3773    /// not be set until the mouse cursor has moved a certain distance.
3774    ///
3775    /// NOTE: if the widget was released this pass, this will be `None`.
3776    /// Use [`Self::drag_stopped_id`] instead.
3777    pub fn dragged_id(&self) -> Option<Id> {
3778        self.interaction_snapshot(|i| i.dragged)
3779    }
3780
3781    /// Is this specific widget being dragged?
3782    ///
3783    /// A widget that sense both clicks and drags is only marked as "dragged"
3784    /// when the mouse has moved a bit
3785    ///
3786    /// See also: [`crate::Response::dragged`].
3787    pub fn is_being_dragged(&self, id: Id) -> bool {
3788        self.dragged_id() == Some(id)
3789    }
3790
3791    /// This widget just started being dragged this pass.
3792    ///
3793    /// The same widget should also be found in [`Self::dragged_id`].
3794    pub fn drag_started_id(&self) -> Option<Id> {
3795        self.interaction_snapshot(|i| i.drag_started)
3796    }
3797
3798    /// This widget was being dragged, but was released this pass
3799    pub fn drag_stopped_id(&self) -> Option<Id> {
3800        self.interaction_snapshot(|i| i.drag_stopped)
3801    }
3802
3803    /// Set which widget is being dragged.
3804    pub fn set_dragged_id(&self, id: Id) {
3805        self.write(|ctx| {
3806            let vp = ctx.viewport();
3807            let i = &mut vp.interact_widgets;
3808            if i.dragged != Some(id) {
3809                i.drag_stopped = i.dragged.or(i.drag_stopped);
3810                i.dragged = Some(id);
3811                i.drag_started = Some(id);
3812            }
3813
3814            ctx.memory.interaction_mut().potential_drag_id = Some(id);
3815        });
3816    }
3817
3818    /// Stop dragging any widget.
3819    pub fn stop_dragging(&self) {
3820        self.write(|ctx| {
3821            let vp = ctx.viewport();
3822            let i = &mut vp.interact_widgets;
3823            if i.dragged.is_some() {
3824                i.drag_stopped = i.dragged;
3825                i.dragged = None;
3826            }
3827
3828            ctx.memory.interaction_mut().potential_drag_id = None;
3829        });
3830    }
3831
3832    /// Is something else being dragged?
3833    ///
3834    /// Returns true if we are dragging something, but not the given widget.
3835    #[inline(always)]
3836    pub fn dragging_something_else(&self, not_this: Id) -> bool {
3837        let dragged = self.dragged_id();
3838        dragged.is_some() && dragged != Some(not_this)
3839    }
3840}
3841
3842#[test]
3843fn context_impl_send_sync() {
3844    fn assert_send_sync<T: Send + Sync>() {}
3845    assert_send_sync::<Context>();
3846}
3847
3848#[cfg(test)]
3849mod test {
3850    use super::Context;
3851
3852    #[test]
3853    fn test_single_pass() {
3854        let ctx = Context::default();
3855        ctx.options_mut(|o| o.max_passes = 1.try_into().unwrap());
3856
3857        // A single call, no request to discard:
3858        {
3859            let mut num_calls = 0;
3860            let output = ctx.run(Default::default(), |ctx| {
3861                num_calls += 1;
3862                assert_eq!(ctx.output(|o| o.num_completed_passes), 0);
3863                assert!(!ctx.output(|o| o.requested_discard()));
3864                assert!(!ctx.will_discard());
3865            });
3866            assert_eq!(num_calls, 1);
3867            assert_eq!(output.platform_output.num_completed_passes, 1);
3868            assert!(!output.platform_output.requested_discard());
3869        }
3870
3871        // A single call, with a denied request to discard:
3872        {
3873            let mut num_calls = 0;
3874            let output = ctx.run(Default::default(), |ctx| {
3875                num_calls += 1;
3876                ctx.request_discard("test");
3877                assert!(!ctx.will_discard(), "The request should have been denied");
3878            });
3879            assert_eq!(num_calls, 1);
3880            assert_eq!(output.platform_output.num_completed_passes, 1);
3881            assert!(
3882                output.platform_output.requested_discard(),
3883                "The request should be reported"
3884            );
3885            assert_eq!(
3886                output
3887                    .platform_output
3888                    .request_discard_reasons
3889                    .first()
3890                    .unwrap()
3891                    .reason,
3892                "test"
3893            );
3894        }
3895    }
3896
3897    #[test]
3898    fn test_dual_pass() {
3899        let ctx = Context::default();
3900        ctx.options_mut(|o| o.max_passes = 2.try_into().unwrap());
3901
3902        // Normal single pass:
3903        {
3904            let mut num_calls = 0;
3905            let output = ctx.run(Default::default(), |ctx| {
3906                assert_eq!(ctx.output(|o| o.num_completed_passes), 0);
3907                assert!(!ctx.output(|o| o.requested_discard()));
3908                assert!(!ctx.will_discard());
3909                num_calls += 1;
3910            });
3911            assert_eq!(num_calls, 1);
3912            assert_eq!(output.platform_output.num_completed_passes, 1);
3913            assert!(!output.platform_output.requested_discard());
3914        }
3915
3916        // Request discard once:
3917        {
3918            let mut num_calls = 0;
3919            let output = ctx.run(Default::default(), |ctx| {
3920                assert_eq!(ctx.output(|o| o.num_completed_passes), num_calls);
3921
3922                assert!(!ctx.will_discard());
3923                if num_calls == 0 {
3924                    ctx.request_discard("test");
3925                    assert!(ctx.will_discard());
3926                }
3927
3928                num_calls += 1;
3929            });
3930            assert_eq!(num_calls, 2);
3931            assert_eq!(output.platform_output.num_completed_passes, 2);
3932            assert!(
3933                !output.platform_output.requested_discard(),
3934                "The request should have been cleared when fulfilled"
3935            );
3936        }
3937
3938        // Request discard twice:
3939        {
3940            let mut num_calls = 0;
3941            let output = ctx.run(Default::default(), |ctx| {
3942                assert_eq!(ctx.output(|o| o.num_completed_passes), num_calls);
3943
3944                assert!(!ctx.will_discard());
3945                ctx.request_discard("test");
3946                if num_calls == 0 {
3947                    assert!(ctx.will_discard(), "First request granted");
3948                } else {
3949                    assert!(!ctx.will_discard(), "Second request should be denied");
3950                }
3951
3952                num_calls += 1;
3953            });
3954            assert_eq!(num_calls, 2);
3955            assert_eq!(output.platform_output.num_completed_passes, 2);
3956            assert!(
3957                output.platform_output.requested_discard(),
3958                "The unfulfilled request should be reported"
3959            );
3960        }
3961    }
3962
3963    #[test]
3964    fn test_multi_pass() {
3965        let ctx = Context::default();
3966        ctx.options_mut(|o| o.max_passes = 10.try_into().unwrap());
3967
3968        // Request discard three times:
3969        {
3970            let mut num_calls = 0;
3971            let output = ctx.run(Default::default(), |ctx| {
3972                assert_eq!(ctx.output(|o| o.num_completed_passes), num_calls);
3973
3974                assert!(!ctx.will_discard());
3975                if num_calls <= 2 {
3976                    ctx.request_discard("test");
3977                    assert!(ctx.will_discard());
3978                }
3979
3980                num_calls += 1;
3981            });
3982            assert_eq!(num_calls, 4);
3983            assert_eq!(output.platform_output.num_completed_passes, 4);
3984            assert!(
3985                !output.platform_output.requested_discard(),
3986                "The request should have been cleared when fulfilled"
3987            );
3988        }
3989    }
3990}