Put everything in Context behind the same Mutex (#1050)
* Move all interior mutability from Context to CtxRef and make it a handle * Rename `CtxRef` to `Context` * The old `Context` is now `ContextImpl` and is non-pub * Add benchmark Painter::rect Co-authored-by: Daniel Keller <dklr433@gmail.com>
This commit is contained in:
parent
225d2b506d
commit
d5673412dd
75 changed files with 550 additions and 495 deletions
|
@ -11,12 +11,21 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
|
|||
* Added `Ui::add_visible` and `Ui::add_visible_ui`.
|
||||
|
||||
### Changed 🔧
|
||||
* ⚠️ `Context::input` and `Ui::input` now locks a mutex. This can lead to a dead-lock is used in an `if let` binding!
|
||||
* `if let Some(pos) = ui.input().pointer.latest_pos()` and similar must now be rewritten on two lines, or with added `{}` around the righ-hand-side.
|
||||
* Search for this problem in your code using the regex `if let .*input`.
|
||||
* Renamed `CtxRef` to `Context` ([#1050](https://github.com/emilk/egui/pull/1050)).
|
||||
* `Context` can now be cloned and stored between frames ([#1050](https://github.com/emilk/egui/pull/1050)).
|
||||
* Renamed `Ui::visible` to `Ui::is_visible`.
|
||||
* Split `Event::Text` into `Event::Text` and `Event::Paste` ([#1058](https://github.com/emilk/egui/pull/1058)).
|
||||
|
||||
### Fixed 🐛
|
||||
* Context menu now respects the theme ([#1043](https://github.com/emilk/egui/pull/1043))
|
||||
|
||||
### Contributors 🙏
|
||||
* [danielkeller](https://github.com/danielkeller): [#1050](https://github.com/emilk/egui/pull/1050).
|
||||
|
||||
|
||||
## 0.16.1 - 2021-12-31 - Add back `CtxRef::begin_frame,end_frame`
|
||||
|
||||
### Added ⭐
|
||||
|
|
|
@ -365,6 +365,7 @@ Notable contributions by:
|
|||
* [@AlexApps99](https://github.com/AlexApps99): [`egui_glow`](https://github.com/emilk/egui/pull/685).
|
||||
* [@mankinskin](https://github.com/mankinskin): [Context menus](https://github.com/emilk/egui/pull/543).
|
||||
* [@t18b219k](https://github.com/t18b219k): [Port glow painter to web](https://github.com/emilk/egui/pull/868).
|
||||
* [@danielkeller](https://github.com/danielkeller): [`Context` refactor](https://github.com/emilk/egui/pull/1050).
|
||||
* And [many more](https://github.com/emilk/egui/graphs/contributors?type=a).
|
||||
|
||||
egui is licensed under [MIT](LICENSE-MIT) OR [Apache-2.0](LICENSE-APACHE).
|
||||
|
|
|
@ -19,7 +19,7 @@ impl epi::App for MyApp {
|
|||
|
||||
fn setup(
|
||||
&mut self,
|
||||
ctx: &egui::CtxRef,
|
||||
ctx: &egui::Context,
|
||||
_frame: &epi::Frame,
|
||||
_storage: Option<&dyn epi::Storage>,
|
||||
) {
|
||||
|
@ -51,7 +51,7 @@ impl epi::App for MyApp {
|
|||
ctx.set_fonts(fonts);
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("egui using custom fonts");
|
||||
ui.text_edit_multiline(&mut self.text);
|
||||
|
|
|
@ -13,7 +13,7 @@ impl epi::App for MyApp {
|
|||
"Native file dialogs and drag-and-drop files"
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.label("Drag-and-drop files onto the window!");
|
||||
|
||||
|
@ -57,7 +57,7 @@ impl epi::App for MyApp {
|
|||
}
|
||||
|
||||
impl MyApp {
|
||||
fn detect_files_being_dropped(&mut self, ctx: &egui::CtxRef) {
|
||||
fn detect_files_being_dropped(&mut self, ctx: &egui::Context) {
|
||||
use egui::*;
|
||||
|
||||
// Preview hovering files:
|
||||
|
|
|
@ -21,7 +21,7 @@ impl epi::App for MyApp {
|
|||
"My egui App"
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
let Self { name, age } = self;
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
|
|
|
@ -12,7 +12,7 @@ impl epi::App for MyApp {
|
|||
"Show an image with eframe/egui"
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
if self.texture.is_none() {
|
||||
// Load the image:
|
||||
let image_data = include_bytes!("rust-logo-256x256.png");
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
//! "My egui App"
|
||||
//! }
|
||||
//!
|
||||
//! fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
//! fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
//! egui::CentralPanel::default().show(ctx, |ui| {
|
||||
//! ui.heading("Hello World!");
|
||||
//! });
|
||||
|
@ -129,7 +129,7 @@ pub fn start_web(canvas_id: &str, app: Box<dyn epi::App>) -> Result<(), wasm_bin
|
|||
/// "My egui App"
|
||||
/// }
|
||||
///
|
||||
/// fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
/// fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
/// egui::CentralPanel::default().show(ctx, |ui| {
|
||||
/// ui.heading("Hello World!");
|
||||
/// });
|
||||
|
@ -160,7 +160,7 @@ pub fn run_native(app: Box<dyn epi::App>, native_options: epi::NativeOptions) ->
|
|||
/// "My egui App"
|
||||
/// }
|
||||
///
|
||||
/// fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
/// fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
/// egui::CentralPanel::default().show(ctx, |ui| {
|
||||
/// ui.heading("Hello World!");
|
||||
/// });
|
||||
|
|
|
@ -191,7 +191,7 @@ impl Persistence {
|
|||
pub struct EpiIntegration {
|
||||
frame: epi::Frame,
|
||||
persistence: crate::epi::Persistence,
|
||||
pub egui_ctx: egui::CtxRef,
|
||||
pub egui_ctx: egui::Context,
|
||||
egui_winit: crate::State,
|
||||
pub app: Box<dyn epi::App>,
|
||||
/// When set, it is time to quit
|
||||
|
@ -206,7 +206,7 @@ impl EpiIntegration {
|
|||
persistence: crate::epi::Persistence,
|
||||
app: Box<dyn epi::App>,
|
||||
) -> Self {
|
||||
let egui_ctx = egui::CtxRef::default();
|
||||
let egui_ctx = egui::Context::default();
|
||||
|
||||
*egui_ctx.memory() = persistence.load_memory().unwrap_or_default();
|
||||
|
||||
|
@ -250,7 +250,7 @@ impl EpiIntegration {
|
|||
}
|
||||
|
||||
fn warm_up(&mut self, window: &winit::window::Window) {
|
||||
let saved_memory = self.egui_ctx.memory().clone();
|
||||
let saved_memory: egui::Memory = self.egui_ctx.memory().clone();
|
||||
self.egui_ctx.memory().set_everything_is_visible(true);
|
||||
let (_, tex_alloc_data, _) = self.update(window);
|
||||
self.frame.lock().output.tex_allocation_data = tex_alloc_data; // handle it next frame
|
||||
|
|
|
@ -176,7 +176,7 @@ pub(crate) struct Prepared {
|
|||
impl Area {
|
||||
pub fn show<R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> InnerResponse<R> {
|
||||
let prepared = self.begin(ctx);
|
||||
|
@ -186,7 +186,7 @@ impl Area {
|
|||
InnerResponse { inner, response }
|
||||
}
|
||||
|
||||
pub(crate) fn begin(self, ctx: &CtxRef) -> Prepared {
|
||||
pub(crate) fn begin(self, ctx: &Context) -> Prepared {
|
||||
let Area {
|
||||
id,
|
||||
movable,
|
||||
|
@ -234,7 +234,7 @@ impl Area {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn show_open_close_animation(&self, ctx: &CtxRef, frame: &Frame, is_open: bool) {
|
||||
pub fn show_open_close_animation(&self, ctx: &Context, frame: &Frame, is_open: bool) {
|
||||
// must be called first so animation managers know the latest state
|
||||
let visibility_factor = ctx.animate_bool(self.id.with("close_animation"), is_open);
|
||||
|
||||
|
@ -276,7 +276,7 @@ impl Prepared {
|
|||
self.drag_bounds
|
||||
}
|
||||
|
||||
pub(crate) fn content_ui(&self, ctx: &CtxRef) -> Ui {
|
||||
pub(crate) fn content_ui(&self, ctx: &Context) -> Ui {
|
||||
let screen_rect = ctx.input().screen_rect();
|
||||
|
||||
let bounds = if let Some(bounds) = self.drag_bounds {
|
||||
|
@ -317,7 +317,7 @@ impl Prepared {
|
|||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)] // intentional to swallow up `content_ui`.
|
||||
pub(crate) fn end(self, ctx: &CtxRef, content_ui: Ui) -> Response {
|
||||
pub(crate) fn end(self, ctx: &Context, content_ui: Ui) -> Response {
|
||||
let Prepared {
|
||||
layer_id,
|
||||
mut state,
|
||||
|
@ -370,8 +370,9 @@ impl Prepared {
|
|||
}
|
||||
|
||||
fn pointer_pressed_on_area(ctx: &Context, layer_id: LayerId) -> bool {
|
||||
if let Some(pointer_pos) = ctx.input().pointer.interact_pos() {
|
||||
ctx.input().pointer.any_pressed() && ctx.layer_id_at(pointer_pos) == Some(layer_id)
|
||||
if let Some(pointer_pos) = ctx.pointer_interact_pos() {
|
||||
let any_pressed = ctx.input().pointer.any_pressed();
|
||||
any_pressed && ctx.layer_id_at(pointer_pos) == Some(layer_id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ impl SidePanel {
|
|||
let mut is_resizing = false;
|
||||
if resizable {
|
||||
let resize_id = id.with("__resize");
|
||||
if let Some(pointer) = ui.input().pointer.latest_pos() {
|
||||
if let Some(pointer) = ui.ctx().latest_pointer_pos() {
|
||||
let we_are_on_top = ui
|
||||
.ctx()
|
||||
.layer_id_at(pointer)
|
||||
|
@ -284,7 +284,7 @@ impl SidePanel {
|
|||
/// Show the panel at the top level.
|
||||
pub fn show<R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> InnerResponse<R> {
|
||||
self.show_dyn(ctx, Box::new(add_contents))
|
||||
|
@ -293,7 +293,7 @@ impl SidePanel {
|
|||
/// Show the panel at the top level.
|
||||
fn show_dyn<'c, R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||
) -> InnerResponse<R> {
|
||||
let layer_id = LayerId::background();
|
||||
|
@ -485,7 +485,8 @@ impl TopBottomPanel {
|
|||
let mut is_resizing = false;
|
||||
if resizable {
|
||||
let resize_id = id.with("__resize");
|
||||
if let Some(pointer) = ui.input().pointer.latest_pos() {
|
||||
let latest_pos = ui.input().pointer.latest_pos();
|
||||
if let Some(pointer) = latest_pos {
|
||||
let we_are_on_top = ui
|
||||
.ctx()
|
||||
.layer_id_at(pointer)
|
||||
|
@ -570,7 +571,7 @@ impl TopBottomPanel {
|
|||
/// Show the panel at the top level.
|
||||
pub fn show<R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> InnerResponse<R> {
|
||||
self.show_dyn(ctx, Box::new(add_contents))
|
||||
|
@ -579,7 +580,7 @@ impl TopBottomPanel {
|
|||
/// Show the panel at the top level.
|
||||
fn show_dyn<'c, R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||
) -> InnerResponse<R> {
|
||||
let layer_id = LayerId::background();
|
||||
|
@ -670,7 +671,7 @@ impl CentralPanel {
|
|||
/// Show the panel at the top level.
|
||||
pub fn show<R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> InnerResponse<R> {
|
||||
self.show_dyn(ctx, Box::new(add_contents))
|
||||
|
@ -679,7 +680,7 @@ impl CentralPanel {
|
|||
/// Show the panel at the top level.
|
||||
fn show_dyn<'c, R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||
) -> InnerResponse<R> {
|
||||
let available_rect = ctx.available_rect();
|
||||
|
|
|
@ -66,7 +66,11 @@ impl MonoState {
|
|||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn show_tooltip<R>(ctx: &CtxRef, id: Id, add_contents: impl FnOnce(&mut Ui) -> R) -> Option<R> {
|
||||
pub fn show_tooltip<R>(
|
||||
ctx: &Context,
|
||||
id: Id,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> Option<R> {
|
||||
show_tooltip_at_pointer(ctx, id, add_contents)
|
||||
}
|
||||
|
||||
|
@ -88,7 +92,7 @@ pub fn show_tooltip<R>(ctx: &CtxRef, id: Id, add_contents: impl FnOnce(&mut Ui)
|
|||
/// # });
|
||||
/// ```
|
||||
pub fn show_tooltip_at_pointer<R>(
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
id: Id,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> Option<R> {
|
||||
|
@ -104,7 +108,7 @@ pub fn show_tooltip_at_pointer<R>(
|
|||
///
|
||||
/// If the tooltip does not fit under the area, it tries to place it above it instead.
|
||||
pub fn show_tooltip_for<R>(
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
id: Id,
|
||||
rect: &Rect,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
|
@ -129,7 +133,7 @@ pub fn show_tooltip_for<R>(
|
|||
///
|
||||
/// Returns `None` if the tooltip could not be placed.
|
||||
pub fn show_tooltip_at<R>(
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
id: Id,
|
||||
suggested_position: Option<Pos2>,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
|
@ -146,7 +150,7 @@ pub fn show_tooltip_at<R>(
|
|||
}
|
||||
|
||||
fn show_tooltip_at_avoid_dyn<'c, R>(
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
mut id: Id,
|
||||
suggested_position: Option<Pos2>,
|
||||
above: bool,
|
||||
|
@ -229,7 +233,7 @@ fn show_tooltip_at_avoid_dyn<'c, R>(
|
|||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn show_tooltip_text(ctx: &CtxRef, id: Id, text: impl Into<WidgetText>) -> Option<()> {
|
||||
pub fn show_tooltip_text(ctx: &Context, id: Id, text: impl Into<WidgetText>) -> Option<()> {
|
||||
show_tooltip(ctx, id, |ui| {
|
||||
crate::widgets::Label::new(text).ui(ui);
|
||||
})
|
||||
|
@ -237,7 +241,7 @@ pub fn show_tooltip_text(ctx: &CtxRef, id: Id, text: impl Into<WidgetText>) -> O
|
|||
|
||||
/// Show a pop-over window.
|
||||
fn show_tooltip_area_dyn<'c, R>(
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
id: Id,
|
||||
window_pos: Pos2,
|
||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||
|
|
|
@ -523,12 +523,11 @@ impl Prepared {
|
|||
};
|
||||
let content_response = ui.interact(inner_rect, id.with("area"), sense);
|
||||
|
||||
let input = ui.input();
|
||||
if content_response.dragged() {
|
||||
for d in 0..2 {
|
||||
if has_bar[d] {
|
||||
state.offset[d] -= input.pointer.delta()[d];
|
||||
state.vel[d] = input.pointer.velocity()[d];
|
||||
state.offset[d] -= ui.input().pointer.delta()[d];
|
||||
state.vel[d] = ui.input().pointer.velocity()[d];
|
||||
state.scroll_stuck_to_end[d] = false;
|
||||
} else {
|
||||
state.vel[d] = 0.0;
|
||||
|
@ -537,7 +536,7 @@ impl Prepared {
|
|||
} else {
|
||||
let stop_speed = 20.0; // Pixels per second.
|
||||
let friction_coeff = 1000.0; // Pixels per second squared.
|
||||
let dt = input.unstable_dt;
|
||||
let dt = ui.input().unstable_dt;
|
||||
|
||||
let friction = friction_coeff * dt;
|
||||
if friction > state.vel.length() || state.vel.length() < stop_speed {
|
||||
|
|
|
@ -235,7 +235,7 @@ impl<'open> Window<'open> {
|
|||
#[inline]
|
||||
pub fn show<R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> Option<InnerResponse<Option<R>>> {
|
||||
self.show_dyn(ctx, Box::new(add_contents))
|
||||
|
@ -243,7 +243,7 @@ impl<'open> Window<'open> {
|
|||
|
||||
fn show_dyn<'c, R>(
|
||||
self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||
) -> Option<InnerResponse<Option<R>>> {
|
||||
let Window {
|
||||
|
@ -296,7 +296,7 @@ impl<'open> Window<'open> {
|
|||
.and_then(|window_interaction| {
|
||||
// Calculate roughly how much larger the window size is compared to the inner rect
|
||||
let title_bar_height = if with_title_bar {
|
||||
title.font_height(ctx.fonts(), &ctx.style()) + title_content_spacing
|
||||
title.font_height(ctx) + title_content_spacing
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
@ -757,7 +757,7 @@ fn show_title_bar(
|
|||
) -> TitleBar {
|
||||
let inner_response = ui.horizontal(|ui| {
|
||||
let height = title
|
||||
.font_height(ui.fonts(), ui.style())
|
||||
.font_height(ui.ctx())
|
||||
.max(ui.spacing().interact_size.y);
|
||||
ui.set_min_height(height);
|
||||
|
||||
|
|
|
@ -1,40 +1,107 @@
|
|||
// #![warn(missing_docs)]
|
||||
|
||||
use std::sync::{
|
||||
atomic::{AtomicU32, Ordering::SeqCst},
|
||||
Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
animation_manager::AnimationManager,
|
||||
data::output::Output,
|
||||
frame_state::FrameState,
|
||||
input_state::*,
|
||||
layers::GraphicLayers,
|
||||
menu::ContextMenuSystem,
|
||||
mutex::{Mutex, MutexGuard},
|
||||
*,
|
||||
animation_manager::AnimationManager, data::output::Output, frame_state::FrameState,
|
||||
input_state::*, layers::GraphicLayers, *,
|
||||
};
|
||||
use epaint::{stats::*, text::Fonts, *};
|
||||
use epaint::{mutex::*, stats::*, text::Fonts, *};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// A wrapper around [`Arc`](std::sync::Arc)`<`[`Context`]`>`.
|
||||
/// This is how you will normally create and access a [`Context`].
|
||||
#[derive(Default)]
|
||||
struct ContextImpl {
|
||||
/// `None` until the start of the first frame.
|
||||
fonts: Option<Fonts>,
|
||||
memory: Memory,
|
||||
animation_manager: AnimationManager,
|
||||
|
||||
input: InputState,
|
||||
|
||||
/// State that is collected during a frame and then cleared
|
||||
frame_state: FrameState,
|
||||
|
||||
// The output of a frame:
|
||||
graphics: GraphicLayers,
|
||||
output: Output,
|
||||
|
||||
paint_stats: PaintStats,
|
||||
|
||||
/// While positive, keep requesting repaints. Decrement at the end of each frame.
|
||||
repaint_requests: u32,
|
||||
}
|
||||
|
||||
impl ContextImpl {
|
||||
fn begin_frame_mut(&mut self, new_raw_input: RawInput) {
|
||||
self.memory.begin_frame(&self.input, &new_raw_input);
|
||||
|
||||
let mut input = std::mem::take(&mut self.input);
|
||||
if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() {
|
||||
input.pixels_per_point = new_pixels_per_point;
|
||||
}
|
||||
|
||||
self.input = input.begin_frame(new_raw_input);
|
||||
self.frame_state.begin_frame(&self.input);
|
||||
|
||||
self.update_fonts_mut(self.input.pixels_per_point());
|
||||
|
||||
// Ensure we register the background area so panels and background ui can catch clicks:
|
||||
let screen_rect = self.input.screen_rect();
|
||||
self.memory.areas.set_state(
|
||||
LayerId::background(),
|
||||
containers::area::State {
|
||||
pos: screen_rect.min,
|
||||
size: screen_rect.size(),
|
||||
interactable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Load fonts unless already loaded.
|
||||
fn update_fonts_mut(&mut self, pixels_per_point: f32) {
|
||||
let new_font_definitions = self.memory.new_font_definitions.take();
|
||||
|
||||
let pixels_per_point_changed = match &self.fonts {
|
||||
None => true,
|
||||
Some(current_fonts) => {
|
||||
(current_fonts.pixels_per_point() - pixels_per_point).abs() > 1e-3
|
||||
}
|
||||
};
|
||||
|
||||
if self.fonts.is_none() || new_font_definitions.is_some() || pixels_per_point_changed {
|
||||
self.fonts = Some(Fonts::new(
|
||||
pixels_per_point,
|
||||
new_font_definitions.unwrap_or_else(|| {
|
||||
self.fonts
|
||||
.as_ref()
|
||||
.map(|font| font.definitions().clone())
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Your handle to egui.
|
||||
///
|
||||
/// Almost all methods are marked `&self`, `Context` has interior mutability (protected by mutexes).
|
||||
/// This is the first thing you need when working with egui.
|
||||
/// Contains the [`InputState`], [`Memory`], [`Output`], and more.
|
||||
///
|
||||
/// [`CtxRef`] is cheap to clone, and any clones refers to the same mutable data.
|
||||
/// [`Context`] is cheap to clone, and any clones refers to the same mutable data
|
||||
/// ([`Context`] uses refcounting internally).
|
||||
///
|
||||
/// A [`CtxRef`] is only valid for the duration of a frame, and so you should not store a [`CtxRef`] between frames.
|
||||
/// A new [`CtxRef`] is created each frame by calling [`Self::run`].
|
||||
/// All methods are marked `&self`; `Context` has interior mutability (protected by a mutex).
|
||||
///
|
||||
///
|
||||
/// You can store
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ``` no_run
|
||||
/// # fn handle_output(_: egui::Output) {}
|
||||
/// # fn paint(_: Vec<egui::ClippedMesh>) {}
|
||||
/// let mut ctx = egui::CtxRef::default();
|
||||
/// let mut ctx = egui::Context::default();
|
||||
///
|
||||
/// // Game loop:
|
||||
/// loop {
|
||||
|
@ -53,58 +120,46 @@ use epaint::{stats::*, text::Fonts, *};
|
|||
/// }
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct CtxRef(std::sync::Arc<Context>);
|
||||
pub struct Context(Arc<RwLock<ContextImpl>>);
|
||||
|
||||
impl std::ops::Deref for CtxRef {
|
||||
type Target = Context;
|
||||
|
||||
fn deref(&self) -> &Context {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Context> for CtxRef {
|
||||
fn as_ref(&self) -> &Context {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<Context> for CtxRef {
|
||||
fn borrow(&self) -> &Context {
|
||||
self.0.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::cmp::PartialEq for CtxRef {
|
||||
fn eq(&self, other: &CtxRef) -> bool {
|
||||
impl std::cmp::PartialEq for Context {
|
||||
fn eq(&self, other: &Context) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CtxRef {
|
||||
impl Default for Context {
|
||||
fn default() -> Self {
|
||||
Self(Arc::new(Context {
|
||||
Self(Arc::new(RwLock::new(ContextImpl {
|
||||
// Start with painting an extra frame to compensate for some widgets
|
||||
// that take two frames before they "settle":
|
||||
repaint_requests: AtomicU32::new(1),
|
||||
..Context::default()
|
||||
}))
|
||||
repaint_requests: 1,
|
||||
..ContextImpl::default()
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl CtxRef {
|
||||
impl Context {
|
||||
fn read(&self) -> RwLockReadGuard<'_, ContextImpl> {
|
||||
self.0.read()
|
||||
}
|
||||
|
||||
fn write(&self) -> RwLockWriteGuard<'_, ContextImpl> {
|
||||
self.0.write()
|
||||
}
|
||||
|
||||
/// Run the ui code for one frame.
|
||||
///
|
||||
/// Put your widgets into a [`SidePanel`], [`TopBottomPanel`], [`CentralPanel`], [`Window`] or [`Area`].
|
||||
///
|
||||
/// This will modify the internal reference to point to a new generation of [`Context`].
|
||||
/// Any old clones of this [`CtxRef`] will refer to the old [`Context`], which will not get new input.
|
||||
/// Any old clones of this [`Context`] will refer to the old [`Context`], which will not get new input.
|
||||
///
|
||||
/// You can alternatively run [`Self::begin_frame`] and [`Context::end_frame`].
|
||||
///
|
||||
/// ``` rust
|
||||
/// // One egui context that you keep reusing:
|
||||
/// let mut ctx = egui::CtxRef::default();
|
||||
/// let mut ctx = egui::Context::default();
|
||||
///
|
||||
/// // Each frame:
|
||||
/// let input = egui::RawInput::default();
|
||||
|
@ -117,9 +172,9 @@ impl CtxRef {
|
|||
/// ```
|
||||
#[must_use]
|
||||
pub fn run(
|
||||
&mut self,
|
||||
&self,
|
||||
new_input: RawInput,
|
||||
run_ui: impl FnOnce(&CtxRef),
|
||||
run_ui: impl FnOnce(&Context),
|
||||
) -> (Output, Vec<ClippedShape>) {
|
||||
self.begin_frame(new_input);
|
||||
run_ui(self);
|
||||
|
@ -130,7 +185,7 @@ impl CtxRef {
|
|||
///
|
||||
/// ``` rust
|
||||
/// // One egui context that you keep reusing:
|
||||
/// let mut ctx = egui::CtxRef::default();
|
||||
/// let mut ctx = egui::Context::default();
|
||||
///
|
||||
/// // Each frame:
|
||||
/// let input = egui::RawInput::default();
|
||||
|
@ -143,10 +198,8 @@ impl CtxRef {
|
|||
/// let (output, shapes) = ctx.end_frame();
|
||||
/// // handle output, paint shapes
|
||||
/// ```
|
||||
pub fn begin_frame(&mut self, new_input: RawInput) {
|
||||
let mut self_: Context = (*self.0).clone();
|
||||
self_.begin_frame_mut(new_input);
|
||||
*self = Self(Arc::new(self_));
|
||||
pub fn begin_frame(&self, new_input: RawInput) {
|
||||
self.write().begin_frame_mut(new_input);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
@ -167,7 +220,7 @@ impl CtxRef {
|
|||
let show_error = |pos: Pos2, text: String| {
|
||||
let painter = self.debug_painter();
|
||||
let rect = painter.error(pos, text);
|
||||
if let Some(pointer_pos) = self.input.pointer.hover_pos() {
|
||||
if let Some(pointer_pos) = self.pointer_hover_pos() {
|
||||
if rect.contains(pointer_pos) {
|
||||
painter.error(
|
||||
rect.left_bottom() + vec2(2.0, 4.0),
|
||||
|
@ -244,14 +297,19 @@ impl CtxRef {
|
|||
changed: false, // must be set by the widget itself
|
||||
};
|
||||
|
||||
let mut memory = self.memory();
|
||||
|
||||
if !enabled || !sense.focusable || !layer_id.allow_interaction() {
|
||||
// Not interested or allowed input:
|
||||
memory.surrender_focus(id);
|
||||
self.memory().surrender_focus(id);
|
||||
return response;
|
||||
}
|
||||
|
||||
self.register_interaction_id(id, rect);
|
||||
|
||||
let clicked_elsewhere = response.clicked_elsewhere();
|
||||
let ctx_impl = &mut *self.write();
|
||||
let memory = &mut ctx_impl.memory;
|
||||
let input = &mut ctx_impl.input;
|
||||
|
||||
// We only want to focus labels if the screen reader is on.
|
||||
let interested_in_focus =
|
||||
sense.interactive() || sense.focusable && memory.options.screen_reader;
|
||||
|
@ -262,14 +320,12 @@ impl CtxRef {
|
|||
|
||||
if sense.click
|
||||
&& memory.has_focus(response.id)
|
||||
&& (self.input().key_pressed(Key::Space) || self.input().key_pressed(Key::Enter))
|
||||
&& (input.key_pressed(Key::Space) || input.key_pressed(Key::Enter))
|
||||
{
|
||||
// Space/enter works like a primary click for e.g. selected buttons
|
||||
response.clicked[PointerButton::Primary as usize] = true;
|
||||
}
|
||||
|
||||
self.register_interaction_id(id, rect);
|
||||
|
||||
if sense.click || sense.drag {
|
||||
memory.interaction.click_interest |= hovered && sense.click;
|
||||
memory.interaction.drag_interest |= hovered && sense.drag;
|
||||
|
@ -278,7 +334,7 @@ impl CtxRef {
|
|||
response.is_pointer_button_down_on =
|
||||
memory.interaction.click_id == Some(id) || response.dragged;
|
||||
|
||||
for pointer_event in &self.input.pointer.pointer_events {
|
||||
for pointer_event in &input.pointer.pointer_events {
|
||||
match pointer_event {
|
||||
PointerEvent::Moved(_) => {}
|
||||
PointerEvent::Pressed(_) => {
|
||||
|
@ -325,14 +381,14 @@ impl CtxRef {
|
|||
}
|
||||
|
||||
if response.is_pointer_button_down_on {
|
||||
response.interact_pointer_pos = self.input().pointer.interact_pos();
|
||||
response.interact_pointer_pos = input.pointer.interact_pos();
|
||||
}
|
||||
|
||||
if self.input.pointer.any_down() {
|
||||
if input.pointer.any_down() {
|
||||
response.hovered &= response.is_pointer_button_down_on; // we don't hover widgets while interacting with *other* widgets
|
||||
}
|
||||
|
||||
if memory.has_focus(response.id) && response.clicked_elsewhere() {
|
||||
if memory.has_focus(response.id) && clicked_elsewhere {
|
||||
memory.surrender_focus(id);
|
||||
}
|
||||
|
||||
|
@ -346,131 +402,99 @@ impl CtxRef {
|
|||
|
||||
/// Get a full-screen painter for a new or existing layer
|
||||
pub fn layer_painter(&self, layer_id: LayerId) -> Painter {
|
||||
Painter::new(self.clone(), layer_id, self.input.screen_rect())
|
||||
let screen_rect = self.input().screen_rect();
|
||||
Painter::new(self.clone(), layer_id, screen_rect)
|
||||
}
|
||||
|
||||
/// Paint on top of everything else
|
||||
pub fn debug_painter(&self) -> Painter {
|
||||
Self::layer_painter(self, LayerId::debug())
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Your handle to egui.
|
||||
///
|
||||
/// This is the first thing you need when working with egui.
|
||||
/// Use [`CtxRef`] to create and refer to a [`Context`].
|
||||
///
|
||||
/// Contains the [`InputState`], [`Memory`], [`Output`], and more.
|
||||
///
|
||||
/// Almost all methods are marked `&self`, [`Context`] has interior mutability (protected by mutexes).
|
||||
/// Multi-threaded access to a [`Context`] is behind the feature flag `multi_threaded`.
|
||||
/// Normally you'd always do all ui work on one thread, or perhaps use multiple contexts,
|
||||
/// but if you really want to access the same [`Context`] from multiple threads, it *SHOULD* be fine,
|
||||
/// but you are likely the first person to try it.
|
||||
#[derive(Default)]
|
||||
pub struct Context {
|
||||
// We clone the Context each frame so we can set a new `input`.
|
||||
// This is so we can avoid a mutex lock to access the `InputState`.
|
||||
// This means everything else needs to be behind an Arc.
|
||||
// We can probably come up with a nicer design.
|
||||
//
|
||||
/// `None` until the start of the first frame.
|
||||
fonts: Option<Arc<Fonts>>,
|
||||
memory: Arc<Mutex<Memory>>,
|
||||
animation_manager: Arc<Mutex<AnimationManager>>,
|
||||
context_menu_system: Arc<Mutex<ContextMenuSystem>>,
|
||||
|
||||
input: InputState,
|
||||
|
||||
/// State that is collected during a frame and then cleared
|
||||
frame_state: Arc<Mutex<FrameState>>,
|
||||
|
||||
// The output of a frame:
|
||||
graphics: Arc<Mutex<GraphicLayers>>,
|
||||
output: Arc<Mutex<Output>>,
|
||||
|
||||
paint_stats: Arc<Mutex<PaintStats>>,
|
||||
|
||||
/// While positive, keep requesting repaints. Decrement at the end of each frame.
|
||||
repaint_requests: AtomicU32,
|
||||
}
|
||||
|
||||
impl Clone for Context {
|
||||
fn clone(&self) -> Self {
|
||||
Context {
|
||||
fonts: self.fonts.clone(),
|
||||
memory: self.memory.clone(),
|
||||
animation_manager: self.animation_manager.clone(),
|
||||
input: self.input.clone(),
|
||||
frame_state: self.frame_state.clone(),
|
||||
graphics: self.graphics.clone(),
|
||||
output: self.output.clone(),
|
||||
paint_stats: self.paint_stats.clone(),
|
||||
repaint_requests: self.repaint_requests.load(SeqCst).into(),
|
||||
context_menu_system: self.context_menu_system.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// How much space is still available after panels has been added.
|
||||
/// This is the "background" area, what egui doesn't cover with panels (but may cover with windows).
|
||||
/// This is also the area to which windows are constrained.
|
||||
pub fn available_rect(&self) -> Rect {
|
||||
self.frame_state.lock().available_rect()
|
||||
self.frame_state().available_rect()
|
||||
}
|
||||
}
|
||||
|
||||
/// ## Borrows parts of [`Context`]
|
||||
impl Context {
|
||||
/// Stores all the egui state.
|
||||
/// If you want to store/restore egui, serialize this.
|
||||
pub fn memory(&self) -> MutexGuard<'_, Memory> {
|
||||
self.memory.lock()
|
||||
pub fn memory(&self) -> RwLockWriteGuard<'_, Memory> {
|
||||
RwLockWriteGuard::map(self.write(), |c| &mut c.memory)
|
||||
}
|
||||
|
||||
pub(crate) fn context_menu_system(&self) -> MutexGuard<'_, ContextMenuSystem> {
|
||||
self.context_menu_system.lock()
|
||||
}
|
||||
|
||||
pub(crate) fn graphics(&self) -> MutexGuard<'_, GraphicLayers> {
|
||||
self.graphics.lock()
|
||||
pub(crate) fn graphics(&self) -> RwLockWriteGuard<'_, GraphicLayers> {
|
||||
RwLockWriteGuard::map(self.write(), |c| &mut c.graphics)
|
||||
}
|
||||
|
||||
/// What egui outputs each frame.
|
||||
pub fn output(&self) -> MutexGuard<'_, Output> {
|
||||
self.output.lock()
|
||||
pub fn output(&self) -> RwLockWriteGuard<'_, Output> {
|
||||
RwLockWriteGuard::map(self.write(), |c| &mut c.output)
|
||||
}
|
||||
|
||||
pub(crate) fn frame_state(&self) -> MutexGuard<'_, FrameState> {
|
||||
self.frame_state.lock()
|
||||
pub(crate) fn frame_state(&self) -> RwLockWriteGuard<'_, FrameState> {
|
||||
RwLockWriteGuard::map(self.write(), |c| &mut c.frame_state)
|
||||
}
|
||||
|
||||
/// Access the [`InputState`].
|
||||
///
|
||||
/// Note that this locks the [`Context`], so be careful with if-let bindings:
|
||||
///
|
||||
/// ```
|
||||
/// # let mut ctx = egui::Context::default();
|
||||
/// if let Some(pos) = ctx.input().pointer.hover_pos() {
|
||||
/// // ⚠️ Using `ctx` again here will lead to a dead-lock!
|
||||
/// }
|
||||
///
|
||||
/// if let Some(pos) = { ctx.input().pointer.hover_pos() } {
|
||||
/// // This is fine!
|
||||
/// }
|
||||
///
|
||||
/// let pos = ctx.input().pointer.hover_pos();
|
||||
/// if let Some(pos) = pos {
|
||||
/// // This is fine!
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn input(&self) -> RwLockReadGuard<'_, InputState> {
|
||||
RwLockReadGuard::map(self.read(), |c| &c.input)
|
||||
}
|
||||
|
||||
pub fn input_mut(&self) -> RwLockWriteGuard<'_, InputState> {
|
||||
RwLockWriteGuard::map(self.write(), |c| &mut c.input)
|
||||
}
|
||||
|
||||
/// Not valid until first call to [`Context::run()`].
|
||||
/// That's because since we don't know the proper `pixels_per_point` until then.
|
||||
pub fn fonts(&self) -> RwLockReadGuard<'_, Fonts> {
|
||||
RwLockReadGuard::map(self.read(), |c| {
|
||||
c.fonts
|
||||
.as_ref()
|
||||
.expect("No fonts available until first call to Context::run()")
|
||||
})
|
||||
}
|
||||
|
||||
fn fonts_mut(&self) -> RwLockWriteGuard<'_, Option<Fonts>> {
|
||||
RwLockWriteGuard::map(self.write(), |c| &mut c.fonts)
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Call this if there is need to repaint the UI, i.e. if you are showing an animation.
|
||||
/// If this is called at least once in a frame, then there will be another frame right after this.
|
||||
/// Call as many times as you wish, only one repaint will be issued.
|
||||
pub fn request_repaint(&self) {
|
||||
// request two frames of repaint, just to cover some corner cases (frame delays):
|
||||
let times_to_repaint = 2;
|
||||
self.repaint_requests.store(times_to_repaint, SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn input(&self) -> &InputState {
|
||||
&self.input
|
||||
}
|
||||
|
||||
/// Not valid until first call to [`CtxRef::run()`].
|
||||
/// That's because since we don't know the proper `pixels_per_point` until then.
|
||||
pub fn fonts(&self) -> &Fonts {
|
||||
&*self
|
||||
.fonts
|
||||
.as_ref()
|
||||
.expect("No fonts available until first call to CtxRef::run()")
|
||||
self.write().repaint_requests = 2;
|
||||
}
|
||||
|
||||
/// The egui font image, containing font characters etc.
|
||||
///
|
||||
/// Not valid until first call to [`CtxRef::run()`].
|
||||
/// Not valid until first call to [`Context::run()`].
|
||||
/// That's because since we don't know the proper `pixels_per_point` until then.
|
||||
pub fn font_image(&self) -> Arc<epaint::FontImage> {
|
||||
self.fonts().font_image()
|
||||
|
@ -483,7 +507,7 @@ impl Context {
|
|||
///
|
||||
/// The new fonts will become active at the start of the next frame.
|
||||
pub fn set_fonts(&self, font_definitions: FontDefinitions) {
|
||||
if let Some(current_fonts) = &self.fonts {
|
||||
if let Some(current_fonts) = &*self.fonts_mut() {
|
||||
// NOTE: this comparison is expensive since it checks TTF data for equality
|
||||
if current_fonts.definitions() == &font_definitions {
|
||||
return; // no change - save us from reloading font textures
|
||||
|
@ -504,7 +528,7 @@ impl Context {
|
|||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// # let mut ctx = egui::CtxRef::default();
|
||||
/// # let mut ctx = egui::Context::default();
|
||||
/// let mut style: egui::Style = (*ctx.style()).clone();
|
||||
/// style.spacing.item_spacing = egui::vec2(10.0, 20.0);
|
||||
/// ctx.set_style(style);
|
||||
|
@ -519,7 +543,7 @@ impl Context {
|
|||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// # let mut ctx = egui::CtxRef::default();
|
||||
/// # let mut ctx = egui::Context::default();
|
||||
/// ctx.set_visuals(egui::Visuals::light()); // Switch to light mode
|
||||
/// ```
|
||||
pub fn set_visuals(&self, visuals: crate::Visuals) {
|
||||
|
@ -529,7 +553,7 @@ impl Context {
|
|||
/// The number of physical pixels for each logical point.
|
||||
#[inline(always)]
|
||||
pub fn pixels_per_point(&self) -> f32 {
|
||||
self.input.pixels_per_point()
|
||||
self.input().pixels_per_point()
|
||||
}
|
||||
|
||||
/// Set the number of physical pixels for each logical point.
|
||||
|
@ -604,75 +628,30 @@ impl Context {
|
|||
|
||||
Rect::from_min_size(pos, window.size())
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
fn begin_frame_mut(&mut self, new_raw_input: RawInput) {
|
||||
self.memory().begin_frame(&self.input, &new_raw_input);
|
||||
|
||||
let mut input = std::mem::take(&mut self.input);
|
||||
if let Some(new_pixels_per_point) = self.memory().new_pixels_per_point.take() {
|
||||
input.pixels_per_point = new_pixels_per_point;
|
||||
}
|
||||
|
||||
self.input = input.begin_frame(new_raw_input);
|
||||
self.frame_state.lock().begin_frame(&self.input);
|
||||
|
||||
self.update_fonts(self.input.pixels_per_point());
|
||||
|
||||
// Ensure we register the background area so panels and background ui can catch clicks:
|
||||
let screen_rect = self.input.screen_rect();
|
||||
self.memory().areas.set_state(
|
||||
LayerId::background(),
|
||||
containers::area::State {
|
||||
pos: screen_rect.min,
|
||||
size: screen_rect.size(),
|
||||
interactable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Load fonts unless already loaded.
|
||||
fn update_fonts(&mut self, pixels_per_point: f32) {
|
||||
let new_font_definitions = self.memory().new_font_definitions.take();
|
||||
|
||||
let pixels_per_point_changed = match &self.fonts {
|
||||
None => true,
|
||||
Some(current_fonts) => {
|
||||
(current_fonts.pixels_per_point() - pixels_per_point).abs() > 1e-3
|
||||
}
|
||||
};
|
||||
|
||||
if self.fonts.is_none() || new_font_definitions.is_some() || pixels_per_point_changed {
|
||||
self.fonts = Some(Arc::new(Fonts::new(
|
||||
pixels_per_point,
|
||||
new_font_definitions.unwrap_or_else(|| {
|
||||
self.fonts
|
||||
.as_ref()
|
||||
.map(|font| font.definitions().clone())
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Call at the end of each frame.
|
||||
/// Returns what has happened this frame [`crate::Output`] as well as what you need to paint.
|
||||
/// You can transform the returned shapes into triangles with a call to [`Context::tessellate`].
|
||||
#[must_use]
|
||||
pub fn end_frame(&self) -> (Output, Vec<ClippedShape>) {
|
||||
if self.input.wants_repaint() {
|
||||
if self.input().wants_repaint() {
|
||||
self.request_repaint();
|
||||
}
|
||||
|
||||
self.memory()
|
||||
.end_frame(&self.input, &self.frame_state().used_ids);
|
||||
{
|
||||
let ctx_impl = &mut *self.write();
|
||||
ctx_impl
|
||||
.memory
|
||||
.end_frame(&ctx_impl.input, &ctx_impl.frame_state.used_ids);
|
||||
}
|
||||
|
||||
self.fonts().end_frame();
|
||||
|
||||
let mut output: Output = std::mem::take(&mut self.output());
|
||||
if self.repaint_requests.load(SeqCst) > 0 {
|
||||
self.repaint_requests.fetch_sub(1, SeqCst);
|
||||
if self.read().repaint_requests > 0 {
|
||||
self.write().repaint_requests -= 1;
|
||||
output.needs_repaint = true;
|
||||
}
|
||||
|
||||
|
@ -681,8 +660,11 @@ impl Context {
|
|||
}
|
||||
|
||||
fn drain_paint_lists(&self) -> Vec<ClippedShape> {
|
||||
let memory = self.memory();
|
||||
self.graphics().drain(memory.areas.order()).collect()
|
||||
let ctx_impl = &mut *self.write();
|
||||
ctx_impl
|
||||
.graphics
|
||||
.drain(ctx_impl.memory.areas.order())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Tessellate the given shapes into triangle meshes.
|
||||
|
@ -700,7 +682,7 @@ impl Context {
|
|||
tessellation_options,
|
||||
self.fonts().font_image().size(),
|
||||
);
|
||||
*self.paint_stats.lock() = paint_stats.with_clipped_meshes(&clipped_meshes);
|
||||
self.write().paint_stats = paint_stats.with_clipped_meshes(&clipped_meshes);
|
||||
clipped_meshes
|
||||
}
|
||||
|
||||
|
@ -725,7 +707,8 @@ impl Context {
|
|||
|
||||
/// Is the pointer (mouse/touch) over any egui area?
|
||||
pub fn is_pointer_over_area(&self) -> bool {
|
||||
if let Some(pointer_pos) = self.input.pointer.interact_pos() {
|
||||
let pointer_pos = self.input().pointer.interact_pos();
|
||||
if let Some(pointer_pos) = pointer_pos {
|
||||
if let Some(layer) = self.layer_id_at(pointer_pos) {
|
||||
if layer.order == Order::Background {
|
||||
!self.frame_state().unused_rect.contains(pointer_pos)
|
||||
|
@ -759,14 +742,45 @@ impl Context {
|
|||
pub fn wants_keyboard_input(&self) -> bool {
|
||||
self.memory().interaction.focus.focused().is_some()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Ergonomic methods to forward some calls often used in 'if let' without holding the borrow
|
||||
impl Context {
|
||||
/// Latest reported pointer position.
|
||||
/// When tapping a touch screen, this will be `None`.
|
||||
#[inline(always)]
|
||||
pub(crate) fn latest_pointer_pos(&self) -> Option<Pos2> {
|
||||
self.input().pointer.latest_pos()
|
||||
}
|
||||
|
||||
/// If it is a good idea to show a tooltip, where is pointer?
|
||||
#[inline(always)]
|
||||
pub fn pointer_hover_pos(&self) -> Option<Pos2> {
|
||||
self.input().pointer.hover_pos()
|
||||
}
|
||||
|
||||
/// If you detect a click or drag and wants to know where it happened, use this.
|
||||
///
|
||||
/// Latest position of the mouse, but ignoring any [`Event::PointerGone`]
|
||||
/// if there were interactions this frame.
|
||||
/// When tapping a touch screen, this will be the location of the touch.
|
||||
#[inline(always)]
|
||||
pub fn pointer_interact_pos(&self) -> Option<Pos2> {
|
||||
self.input().pointer.interact_pos()
|
||||
}
|
||||
|
||||
/// Calls [`InputState::multi_touch`].
|
||||
pub fn multi_touch(&self) -> Option<MultiTouchInfo> {
|
||||
self.input().multi_touch()
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Move all the graphics at the given layer.
|
||||
/// Can be used to implement drag-and-drop (see relevant demo).
|
||||
pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) {
|
||||
if delta != Vec2::ZERO {
|
||||
self.graphics().list(layer_id).lock().translate(delta);
|
||||
self.graphics().list(layer_id).translate(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -777,7 +791,8 @@ impl Context {
|
|||
}
|
||||
|
||||
pub(crate) fn rect_contains_pointer(&self, layer_id: LayerId, rect: Rect) -> bool {
|
||||
if let Some(pointer_pos) = self.input.pointer.interact_pos() {
|
||||
let pointer_pos = self.input().pointer.interact_pos();
|
||||
if let Some(pointer_pos) = pointer_pos {
|
||||
rect.contains(pointer_pos) && self.layer_id_at(pointer_pos) == Some(layer_id)
|
||||
} else {
|
||||
false
|
||||
|
@ -817,10 +832,12 @@ impl Context {
|
|||
|
||||
/// Like [`Self::animate_bool`] but allows you to control the animation time.
|
||||
pub fn animate_bool_with_time(&self, id: Id, value: bool, animation_time: f32) -> f32 {
|
||||
let animated_value =
|
||||
self.animation_manager
|
||||
.lock()
|
||||
.animate_bool(&self.input, animation_time, id, value);
|
||||
let animated_value = {
|
||||
let ctx_impl = &mut *self.write();
|
||||
ctx_impl
|
||||
.animation_manager
|
||||
.animate_bool(&ctx_impl.input, animation_time, id, value)
|
||||
};
|
||||
let animation_in_progress = 0.0 < animated_value && animated_value < 1.0;
|
||||
if animation_in_progress {
|
||||
self.request_repaint();
|
||||
|
@ -830,7 +847,7 @@ impl Context {
|
|||
|
||||
/// Clear memory of any animations.
|
||||
pub fn clear_animations(&self) {
|
||||
*self.animation_manager.lock() = Default::default();
|
||||
self.write().animation_manager = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -849,7 +866,8 @@ impl Context {
|
|||
.show(ui, |ui| {
|
||||
let mut font_definitions = self.fonts().definitions().clone();
|
||||
font_definitions.ui(ui);
|
||||
self.fonts().font_image().ui(ui);
|
||||
let font_image = self.fonts().font_image();
|
||||
font_image.ui(ui);
|
||||
self.set_fonts(font_definitions);
|
||||
});
|
||||
|
||||
|
@ -891,16 +909,12 @@ impl Context {
|
|||
.on_hover_text("Is egui currently listening for text input?");
|
||||
|
||||
let pointer_pos = self
|
||||
.input()
|
||||
.pointer
|
||||
.hover_pos()
|
||||
.pointer_hover_pos()
|
||||
.map_or_else(String::new, |pos| format!("{:?}", pos));
|
||||
ui.label(format!("Pointer pos: {}", pointer_pos));
|
||||
|
||||
let top_layer = self
|
||||
.input()
|
||||
.pointer
|
||||
.hover_pos()
|
||||
.pointer_hover_pos()
|
||||
.and_then(|pos| self.layer_id_at(pos))
|
||||
.map_or_else(String::new, |layer| layer.short_debug_format());
|
||||
ui.label(format!("Top layer under mouse: {}", top_layer));
|
||||
|
@ -916,12 +930,16 @@ impl Context {
|
|||
|
||||
CollapsingHeader::new("📥 Input")
|
||||
.default_open(false)
|
||||
.show(ui, |ui| ui.input().clone().ui(ui));
|
||||
.show(ui, |ui| {
|
||||
let input = ui.input().clone();
|
||||
input.ui(ui);
|
||||
});
|
||||
|
||||
CollapsingHeader::new("📊 Paint stats")
|
||||
.default_open(true)
|
||||
.show(ui, |ui| {
|
||||
self.paint_stats.lock().ui(ui);
|
||||
let paint_stats = self.write().paint_stats;
|
||||
paint_stats.ui(ui);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ pub struct DroppedFile {
|
|||
/// Set by the `egui_web` backend.
|
||||
pub last_modified: Option<std::time::SystemTime>,
|
||||
/// Set by the `egui_web` backend.
|
||||
pub bytes: Option<std::sync::Arc<[u8]>>,
|
||||
pub bytes: Option<epaint::mutex::Arc<[u8]>>,
|
||||
}
|
||||
|
||||
/// An input event generated by the integration.
|
||||
|
|
|
@ -72,7 +72,7 @@ impl FrameState {
|
|||
pub(crate) fn available_rect(&self) -> Rect {
|
||||
crate::egui_assert!(
|
||||
self.available_rect.is_finite(),
|
||||
"Called `available_rect()` before `CtxRef::run()`"
|
||||
"Called `available_rect()` before `Context::run()`"
|
||||
);
|
||||
self.available_rect
|
||||
}
|
||||
|
|
|
@ -45,8 +45,8 @@ impl State {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub(crate) struct GridLayout {
|
||||
ctx: CtxRef,
|
||||
style: std::sync::Arc<Style>,
|
||||
ctx: Context,
|
||||
style: epaint::mutex::Arc<Style>,
|
||||
id: Id,
|
||||
|
||||
/// State previous frame (if any).
|
||||
|
|
|
@ -261,7 +261,8 @@ impl InputState {
|
|||
/// # egui::__run_test_ui(|ui| {
|
||||
/// let mut zoom = 1.0; // no zoom
|
||||
/// let mut rotation = 0.0; // no rotation
|
||||
/// if let Some(multi_touch) = ui.input().multi_touch() {
|
||||
/// let multi_touch = ui.input().multi_touch();
|
||||
/// if let Some(multi_touch) = multi_touch {
|
||||
/// zoom *= multi_touch.zoom_delta;
|
||||
/// rotation += multi_touch.rotation_delta;
|
||||
/// }
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
};
|
||||
|
||||
/// All you probably need to know about a multi-touch gesture.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct MultiTouchInfo {
|
||||
/// Point in time when the gesture started.
|
||||
pub start_time: f64,
|
||||
|
|
|
@ -32,7 +32,7 @@ impl Widget for &epaint::FontImage {
|
|||
response
|
||||
.on_hover_cursor(CursorIcon::ZoomIn)
|
||||
.on_hover_ui_at_pointer(|ui| {
|
||||
if let Some(pos) = ui.input().pointer.latest_pos() {
|
||||
if let Some(pos) = ui.ctx().latest_pointer_pos() {
|
||||
let (_id, zoom_rect) = ui.allocate_space(vec2(128.0, 128.0));
|
||||
let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
|
||||
let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
//! are sometimes painted behind or in front of other things.
|
||||
|
||||
use crate::{Id, *};
|
||||
use epaint::mutex::Mutex;
|
||||
use epaint::{ClippedShape, Shape};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Different layer categories
|
||||
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
|
||||
|
@ -153,10 +151,10 @@ impl PaintList {
|
|||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct GraphicLayers([IdMap<Arc<Mutex<PaintList>>>; Order::COUNT]);
|
||||
pub(crate) struct GraphicLayers([IdMap<PaintList>; Order::COUNT]);
|
||||
|
||||
impl GraphicLayers {
|
||||
pub fn list(&mut self, layer_id: LayerId) -> &Arc<Mutex<PaintList>> {
|
||||
pub fn list(&mut self, layer_id: LayerId) -> &mut PaintList {
|
||||
self.0[layer_id.order as usize]
|
||||
.entry(layer_id.id)
|
||||
.or_default()
|
||||
|
@ -171,20 +169,20 @@ impl GraphicLayers {
|
|||
// If a layer is empty at the start of the frame
|
||||
// then nobody has added to it, and it is old and defunct.
|
||||
// Free it to save memory:
|
||||
order_map.retain(|_, list| !list.lock().is_empty());
|
||||
order_map.retain(|_, list| !list.is_empty());
|
||||
|
||||
// First do the layers part of area_order:
|
||||
for layer_id in area_order {
|
||||
if layer_id.order == order {
|
||||
if let Some(list) = order_map.get_mut(&layer_id.id) {
|
||||
all_shapes.append(&mut list.lock().0);
|
||||
all_shapes.append(&mut list.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also draw areas that are missing in `area_order`:
|
||||
for shapes in order_map.values_mut() {
|
||||
all_shapes.append(&mut shapes.lock().0);
|
||||
all_shapes.append(&mut shapes.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//! To quickly get started with egui, you can take a look at [`eframe_template`](https://github.com/emilk/eframe_template)
|
||||
//! which uses [`eframe`](https://docs.rs/eframe).
|
||||
//!
|
||||
//! To create a GUI using egui you first need a [`CtxRef`] (by convention referred to by `ctx`).
|
||||
//! To create a GUI using egui you first need a [`Context`] (by convention referred to by `ctx`).
|
||||
//! Then you add a [`Window`] or a [`SidePanel`] to get a [`Ui`], which is what you'll be using to add all the buttons and labels that you need.
|
||||
//!
|
||||
//!
|
||||
|
@ -113,7 +113,7 @@
|
|||
//! # fn handle_output(_: egui::Output) {}
|
||||
//! # fn paint(_: Vec<egui::ClippedMesh>) {}
|
||||
//! # fn gather_input() -> egui::RawInput { egui::RawInput::default() }
|
||||
//! let mut ctx = egui::CtxRef::default();
|
||||
//! let mut ctx = egui::Context::default();
|
||||
//!
|
||||
//! // Game loop:
|
||||
//! loop {
|
||||
|
@ -398,7 +398,7 @@ pub mod text {
|
|||
|
||||
pub use {
|
||||
containers::*,
|
||||
context::{Context, CtxRef},
|
||||
context::Context,
|
||||
data::{
|
||||
input::*,
|
||||
output::{self, CursorIcon, Output, WidgetInfo},
|
||||
|
@ -574,8 +574,8 @@ pub enum WidgetType {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// For use in tests; especially doctests.
|
||||
pub fn __run_test_ctx(mut run_ui: impl FnMut(&CtxRef)) {
|
||||
let mut ctx = CtxRef::default();
|
||||
pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
|
||||
let ctx = Context::default();
|
||||
let _ = ctx.run(Default::default(), |ctx| {
|
||||
run_ui(ctx);
|
||||
});
|
||||
|
@ -583,7 +583,7 @@ pub fn __run_test_ctx(mut run_ui: impl FnMut(&CtxRef)) {
|
|||
|
||||
/// For use in tests; especially doctests.
|
||||
pub fn __run_test_ui(mut add_contents: impl FnMut(&mut Ui)) {
|
||||
let mut ctx = CtxRef::default();
|
||||
let ctx = Context::default();
|
||||
let _ = ctx.run(Default::default(), |ctx| {
|
||||
crate::CentralPanel::default().show(ctx, |ui| {
|
||||
add_contents(ui);
|
||||
|
|
|
@ -45,7 +45,7 @@ pub struct Memory {
|
|||
/// }
|
||||
/// type CharCountCache<'a> = FrameCache<usize, CharCounter>;
|
||||
///
|
||||
/// # let mut ctx = egui::CtxRef::default();
|
||||
/// # let mut ctx = egui::Context::default();
|
||||
/// let mut memory = ctx.memory();
|
||||
/// let cache = memory.caches.cache::<CharCountCache<'_>>();
|
||||
/// assert_eq!(cache.get("hello"), 5);
|
||||
|
@ -91,7 +91,7 @@ pub struct Memory {
|
|||
pub struct Options {
|
||||
/// The default style for new `Ui`:s.
|
||||
#[cfg_attr(feature = "serde", serde(skip))]
|
||||
pub(crate) style: std::sync::Arc<Style>,
|
||||
pub(crate) style: epaint::mutex::Arc<Style>,
|
||||
|
||||
/// Controls the tessellator.
|
||||
pub tessellation_options: epaint::TessellationOptions,
|
||||
|
|
|
@ -16,12 +16,11 @@
|
|||
//! ```
|
||||
|
||||
use super::{
|
||||
style::WidgetVisuals, Align, CtxRef, Id, InnerResponse, PointerState, Pos2, Rect, Response,
|
||||
style::WidgetVisuals, Align, Context, Id, InnerResponse, PointerState, Pos2, Rect, Response,
|
||||
Sense, TextStyle, Ui, Vec2,
|
||||
};
|
||||
use crate::{widgets::*, *};
|
||||
use epaint::{mutex::RwLock, Stroke};
|
||||
use std::sync::Arc;
|
||||
use epaint::{mutex::Arc, mutex::RwLock, Stroke};
|
||||
|
||||
/// What is saved between frames.
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -116,7 +115,7 @@ pub(crate) fn submenu_button<R>(
|
|||
|
||||
/// wrapper for the contents of every menu.
|
||||
pub(crate) fn menu_ui<'c, R>(
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
menu_id: impl std::hash::Hash,
|
||||
menu_state_arc: &Arc<RwLock<MenuState>>,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R + 'c,
|
||||
|
@ -187,33 +186,19 @@ fn stationary_menu_impl<'c, R>(
|
|||
InnerResponse::new(inner.map(|r| r.inner), button_response)
|
||||
}
|
||||
|
||||
/// Stores the state for the context menu.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ContextMenuSystem {
|
||||
root: MenuRootManager,
|
||||
}
|
||||
impl ContextMenuSystem {
|
||||
/// Show a menu at pointer if right-clicked response.
|
||||
/// Should be called from [`Context`] on a [`Response`]
|
||||
pub fn context_menu(
|
||||
&mut self,
|
||||
response: &Response,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> Option<InnerResponse<()>> {
|
||||
MenuRoot::context_click_interaction(response, &mut self.root, response.id);
|
||||
self.root.show(response, add_contents)
|
||||
}
|
||||
}
|
||||
impl std::ops::Deref for ContextMenuSystem {
|
||||
type Target = MenuRootManager;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.root
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for ContextMenuSystem {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.root
|
||||
}
|
||||
/// Response to secondary clicks (right-clicks) by showing the given menu.
|
||||
pub(crate) fn context_menu(
|
||||
response: &Response,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> Option<InnerResponse<()>> {
|
||||
let menu_id = Id::new("__egui::context_menu");
|
||||
let mut bar_state = BarState::load(&response.ctx, menu_id);
|
||||
|
||||
MenuRoot::context_click_interaction(response, &mut bar_state, response.id);
|
||||
let inner_response = bar_state.show(response, add_contents);
|
||||
|
||||
bar_state.store(&response.ctx, menu_id);
|
||||
inner_response
|
||||
}
|
||||
|
||||
/// Stores the state for the context menu.
|
||||
|
@ -520,7 +505,7 @@ impl MenuState {
|
|||
self.response = MenuResponse::Close;
|
||||
}
|
||||
pub fn show<R>(
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
menu_state: &Arc<RwLock<Self>>,
|
||||
id: Id,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
|
@ -529,7 +514,7 @@ impl MenuState {
|
|||
}
|
||||
fn show_submenu<R>(
|
||||
&mut self,
|
||||
ctx: &CtxRef,
|
||||
ctx: &Context,
|
||||
id: Id,
|
||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||
) -> Option<R> {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::{
|
||||
emath::{Align2, Pos2, Rect, Vec2},
|
||||
layers::{LayerId, PaintList, ShapeIdx},
|
||||
Color32, CtxRef,
|
||||
Color32, Context,
|
||||
};
|
||||
use epaint::{
|
||||
mutex::Mutex,
|
||||
mutex::{Arc, RwLockReadGuard, RwLockWriteGuard},
|
||||
text::{Fonts, Galley, TextStyle},
|
||||
CircleShape, RectShape, Shape, Stroke, TextShape,
|
||||
};
|
||||
|
@ -15,13 +15,11 @@ use epaint::{
|
|||
#[derive(Clone)]
|
||||
pub struct Painter {
|
||||
/// Source of fonts and destination of shapes
|
||||
ctx: CtxRef,
|
||||
ctx: Context,
|
||||
|
||||
/// Where we paint
|
||||
layer_id: LayerId,
|
||||
|
||||
paint_list: std::sync::Arc<Mutex<PaintList>>,
|
||||
|
||||
/// Everything painted in this `Painter` will be clipped against this.
|
||||
/// This means nothing outside of this rectangle will be visible on screen.
|
||||
clip_rect: Rect,
|
||||
|
@ -32,12 +30,10 @@ pub struct Painter {
|
|||
}
|
||||
|
||||
impl Painter {
|
||||
pub fn new(ctx: CtxRef, layer_id: LayerId, clip_rect: Rect) -> Self {
|
||||
let paint_list = ctx.graphics().list(layer_id).clone();
|
||||
pub fn new(ctx: Context, layer_id: LayerId, clip_rect: Rect) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
layer_id,
|
||||
paint_list,
|
||||
clip_rect,
|
||||
fade_to_color: None,
|
||||
}
|
||||
|
@ -45,10 +41,8 @@ impl Painter {
|
|||
|
||||
#[must_use]
|
||||
pub fn with_layer_id(self, layer_id: LayerId) -> Self {
|
||||
let paint_list = self.ctx.graphics().list(layer_id).clone();
|
||||
Self {
|
||||
ctx: self.ctx,
|
||||
paint_list,
|
||||
layer_id,
|
||||
clip_rect: self.clip_rect,
|
||||
fade_to_color: None,
|
||||
|
@ -58,7 +52,6 @@ impl Painter {
|
|||
/// redirect
|
||||
pub fn set_layer_id(&mut self, layer_id: LayerId) {
|
||||
self.layer_id = layer_id;
|
||||
self.paint_list = self.ctx.graphics().list(self.layer_id).clone();
|
||||
}
|
||||
|
||||
/// If set, colors will be modified to look like this
|
||||
|
@ -83,7 +76,6 @@ impl Painter {
|
|||
Self {
|
||||
ctx: self.ctx.clone(),
|
||||
layer_id: self.layer_id,
|
||||
paint_list: self.paint_list.clone(),
|
||||
clip_rect: rect.intersect(self.clip_rect),
|
||||
fade_to_color: self.fade_to_color,
|
||||
}
|
||||
|
@ -92,15 +84,15 @@ impl Painter {
|
|||
|
||||
/// ## Accessors etc
|
||||
impl Painter {
|
||||
/// Get a reference to the parent [`CtxRef`].
|
||||
/// Get a reference to the parent [`Context`].
|
||||
#[inline(always)]
|
||||
pub fn ctx(&self) -> &CtxRef {
|
||||
pub fn ctx(&self) -> &Context {
|
||||
&self.ctx
|
||||
}
|
||||
|
||||
/// Available fonts.
|
||||
#[inline(always)]
|
||||
pub fn fonts(&self) -> &Fonts {
|
||||
pub fn fonts(&self) -> RwLockReadGuard<'_, Fonts> {
|
||||
self.ctx.fonts()
|
||||
}
|
||||
|
||||
|
@ -145,6 +137,10 @@ impl Painter {
|
|||
|
||||
/// ## Low level
|
||||
impl Painter {
|
||||
fn paint_list(&self) -> RwLockWriteGuard<'_, PaintList> {
|
||||
RwLockWriteGuard::map(self.ctx.graphics(), |g| g.list(self.layer_id))
|
||||
}
|
||||
|
||||
fn transform_shape(&self, shape: &mut Shape) {
|
||||
if let Some(fade_to_color) = self.fade_to_color {
|
||||
tint_shape_towards(shape, fade_to_color);
|
||||
|
@ -156,11 +152,11 @@ impl Painter {
|
|||
/// NOTE: all coordinates are screen coordinates!
|
||||
pub fn add(&self, shape: impl Into<Shape>) -> ShapeIdx {
|
||||
if self.fade_to_color == Some(Color32::TRANSPARENT) {
|
||||
self.paint_list.lock().add(self.clip_rect, Shape::Noop)
|
||||
self.paint_list().add(self.clip_rect, Shape::Noop)
|
||||
} else {
|
||||
let mut shape = shape.into();
|
||||
self.transform_shape(&mut shape);
|
||||
self.paint_list.lock().add(self.clip_rect, shape)
|
||||
self.paint_list().add(self.clip_rect, shape)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +174,7 @@ impl Painter {
|
|||
}
|
||||
}
|
||||
|
||||
self.paint_list.lock().extend(self.clip_rect, shapes);
|
||||
self.paint_list().extend(self.clip_rect, shapes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,7 +185,7 @@ impl Painter {
|
|||
}
|
||||
let mut shape = shape.into();
|
||||
self.transform_shape(&mut shape);
|
||||
self.paint_list.lock().set(idx, self.clip_rect, shape);
|
||||
self.paint_list().set(idx, self.clip_rect, shape);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,7 +353,7 @@ impl Painter {
|
|||
text_style: TextStyle,
|
||||
color: crate::Color32,
|
||||
wrap_width: f32,
|
||||
) -> std::sync::Arc<Galley> {
|
||||
) -> Arc<Galley> {
|
||||
self.fonts().layout(text, text_style, color, wrap_width)
|
||||
}
|
||||
|
||||
|
@ -370,7 +366,7 @@ impl Painter {
|
|||
text: String,
|
||||
text_style: TextStyle,
|
||||
color: crate::Color32,
|
||||
) -> std::sync::Arc<Galley> {
|
||||
) -> Arc<Galley> {
|
||||
self.fonts().layout(text, text_style, color, f32::INFINITY)
|
||||
}
|
||||
|
||||
|
@ -380,7 +376,7 @@ impl Painter {
|
|||
///
|
||||
/// If you want to change the color of the text, use [`Self::galley_with_color`].
|
||||
#[inline(always)]
|
||||
pub fn galley(&self, pos: Pos2, galley: std::sync::Arc<Galley>) {
|
||||
pub fn galley(&self, pos: Pos2, galley: Arc<Galley>) {
|
||||
if !galley.is_empty() {
|
||||
self.add(Shape::galley(pos, galley));
|
||||
}
|
||||
|
@ -392,12 +388,7 @@ impl Painter {
|
|||
///
|
||||
/// The text color in the [`Galley`] will be replaced with the given color.
|
||||
#[inline(always)]
|
||||
pub fn galley_with_color(
|
||||
&self,
|
||||
pos: Pos2,
|
||||
galley: std::sync::Arc<Galley>,
|
||||
text_color: Color32,
|
||||
) {
|
||||
pub fn galley_with_color(&self, pos: Pos2, galley: Arc<Galley>, text_color: Color32) {
|
||||
if !galley.is_empty() {
|
||||
self.add(TextShape {
|
||||
override_text_color: Some(text_color),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
emath::{lerp, Align, Pos2, Rect, Vec2},
|
||||
CtxRef, CursorIcon, Id, LayerId, PointerButton, Sense, Ui, WidgetText, NUM_POINTER_BUTTONS,
|
||||
menu, Context, CursorIcon, Id, LayerId, PointerButton, Sense, Ui, WidgetText,
|
||||
NUM_POINTER_BUTTONS,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -16,7 +17,7 @@ use crate::{
|
|||
pub struct Response {
|
||||
// CONTEXT:
|
||||
/// Used for optionally showing a tooltip and checking for more interactions.
|
||||
pub ctx: CtxRef,
|
||||
pub ctx: Context,
|
||||
|
||||
// IN:
|
||||
/// Which layer the widget is part of.
|
||||
|
@ -492,9 +493,7 @@ impl Response {
|
|||
///
|
||||
/// See also: [`Ui::menu_button`] and [`Ui::close_menu`].
|
||||
pub fn context_menu(self, add_contents: impl FnOnce(&mut Ui)) -> Self {
|
||||
self.ctx
|
||||
.context_menu_system()
|
||||
.context_menu(&self, add_contents);
|
||||
menu::context_menu(&self, add_contents);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
// #![warn(missing_docs)]
|
||||
|
||||
use epaint::mutex::RwLock;
|
||||
use epaint::mutex::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::hash::Hash;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
color::*, containers::*, epaint::text::Fonts, layout::*, menu::MenuState, mutex::MutexGuard,
|
||||
placer::Placer, widgets::*, *,
|
||||
color::*, containers::*, epaint::text::Fonts, layout::*, menu::MenuState, placer::Placer,
|
||||
widgets::*, *,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -49,7 +48,7 @@ pub struct Ui {
|
|||
/// The `Style` (visuals, spacing, etc) of this ui.
|
||||
/// Commonly many `Ui`:s share the same `Style`.
|
||||
/// The `Ui` implements copy-on-write for this.
|
||||
style: std::sync::Arc<Style>,
|
||||
style: Arc<Style>,
|
||||
|
||||
/// Handles the `Ui` size and the placement of new widgets.
|
||||
placer: Placer,
|
||||
|
@ -70,7 +69,7 @@ impl Ui {
|
|||
///
|
||||
/// Normally you would not use this directly, but instead use
|
||||
/// [`SidePanel`], [`TopBottomPanel`], [`CentralPanel`], [`Window`] or [`Area`].
|
||||
pub fn new(ctx: CtxRef, layer_id: LayerId, id: Id, max_rect: Rect, clip_rect: Rect) -> Self {
|
||||
pub fn new(ctx: Context, layer_id: LayerId, id: Id, max_rect: Rect, clip_rect: Rect) -> Self {
|
||||
let style = ctx.style();
|
||||
Ui {
|
||||
id,
|
||||
|
@ -122,7 +121,7 @@ impl Ui {
|
|||
///
|
||||
/// Note that this may be a different [`Style`] than that of [`Context::style`].
|
||||
#[inline]
|
||||
pub fn style(&self) -> &std::sync::Arc<Style> {
|
||||
pub fn style(&self) -> &Arc<Style> {
|
||||
&self.style
|
||||
}
|
||||
|
||||
|
@ -138,13 +137,13 @@ impl Ui {
|
|||
/// # });
|
||||
/// ```
|
||||
pub fn style_mut(&mut self) -> &mut Style {
|
||||
std::sync::Arc::make_mut(&mut self.style) // clone-on-write
|
||||
Arc::make_mut(&mut self.style) // clone-on-write
|
||||
}
|
||||
|
||||
/// Changes apply to this `Ui` and its subsequent children.
|
||||
///
|
||||
/// To set the visuals of all `Ui`:s, use [`Context::set_visuals`].
|
||||
pub fn set_style(&mut self, style: impl Into<std::sync::Arc<Style>>) {
|
||||
pub fn set_style(&mut self, style: impl Into<Arc<Style>>) {
|
||||
self.style = style.into();
|
||||
}
|
||||
|
||||
|
@ -195,9 +194,9 @@ impl Ui {
|
|||
&mut self.style_mut().visuals
|
||||
}
|
||||
|
||||
/// Get a reference to the parent [`CtxRef`].
|
||||
/// Get a reference to the parent [`Context`].
|
||||
#[inline]
|
||||
pub fn ctx(&self) -> &CtxRef {
|
||||
pub fn ctx(&self) -> &Context {
|
||||
self.painter.ctx()
|
||||
}
|
||||
|
||||
|
@ -313,31 +312,50 @@ impl Ui {
|
|||
self.painter().layer_id()
|
||||
}
|
||||
|
||||
/// The `Input` of the `Context` associated with the `Ui`.
|
||||
/// The [`InputState`] of the [`Context`] associated with this [`Ui`].
|
||||
/// Equivalent to `.ctx().input()`.
|
||||
///
|
||||
/// Note that this locks the [`Context`], so be careful with if-let bindings:
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// if let Some(pos) = { ui.input().pointer.hover_pos() } {
|
||||
/// // This is fine!
|
||||
/// }
|
||||
///
|
||||
/// let pos = ui.input().pointer.hover_pos();
|
||||
/// if let Some(pos) = pos {
|
||||
/// // This is also fine!
|
||||
/// }
|
||||
///
|
||||
/// if let Some(pos) = ui.input().pointer.hover_pos() {
|
||||
/// // ⚠️ Using `ui` again here will lead to a dead-lock!
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn input(&self) -> &InputState {
|
||||
pub fn input(&self) -> RwLockReadGuard<'_, InputState> {
|
||||
self.ctx().input()
|
||||
}
|
||||
|
||||
/// The `Memory` of the `Context` associated with the `Ui`.
|
||||
/// Equivalent to `.ctx().memory()`.
|
||||
#[inline]
|
||||
pub fn memory(&self) -> MutexGuard<'_, Memory> {
|
||||
pub fn memory(&self) -> RwLockWriteGuard<'_, Memory> {
|
||||
self.ctx().memory()
|
||||
}
|
||||
|
||||
/// The `Output` of the `Context` associated with the `Ui`.
|
||||
/// Equivalent to `.ctx().output()`.
|
||||
#[inline]
|
||||
pub fn output(&self) -> MutexGuard<'_, Output> {
|
||||
pub fn output(&self) -> RwLockWriteGuard<'_, Output> {
|
||||
self.ctx().output()
|
||||
}
|
||||
|
||||
/// The `Fonts` of the `Context` associated with the `Ui`.
|
||||
/// Equivalent to `.ctx().fonts()`.
|
||||
#[inline]
|
||||
pub fn fonts(&self) -> &Fonts {
|
||||
pub fn fonts(&self) -> RwLockReadGuard<'_, Fonts> {
|
||||
self.ctx().fonts()
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
// For non-serializable types, these simply return `None`.
|
||||
// This will also allow users to pick their own serialization format per type.
|
||||
|
||||
use epaint::mutex::Arc;
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::sync::Arc;
|
||||
use epaint::mutex::Arc;
|
||||
|
||||
use crate::{
|
||||
style::WidgetVisuals, text::LayoutJob, Align, Color32, Galley, Pos2, Style, TextStyle, Ui,
|
||||
Visuals,
|
||||
style::WidgetVisuals, text::LayoutJob, Align, Color32, Context, Galley, Pos2, Style, TextStyle,
|
||||
Ui, Visuals,
|
||||
};
|
||||
|
||||
/// Text and optional style choices for it.
|
||||
|
@ -170,12 +170,12 @@ impl RichText {
|
|||
}
|
||||
|
||||
/// Read the font height of the selected text style.
|
||||
pub fn font_height(&self, fonts: &epaint::text::Fonts, style: &crate::Style) -> f32 {
|
||||
pub fn font_height(&self, ctx: &Context) -> f32 {
|
||||
let text_style = self
|
||||
.text_style
|
||||
.or(style.override_text_style)
|
||||
.unwrap_or(style.body_text_style);
|
||||
fonts.row_height(text_style)
|
||||
.or(ctx.style().override_text_style)
|
||||
.unwrap_or(ctx.style().body_text_style);
|
||||
ctx.fonts().row_height(text_style)
|
||||
}
|
||||
|
||||
fn into_text_job(
|
||||
|
@ -437,10 +437,10 @@ impl WidgetText {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn font_height(&self, fonts: &epaint::text::Fonts, style: &crate::Style) -> f32 {
|
||||
pub(crate) fn font_height(&self, ctx: &Context) -> f32 {
|
||||
match self {
|
||||
Self::RichText(text) => text.font_height(fonts, style),
|
||||
Self::LayoutJob(job) => job.font_height(fonts),
|
||||
Self::RichText(text) => text.font_height(ctx),
|
||||
Self::LayoutJob(job) => job.font_height(&*ctx.fonts()),
|
||||
Self::Galley(galley) => {
|
||||
if let Some(row) = galley.rows.first() {
|
||||
row.height()
|
||||
|
|
|
@ -159,8 +159,8 @@ impl<'a> Widget for DragValue<'a> {
|
|||
max_decimals,
|
||||
} = self;
|
||||
|
||||
let is_slow_speed =
|
||||
ui.input().modifiers.shift_only() && ui.memory().is_being_dragged(ui.next_auto_id());
|
||||
let shift = ui.input().modifiers.shift_only();
|
||||
let is_slow_speed = shift && ui.memory().is_being_dragged(ui.next_auto_id());
|
||||
|
||||
let old_value = get(&mut get_set_value);
|
||||
let value = clamp_to_range(old_value, clamp_range.clone());
|
||||
|
|
|
@ -106,7 +106,7 @@ impl Label {
|
|||
if let Some(first_section) = text_job.job.sections.first_mut() {
|
||||
first_section.leading_space = first_row_indentation;
|
||||
}
|
||||
let text_galley = text_job.into_galley(ui.fonts());
|
||||
let text_galley = text_job.into_galley(&*ui.fonts());
|
||||
|
||||
let pos = pos2(ui.max_rect().left(), ui.cursor().top());
|
||||
assert!(
|
||||
|
@ -139,7 +139,7 @@ impl Label {
|
|||
text_job.job.justify = ui.layout().horizontal_justify();
|
||||
};
|
||||
|
||||
let text_galley = text_job.into_galley(ui.fonts());
|
||||
let text_galley = text_job.into_galley(&*ui.fonts());
|
||||
let (rect, response) = ui.allocate_exact_size(text_galley.size(), self.sense);
|
||||
let pos = match text_galley.galley.job.halign {
|
||||
Align::LEFT => rect.left_top(),
|
||||
|
|
|
@ -1619,7 +1619,7 @@ fn add_rulers_and_text(
|
|||
|
||||
let corner_value = elem.corner_value();
|
||||
shapes.push(Shape::text(
|
||||
plot.ui.fonts(),
|
||||
&*plot.ui.fonts(),
|
||||
plot.transform.position_from_value(&corner_value) + vec2(3.0, -2.0),
|
||||
Align2::LEFT_BOTTOM,
|
||||
text,
|
||||
|
@ -1674,7 +1674,7 @@ pub(super) fn rulers_at_value(
|
|||
};
|
||||
|
||||
shapes.push(Shape::text(
|
||||
plot.ui.fonts(),
|
||||
&*plot.ui.fonts(),
|
||||
pointer + vec2(3.0, -2.0),
|
||||
Align2::LEFT_BOTTOM,
|
||||
text,
|
||||
|
|
|
@ -479,7 +479,7 @@ pub struct PlotUi {
|
|||
next_auto_color_idx: usize,
|
||||
last_screen_transform: ScreenTransform,
|
||||
response: Response,
|
||||
ctx: CtxRef,
|
||||
ctx: Context,
|
||||
}
|
||||
|
||||
impl PlotUi {
|
||||
|
@ -491,7 +491,7 @@ impl PlotUi {
|
|||
Hsva::new(h, 0.85, 0.5, 1.0).into() // TODO: OkLab or some other perspective color space
|
||||
}
|
||||
|
||||
pub fn ctx(&self) -> &CtxRef {
|
||||
pub fn ctx(&self) -> &Context {
|
||||
&self.ctx
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use epaint::mutex::Arc;
|
||||
|
||||
use epaint::text::{cursor::*, Galley, LayoutJob};
|
||||
|
||||
|
@ -406,7 +406,7 @@ impl<'t> TextEdit<'t> {
|
|||
let painter = ui.painter_at(text_clip_rect);
|
||||
|
||||
if interactive {
|
||||
if let Some(pointer_pos) = ui.input().pointer.interact_pos() {
|
||||
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() {
|
||||
if response.hovered() && text.is_mutable() {
|
||||
ui.output().mutable_text_under_cursor = true;
|
||||
}
|
||||
|
@ -665,7 +665,8 @@ fn events(
|
|||
|
||||
let mut any_change = false;
|
||||
|
||||
for event in &ui.input().events {
|
||||
let events = ui.input().events.clone(); // avoid dead-lock by cloning. TODO: optimize
|
||||
for event in &events {
|
||||
let did_mutate_text = match event {
|
||||
Event::Copy => {
|
||||
if cursor_range.is_empty() {
|
||||
|
|
|
@ -4,16 +4,16 @@ use egui::epaint::TextShape;
|
|||
use egui_demo_lib::LOREM_IPSUM_LONG;
|
||||
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
let raw_input = egui::RawInput::default();
|
||||
use egui::RawInput;
|
||||
|
||||
{
|
||||
let mut ctx = egui::CtxRef::default();
|
||||
let ctx = egui::Context::default();
|
||||
let mut demo_windows = egui_demo_lib::DemoWindows::default();
|
||||
|
||||
// The most end-to-end benchmark.
|
||||
c.bench_function("demo_with_tessellate__realistic", |b| {
|
||||
b.iter(|| {
|
||||
let (_output, shapes) = ctx.run(raw_input.clone(), |ctx| {
|
||||
let (_output, shapes) = ctx.run(RawInput::default(), |ctx| {
|
||||
demo_windows.ui(ctx);
|
||||
});
|
||||
ctx.tessellate(shapes)
|
||||
|
@ -22,13 +22,13 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
|
||||
c.bench_function("demo_no_tessellate", |b| {
|
||||
b.iter(|| {
|
||||
ctx.run(raw_input.clone(), |ctx| {
|
||||
ctx.run(RawInput::default(), |ctx| {
|
||||
demo_windows.ui(ctx);
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
let (_output, shapes) = ctx.run(raw_input.clone(), |ctx| {
|
||||
let (_output, shapes) = ctx.run(RawInput::default(), |ctx| {
|
||||
demo_windows.ui(ctx);
|
||||
});
|
||||
c.bench_function("demo_only_tessellate", |b| {
|
||||
|
@ -37,12 +37,12 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
}
|
||||
|
||||
if false {
|
||||
let mut ctx = egui::CtxRef::default();
|
||||
let ctx = egui::Context::default();
|
||||
ctx.memory().set_everything_is_visible(true); // give us everything
|
||||
let mut demo_windows = egui_demo_lib::DemoWindows::default();
|
||||
c.bench_function("demo_full_no_tessellate", |b| {
|
||||
b.iter(|| {
|
||||
ctx.run(raw_input.clone(), |ctx| {
|
||||
ctx.run(RawInput::default(), |ctx| {
|
||||
demo_windows.ui(ctx);
|
||||
})
|
||||
})
|
||||
|
@ -50,8 +50,8 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
}
|
||||
|
||||
{
|
||||
let mut ctx = egui::CtxRef::default();
|
||||
let _ = ctx.run(raw_input, |ctx| {
|
||||
let ctx = egui::Context::default();
|
||||
let _ = ctx.run(RawInput::default(), |ctx| {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
c.bench_function("label &str", |b| {
|
||||
b.iter(|| {
|
||||
|
@ -67,6 +67,23 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
{
|
||||
let ctx = egui::Context::default();
|
||||
ctx.begin_frame(RawInput::default());
|
||||
|
||||
egui::CentralPanel::default().show(&ctx, |ui| {
|
||||
c.bench_function("Painter::rect", |b| {
|
||||
let painter = ui.painter();
|
||||
let rect = ui.max_rect();
|
||||
b.iter(|| {
|
||||
painter.rect(rect, 2.0, egui::Color32::RED, (1.0, egui::Color32::WHITE));
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Don't call `end_frame` to not have to drain the huge paint list
|
||||
}
|
||||
|
||||
{
|
||||
let pixels_per_point = 1.0;
|
||||
let wrap_width = 512.0;
|
||||
|
|
|
@ -34,7 +34,7 @@ impl epi::App for ColorTest {
|
|||
"🎨 Color test"
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
if frame.is_web() {
|
||||
ui.label(
|
||||
|
|
|
@ -16,7 +16,7 @@ impl epi::App for DemoApp {
|
|||
|
||||
fn setup(
|
||||
&mut self,
|
||||
_ctx: &egui::CtxRef,
|
||||
_ctx: &egui::Context,
|
||||
_frame: &epi::Frame,
|
||||
_storage: Option<&dyn epi::Storage>,
|
||||
) {
|
||||
|
@ -31,7 +31,7 @@ impl epi::App for DemoApp {
|
|||
epi::set_value(storage, epi::APP_KEY, self);
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||
self.demo_windows.ui(ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ impl super::Demo for CodeEditor {
|
|||
"🖮 Code Editor"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
use super::View as _;
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
|
|
|
@ -68,7 +68,7 @@ impl super::Demo for CodeExample {
|
|||
"🖮 Code Example"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
use super::View;
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
|
|
|
@ -47,7 +47,7 @@ impl super::Demo for ContextMenus {
|
|||
"☰ Context Menus"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
use super::View;
|
||||
egui::Window::new(self.name())
|
||||
.vscroll(false)
|
||||
|
|
|
@ -10,7 +10,7 @@ impl super::Demo for DancingStrings {
|
|||
"♫ Dancing Strings"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &Context, open: &mut bool) {
|
||||
use super::View as _;
|
||||
Window::new(self.name())
|
||||
.open(open)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::Demo;
|
||||
use egui::{CtxRef, ScrollArea, Ui};
|
||||
use egui::{Context, ScrollArea, Ui};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -58,7 +58,7 @@ impl Demos {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn windows(&mut self, ctx: &CtxRef) {
|
||||
pub fn windows(&mut self, ctx: &Context) {
|
||||
let Self { demos, open } = self;
|
||||
for demo in demos {
|
||||
let mut is_open = open.contains(demo.name());
|
||||
|
@ -113,7 +113,7 @@ impl Tests {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn windows(&mut self, ctx: &CtxRef) {
|
||||
pub fn windows(&mut self, ctx: &Context) {
|
||||
let Self { demos, open } = self;
|
||||
for demo in demos {
|
||||
let mut is_open = open.contains(demo.name());
|
||||
|
@ -149,7 +149,7 @@ pub struct DemoWindows {
|
|||
impl DemoWindows {
|
||||
/// Show the app ui (menu bar and windows).
|
||||
/// `sidebar_ui` can be used to optionally show some things in the sidebar
|
||||
pub fn ui(&mut self, ctx: &CtxRef) {
|
||||
pub fn ui(&mut self, ctx: &Context) {
|
||||
let Self { demos, tests } = self;
|
||||
|
||||
egui::SidePanel::right("egui_demo_panel")
|
||||
|
@ -214,7 +214,7 @@ impl DemoWindows {
|
|||
}
|
||||
|
||||
/// Show the open windows.
|
||||
fn windows(&mut self, ctx: &CtxRef) {
|
||||
fn windows(&mut self, ctx: &Context) {
|
||||
let Self { demos, tests } = self;
|
||||
|
||||
demos.windows(ctx);
|
||||
|
|
|
@ -25,7 +25,7 @@ pub fn drag_source(ui: &mut Ui, id: Id, body: impl FnOnce(&mut Ui)) {
|
|||
// (anything with `Order::Tooltip` always gets an empty `Response`)
|
||||
// So this is fine!
|
||||
|
||||
if let Some(pointer_pos) = ui.input().pointer.interact_pos() {
|
||||
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() {
|
||||
let delta = pointer_pos - response.rect.center();
|
||||
ui.ctx().translate_layer(layer_id, delta);
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ impl super::Demo for DragAndDropDemo {
|
|||
"✋ Drag and Drop"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &Context, open: &mut bool) {
|
||||
use super::View as _;
|
||||
Window::new(self.name())
|
||||
.open(open)
|
||||
|
|
|
@ -21,7 +21,7 @@ impl super::Demo for FontBook {
|
|||
"🔤 Font Book"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
||||
use super::View as _;
|
||||
self.ui(ui);
|
||||
|
|
|
@ -76,7 +76,7 @@ impl super::Demo for LayoutTest {
|
|||
"Layout Test"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.resizable(false)
|
||||
|
|
|
@ -31,7 +31,7 @@ impl Demo for MiscDemoWindow {
|
|||
"✨ Misc Demos"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &Context, open: &mut bool) {
|
||||
Window::new(self.name())
|
||||
.open(open)
|
||||
.vscroll(true)
|
||||
|
@ -140,7 +140,8 @@ impl Widgets {
|
|||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
// Trick so we don't have to add spaces in the text below:
|
||||
ui.spacing_mut().item_spacing.x = ui.fonts()[TextStyle::Body].glyph_width(' ');
|
||||
let width = ui.fonts()[TextStyle::Body].glyph_width(' ');
|
||||
ui.spacing_mut().item_spacing.x = width;
|
||||
|
||||
ui.label(RichText::new("Text can have").color(Color32::from_rgb(110, 255, 110)));
|
||||
ui.colored_label(Color32::from_rgb(128, 140, 255), "color"); // Shortcut version
|
||||
|
|
|
@ -45,5 +45,5 @@ pub trait Demo {
|
|||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Show windows, etc
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool);
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ impl super::Demo for MultiTouch {
|
|||
"👌 Multi Touch"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.default_size(vec2(512.0, 512.0))
|
||||
|
@ -77,7 +77,7 @@ impl super::View for MultiTouch {
|
|||
// color and width:
|
||||
let mut stroke_width = 1.;
|
||||
let color = Color32::GRAY;
|
||||
if let Some(multi_touch) = ui.input().multi_touch() {
|
||||
if let Some(multi_touch) = ui.ctx().multi_touch() {
|
||||
// This adjusts the current zoom factor and rotation angle according to the dynamic
|
||||
// change (for the current frame) of the touch gesture:
|
||||
self.zoom *= multi_touch.zoom_delta;
|
||||
|
|
|
@ -74,7 +74,7 @@ impl super::Demo for Painting {
|
|||
"🖊 Painting"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &Context, open: &mut bool) {
|
||||
use super::View as _;
|
||||
Window::new(self.name())
|
||||
.open(open)
|
||||
|
|
|
@ -647,7 +647,7 @@ impl super::Demo for PlotDemo {
|
|||
"🗠 Plot"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &Context, open: &mut bool) {
|
||||
use super::View as _;
|
||||
Window::new(self.name())
|
||||
.open(open)
|
||||
|
|
|
@ -29,7 +29,7 @@ impl super::Demo for Scrolling {
|
|||
"↕ Scrolling"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.resizable(false)
|
||||
|
|
|
@ -36,7 +36,7 @@ impl super::Demo for Sliders {
|
|||
"⬌ Sliders"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.resizable(false)
|
||||
|
|
|
@ -6,7 +6,7 @@ impl super::Demo for CursorTest {
|
|||
"Cursor Test"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
||||
use super::View as _;
|
||||
self.ui(ui);
|
||||
|
@ -38,7 +38,7 @@ impl super::Demo for IdTest {
|
|||
"ID Test"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
||||
use super::View as _;
|
||||
self.ui(ui);
|
||||
|
@ -115,7 +115,7 @@ impl super::Demo for ManualLayoutTest {
|
|||
"Manual Layout Test"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.resizable(false)
|
||||
.open(open)
|
||||
|
@ -202,7 +202,7 @@ impl super::Demo for TableTest {
|
|||
"Table Test"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
||||
use super::View as _;
|
||||
self.ui(ui);
|
||||
|
@ -314,7 +314,7 @@ impl super::Demo for InputTest {
|
|||
"Input Test"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.resizable(false)
|
||||
|
@ -383,7 +383,7 @@ impl super::Demo for WindowResizeTest {
|
|||
"↔ Window Resize"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
use egui::*;
|
||||
|
||||
Window::new("↔ auto-sized")
|
||||
|
|
|
@ -19,7 +19,7 @@ impl super::Demo for TextEdit {
|
|||
"🖹 TextEdit"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.resizable(false)
|
||||
|
|
|
@ -39,7 +39,7 @@ impl super::Demo for WidgetGallery {
|
|||
"🗄 Widget Gallery"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
egui::Window::new(self.name())
|
||||
.open(open)
|
||||
.resizable(true)
|
||||
|
|
|
@ -36,7 +36,7 @@ impl super::Demo for WindowOptions {
|
|||
"🗖 Window Options"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
let Self {
|
||||
title,
|
||||
title_bar,
|
||||
|
|
|
@ -7,7 +7,7 @@ impl super::Demo for WindowWithPanels {
|
|||
"🗖 Window With Panels"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
use super::View as _;
|
||||
let window = egui::Window::new("Window with Panels")
|
||||
.default_width(600.0)
|
||||
|
|
|
@ -37,7 +37,7 @@ impl epi::App for FractalClock {
|
|||
"🕑 Fractal Clock"
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||
egui::CentralPanel::default()
|
||||
.frame(Frame::dark_canvas(&ctx.style()))
|
||||
.show(ctx, |ui| self.ui(ui, crate::seconds_since_midnight()));
|
||||
|
|
|
@ -67,7 +67,7 @@ impl epi::App for HttpApp {
|
|||
"⬇ HTTP"
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
if let Some(receiver) = &mut self.in_progress {
|
||||
// Are we there yet?
|
||||
if let Ok(result) = receiver.try_recv() {
|
||||
|
|
|
@ -78,7 +78,7 @@ impl Default for BackendPanel {
|
|||
}
|
||||
|
||||
impl BackendPanel {
|
||||
pub fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
pub fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
self.frame_history
|
||||
.on_new_frame(ctx.input().time, frame.info().cpu_usage);
|
||||
|
||||
|
@ -88,7 +88,7 @@ impl BackendPanel {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn end_of_frame(&mut self, ctx: &egui::CtxRef) {
|
||||
pub fn end_of_frame(&mut self, ctx: &egui::Context) {
|
||||
self.egui_windows.windows(ctx);
|
||||
}
|
||||
|
||||
|
@ -325,7 +325,7 @@ impl EguiWindows {
|
|||
ui.checkbox(output_events, "📤 Output Events");
|
||||
}
|
||||
|
||||
fn windows(&mut self, ctx: &egui::CtxRef) {
|
||||
fn windows(&mut self, ctx: &egui::Context) {
|
||||
let Self {
|
||||
settings,
|
||||
inspection,
|
||||
|
|
|
@ -34,7 +34,7 @@ impl epi::App for EasyMarkEditor {
|
|||
"🖹 EasyMark editor"
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||
egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |ui| {
|
||||
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
|
||||
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
|
||||
|
|
|
@ -18,7 +18,8 @@ pub fn easy_mark_it<'em>(ui: &mut Ui, items: impl Iterator<Item = easy_mark::Ite
|
|||
|
||||
ui.allocate_ui_with_layout(initial_size, layout, |ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.set_row_height(ui.fonts()[TextStyle::Body].row_height());
|
||||
let row_height = (*ui.fonts())[TextStyle::Body].row_height();
|
||||
ui.set_row_height(row_height);
|
||||
|
||||
for item in items {
|
||||
item_ui(ui, item);
|
||||
|
|
|
@ -94,7 +94,7 @@ impl FrameHistory {
|
|||
let cpu_usage = to_screen.inverse().transform_pos(pointer_pos).y;
|
||||
let text = format!("{:.1} ms", 1e3 * cpu_usage);
|
||||
shapes.push(Shape::text(
|
||||
ui.fonts(),
|
||||
&*ui.fonts(),
|
||||
pos2(rect.left(), y),
|
||||
egui::Align2::LEFT_BOTTOM,
|
||||
text,
|
||||
|
|
|
@ -140,7 +140,7 @@ Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, tur
|
|||
#[test]
|
||||
fn test_egui_e2e() {
|
||||
let mut demo_windows = crate::DemoWindows::default();
|
||||
let mut ctx = egui::CtxRef::default();
|
||||
let ctx = egui::Context::default();
|
||||
let raw_input = egui::RawInput::default();
|
||||
|
||||
const NUM_FRAMES: usize = 5;
|
||||
|
@ -156,7 +156,7 @@ fn test_egui_e2e() {
|
|||
#[test]
|
||||
fn test_egui_zero_window_size() {
|
||||
let mut demo_windows = crate::DemoWindows::default();
|
||||
let mut ctx = egui::CtxRef::default();
|
||||
let ctx = egui::Context::default();
|
||||
let raw_input = egui::RawInput {
|
||||
screen_rect: Some(egui::Rect::from_min_max(egui::Pos2::ZERO, egui::Pos2::ZERO)),
|
||||
..Default::default()
|
||||
|
|
|
@ -44,7 +44,7 @@ impl epi::App for WrapApp {
|
|||
|
||||
fn setup(
|
||||
&mut self,
|
||||
_ctx: &egui::CtxRef,
|
||||
_ctx: &egui::Context,
|
||||
_frame: &epi::Frame,
|
||||
_storage: Option<&dyn epi::Storage>,
|
||||
) {
|
||||
|
@ -72,7 +72,7 @@ impl epi::App for WrapApp {
|
|||
cfg!(not(debug_assertions))
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||
if let Some(web_info) = frame.info().web_info.as_ref() {
|
||||
if let Some(anchor) = web_info.web_location_hash.strip_prefix('#') {
|
||||
self.selected_anchor = anchor.to_owned();
|
||||
|
@ -165,7 +165,7 @@ impl WrapApp {
|
|||
});
|
||||
}
|
||||
|
||||
fn ui_file_drag_and_drop(&mut self, ctx: &egui::CtxRef) {
|
||||
fn ui_file_drag_and_drop(&mut self, ctx: &egui::Context) {
|
||||
use egui::*;
|
||||
|
||||
// Preview hovering files:
|
||||
|
|
|
@ -101,7 +101,7 @@ pub use egui_winit;
|
|||
|
||||
/// Convenience wrapper for using [`egui`] from a [`glium`] app.
|
||||
pub struct EguiGlium {
|
||||
pub egui_ctx: egui::CtxRef,
|
||||
pub egui_ctx: egui::Context,
|
||||
pub egui_winit: egui_winit::State,
|
||||
pub painter: crate::Painter,
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ impl EguiGlium {
|
|||
pub fn run(
|
||||
&mut self,
|
||||
display: &glium::Display,
|
||||
run_ui: impl FnMut(&egui::CtxRef),
|
||||
run_ui: impl FnMut(&egui::Context),
|
||||
) -> (bool, Vec<egui::epaint::ClippedShape>) {
|
||||
let raw_input = self
|
||||
.egui_winit
|
||||
|
|
|
@ -109,7 +109,7 @@ pub use epi_backend::{run, NativeOptions};
|
|||
/// Use [`egui`] from a [`glow`] app.
|
||||
#[cfg(feature = "winit")]
|
||||
pub struct EguiGlow {
|
||||
pub egui_ctx: egui::CtxRef,
|
||||
pub egui_ctx: egui::Context,
|
||||
pub egui_winit: egui_winit::State,
|
||||
pub painter: crate::Painter,
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ impl EguiGlow {
|
|||
pub fn run(
|
||||
&mut self,
|
||||
window: &glutin::window::Window,
|
||||
run_ui: impl FnMut(&egui::CtxRef),
|
||||
run_ui: impl FnMut(&egui::Context),
|
||||
) -> (bool, Vec<egui::epaint::ClippedShape>) {
|
||||
let raw_input = self.egui_winit.take_egui_input(window);
|
||||
let (egui_output, shapes) = self.egui_ctx.run(raw_input, run_ui);
|
||||
|
|
|
@ -82,7 +82,7 @@ impl epi::backend::RepaintSignal for NeedRepaint {
|
|||
|
||||
pub struct AppRunner {
|
||||
frame: epi::Frame,
|
||||
egui_ctx: egui::CtxRef,
|
||||
egui_ctx: egui::Context,
|
||||
painter: Box<dyn Painter>,
|
||||
pub(crate) input: WebInput,
|
||||
app: Box<dyn epi::App>,
|
||||
|
@ -117,7 +117,7 @@ impl AppRunner {
|
|||
repaint_signal: needs_repaint.clone(),
|
||||
});
|
||||
|
||||
let egui_ctx = egui::CtxRef::default();
|
||||
let egui_ctx = egui::Context::default();
|
||||
load_memory(&egui_ctx);
|
||||
if prefer_dark_mode == Some(true) {
|
||||
egui_ctx.set_visuals(egui::Visuals::dark());
|
||||
|
@ -151,7 +151,7 @@ impl AppRunner {
|
|||
Ok(runner)
|
||||
}
|
||||
|
||||
pub fn egui_ctx(&self) -> &egui::CtxRef {
|
||||
pub fn egui_ctx(&self) -> &egui::Context {
|
||||
&self.egui_ctx
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ impl AppRunner {
|
|||
|
||||
pub fn warm_up(&mut self) -> Result<(), JsValue> {
|
||||
if self.app.warm_up_enabled() {
|
||||
let saved_memory = self.egui_ctx.memory().clone();
|
||||
let saved_memory: egui::Memory = self.egui_ctx.memory().clone();
|
||||
self.egui_ctx.memory().set_everything_is_visible(true);
|
||||
self.logic()?;
|
||||
*self.egui_ctx.memory() = saved_memory; // We don't want to remember that windows were huge.
|
||||
|
|
|
@ -114,10 +114,10 @@ mod mutex_impl {
|
|||
#[cfg(feature = "multi_threaded")]
|
||||
mod rw_lock_impl {
|
||||
/// The lock you get from [`RwLock::read`].
|
||||
pub use parking_lot::RwLockReadGuard;
|
||||
pub use parking_lot::MappedRwLockReadGuard as RwLockReadGuard;
|
||||
|
||||
/// The lock you get from [`RwLock::write`].
|
||||
pub use parking_lot::RwLockWriteGuard;
|
||||
pub use parking_lot::MappedRwLockWriteGuard as RwLockWriteGuard;
|
||||
|
||||
/// Provides interior mutability. Only thread-safe if the `multi_threaded` feature is enabled.
|
||||
#[derive(Default)]
|
||||
|
@ -131,16 +131,21 @@ mod rw_lock_impl {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn read(&self) -> RwLockReadGuard<'_, T> {
|
||||
self.0.read()
|
||||
parking_lot::RwLockReadGuard::map(self.0.read(), |v| v)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
|
||||
self.0.write()
|
||||
parking_lot::RwLockWriteGuard::map(self.0.write(), |v| v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "multi_threaded")]
|
||||
mod arc_impl {
|
||||
pub use std::sync::Arc;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[cfg(not(feature = "multi_threaded"))]
|
||||
|
@ -201,8 +206,15 @@ mod rw_lock_impl {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "multi_threaded"))]
|
||||
mod arc_impl {
|
||||
// pub use std::rc::Rc as Arc; // TODO(emilk): optimize single threaded code by using `Rc` instead of `Arc`.
|
||||
pub use std::sync::Arc;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub use arc_impl::Arc;
|
||||
pub use mutex_impl::{Mutex, MutexGuard};
|
||||
pub use rw_lock_impl::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ impl Shape {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn galley(pos: Pos2, galley: std::sync::Arc<Galley>) -> Self {
|
||||
pub fn galley(pos: Pos2, galley: crate::mutex::Arc<Galley>) -> Self {
|
||||
TextShape::new(pos, galley).into()
|
||||
}
|
||||
|
||||
|
@ -355,7 +355,7 @@ pub struct TextShape {
|
|||
pub pos: Pos2,
|
||||
|
||||
/// The layed out text, from [`Fonts::layout_job`].
|
||||
pub galley: std::sync::Arc<Galley>,
|
||||
pub galley: crate::mutex::Arc<Galley>,
|
||||
|
||||
/// Add this underline to the whole text.
|
||||
/// You can also set an underline when creating the galley.
|
||||
|
@ -373,7 +373,7 @@ pub struct TextShape {
|
|||
|
||||
impl TextShape {
|
||||
#[inline]
|
||||
pub fn new(pos: Pos2, galley: std::sync::Arc<Galley>) -> Self {
|
||||
pub fn new(pos: Pos2, galley: crate::mutex::Arc<Galley>) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
galley,
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use crate::{
|
||||
mutex::{Mutex, RwLock},
|
||||
mutex::{Arc, Mutex, RwLock},
|
||||
text::TextStyle,
|
||||
TextureAtlas,
|
||||
};
|
||||
use ahash::AHashMap;
|
||||
use emath::{vec2, Vec2};
|
||||
use std::collections::BTreeSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::BTreeMap, sync::Arc};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::{
|
||||
mutex::Mutex,
|
||||
mutex::{Arc, Mutex},
|
||||
text::{
|
||||
font::{Font, FontImpl},
|
||||
Galley, LayoutJob,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::ops::RangeInclusive;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{Fonts, Galley, Glyph, LayoutJob, LayoutSection, Row, RowVisuals};
|
||||
use crate::{Color32, Mesh, Stroke, Vertex};
|
||||
use crate::{mutex::Arc, Color32, Mesh, Stroke, Vertex};
|
||||
use emath::*;
|
||||
|
||||
/// Temporary storage before line-wrapping.
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#![allow(clippy::derive_hash_xor_eq)] // We need to impl Hash for f32, but we don't implement Eq, which is fine
|
||||
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{cursor::*, font::UvRect};
|
||||
use crate::{Color32, Mesh, Stroke, TextStyle};
|
||||
use crate::{mutex::Arc, Color32, Mesh, Stroke, TextStyle};
|
||||
use emath::*;
|
||||
|
||||
/// Describes the task of laying out text.
|
||||
|
|
|
@ -106,11 +106,11 @@ pub trait App {
|
|||
///
|
||||
/// Put your widgets into a [`egui::SidePanel`], [`egui::TopBottomPanel`], [`egui::CentralPanel`], [`egui::Window`] or [`egui::Area`].
|
||||
///
|
||||
/// The given [`egui::CtxRef`] is only valid for the duration of this call.
|
||||
/// The [`Frame`] however can be cloned and saved.
|
||||
/// The [`egui::Context`] and [`Frame`] can be cloned and saved if you like.
|
||||
///
|
||||
/// To force a repaint, call either [`egui::Context::request_repaint`] or [`Frame::request_repaint`].
|
||||
fn update(&mut self, ctx: &egui::CtxRef, frame: &Frame);
|
||||
/// To force a repaint, call either [`egui::Context::request_repaint`] during the call to `update`,
|
||||
/// or call [`Frame::request_repaint`] at any time (e.g. from another thread).
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &Frame);
|
||||
|
||||
/// Called once before the first frame.
|
||||
///
|
||||
|
@ -118,7 +118,7 @@ pub trait App {
|
|||
/// [`egui::Context::set_visuals`] etc.
|
||||
///
|
||||
/// Also allows you to restore state, if there is a storage (required the "persistence" feature).
|
||||
fn setup(&mut self, _ctx: &egui::CtxRef, _frame: &Frame, _storage: Option<&dyn Storage>) {}
|
||||
fn setup(&mut self, _ctx: &egui::Context, _frame: &Frame, _storage: Option<&dyn Storage>) {}
|
||||
|
||||
/// If `true` a warm-up call to [`Self::update`] will be issued where
|
||||
/// `ctx.memory().everything_is_visible()` will be set to `true`.
|
||||
|
|
Loading…
Reference in a new issue