mirror of
https://github.com/emilk/egui.git
synced 2026-09-03 07:10:04 -04:00
Fix mouse input
Now on Context.create_viewport in the render function will we have viewport_id and parent_viewport_id New problem if a windows is fucused and we interact with other window the first event will be send to the last window that was focused
This commit is contained in:
@@ -432,7 +432,7 @@ impl EpiIntegration {
|
|||||||
let saved_memory: egui::Memory = self.egui_ctx.memory(|mem| mem.clone());
|
let saved_memory: egui::Memory = self.egui_ctx.memory(|mem| mem.clone());
|
||||||
self.egui_ctx
|
self.egui_ctx
|
||||||
.memory_mut(|mem| mem.set_everything_is_visible(true));
|
.memory_mut(|mem| mem.set_everything_is_visible(true));
|
||||||
let full_output = self.update(app, window, egui_winit, None);
|
let full_output = self.update(app, window, egui_winit, None, 0, 0);
|
||||||
self.pending_full_output.append(full_output); // Handle it next frame
|
self.pending_full_output.append(full_output); // Handle it next frame
|
||||||
self.egui_ctx.memory_mut(|mem| *mem = saved_memory); // We don't want to remember that windows were huge.
|
self.egui_ctx.memory_mut(|mem| *mem = saved_memory); // We don't want to remember that windows were huge.
|
||||||
self.egui_ctx.clear_animations();
|
self.egui_ctx.clear_animations();
|
||||||
@@ -496,7 +496,9 @@ impl EpiIntegration {
|
|||||||
app: &mut dyn epi::App,
|
app: &mut dyn epi::App,
|
||||||
window: &winit::window::Window,
|
window: &winit::window::Window,
|
||||||
egui_winit: &mut egui_winit::State,
|
egui_winit: &mut egui_winit::State,
|
||||||
render: Option<Arc<Box<dyn Fn(&Context) + Sync + Send>>>,
|
render: Option<Arc<Box<dyn Fn(&Context, u64, u64) + Sync + Send>>>,
|
||||||
|
viewport_id: u64,
|
||||||
|
parent_id: u64,
|
||||||
) -> egui::FullOutput {
|
) -> egui::FullOutput {
|
||||||
let frame_start = std::time::Instant::now();
|
let frame_start = std::time::Instant::now();
|
||||||
|
|
||||||
@@ -511,7 +513,7 @@ impl EpiIntegration {
|
|||||||
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
|
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
|
||||||
crate::profile_scope!("App::update");
|
crate::profile_scope!("App::update");
|
||||||
if let Some(render) = render {
|
if let Some(render) = render {
|
||||||
(render.as_ref())(egui_ctx)
|
(render.as_ref())(egui_ctx, viewport_id, parent_id)
|
||||||
} else {
|
} else {
|
||||||
app.update(egui_ctx, &mut self.frame);
|
app.update(egui_ctx, &mut self.frame);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -454,7 +454,8 @@ mod glow_integration {
|
|||||||
gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
|
gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
|
||||||
window: Option<winit::window::Window>,
|
window: Option<winit::window::Window>,
|
||||||
window_id: u64,
|
window_id: u64,
|
||||||
render: Option<Arc<Box<dyn Fn(&Context) + Sync + Send>>>,
|
parent_id: u64,
|
||||||
|
render: Option<Arc<Box<dyn Fn(&Context, u64, u64) + Sync + Send>>>,
|
||||||
pub egui_winit: Option<egui_winit::State>,
|
pub egui_winit: Option<egui_winit::State>,
|
||||||
}
|
}
|
||||||
/// This struct will contain both persistent and temporary glutin state.
|
/// This struct will contain both persistent and temporary glutin state.
|
||||||
@@ -603,6 +604,7 @@ mod glow_integration {
|
|||||||
window_id: 0,
|
window_id: 0,
|
||||||
egui_winit: None,
|
egui_winit: None,
|
||||||
render: None,
|
render: None,
|
||||||
|
parent_id: 0,
|
||||||
}],
|
}],
|
||||||
window_maps,
|
window_maps,
|
||||||
})
|
})
|
||||||
@@ -1007,6 +1009,13 @@ mod glow_integration {
|
|||||||
painter,
|
painter,
|
||||||
} = running;
|
} = running;
|
||||||
|
|
||||||
|
let mut window_map = HashMap::default();
|
||||||
|
for window in gl_window.windows.iter() {
|
||||||
|
if let Some(win) = &window.window {
|
||||||
|
window_map.insert(window.window_id, win.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let egui::FullOutput {
|
let egui::FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
repaint_after,
|
repaint_after,
|
||||||
@@ -1052,6 +1061,8 @@ mod glow_integration {
|
|||||||
win.window.as_ref().unwrap(),
|
win.window.as_ref().unwrap(),
|
||||||
win.egui_winit.as_mut().unwrap(),
|
win.egui_winit.as_mut().unwrap(),
|
||||||
win.render.clone(),
|
win.render.clone(),
|
||||||
|
win.window_id,
|
||||||
|
win.parent_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
integration.handle_platform_output(
|
integration.handle_platform_output(
|
||||||
@@ -1123,11 +1134,19 @@ mod glow_integration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
control_flow = if integration.should_close() {
|
control_flow = if integration.should_close() {
|
||||||
EventResult::Exit
|
vec![EventResult::Exit]
|
||||||
} else if repaint_after.is_zero() {
|
} else {
|
||||||
EventResult::RepaintNext(win.window.as_ref().unwrap().id())
|
repaint_after
|
||||||
|
.into_iter()
|
||||||
|
.map(|(id, time)| {
|
||||||
|
if time.is_zero() {
|
||||||
|
if let Some(id) = window_map.get(&id) {
|
||||||
|
Some(EventResult::RepaintNext(*id))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
} else if let Some(repaint_after_instant) =
|
} else if let Some(repaint_after_instant) =
|
||||||
std::time::Instant::now().checked_add(repaint_after)
|
std::time::Instant::now().checked_add(time)
|
||||||
{
|
{
|
||||||
// if repaint_after is something huge and can't be added to Instant,
|
// if repaint_after is something huge and can't be added to Instant,
|
||||||
// we will use `ControlFlow::Wait` instead.
|
// we will use `ControlFlow::Wait` instead.
|
||||||
@@ -1135,12 +1154,17 @@ mod glow_integration {
|
|||||||
// winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own
|
// winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own
|
||||||
// egui backend impl i guess.
|
// egui backend impl i guess.
|
||||||
|
|
||||||
EventResult::RepaintAt(
|
if let Some(id) = window_map.get(&id) {
|
||||||
win.window.as_ref().unwrap().id(),
|
Some(EventResult::RepaintAt(*id, repaint_after_instant))
|
||||||
repaint_after_instant,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
EventResult::Wait
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<EventResult>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
integration.maybe_autosave(app.as_mut(), win.window.as_ref().unwrap());
|
integration.maybe_autosave(app.as_mut(), win.window.as_ref().unwrap());
|
||||||
@@ -1156,7 +1180,7 @@ mod glow_integration {
|
|||||||
// 0 is the main viewport/window that will not be known by the egui_ctx
|
// 0 is the main viewport/window that will not be known by the egui_ctx
|
||||||
let mut active_viewports_ids = vec![0];
|
let mut active_viewports_ids = vec![0];
|
||||||
|
|
||||||
viewports.retain_mut(|(id, builder, render)| {
|
viewports.retain_mut(|(id, parent, builder, render)| {
|
||||||
for w in gl_window.windows.iter_mut() {
|
for w in gl_window.windows.iter_mut() {
|
||||||
if w.window_id == *id {
|
if w.window_id == *id {
|
||||||
if w.builder != *builder {
|
if w.builder != *builder {
|
||||||
@@ -1169,6 +1193,7 @@ mod glow_integration {
|
|||||||
w.gl_surface = None;
|
w.gl_surface = None;
|
||||||
w.render = Some(render.clone());
|
w.render = Some(render.clone());
|
||||||
w.builder = builder.clone();
|
w.builder = builder.clone();
|
||||||
|
w.parent_id = *id;
|
||||||
}
|
}
|
||||||
active_viewports_ids.push(*id);
|
active_viewports_ids.push(*id);
|
||||||
return false;
|
return false;
|
||||||
@@ -1177,7 +1202,7 @@ mod glow_integration {
|
|||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
for (id, builder, render) in viewports {
|
for (id, parent, builder, render) in viewports {
|
||||||
gl_window.windows.push(Window {
|
gl_window.windows.push(Window {
|
||||||
builder,
|
builder,
|
||||||
gl_surface: None,
|
gl_surface: None,
|
||||||
@@ -1185,6 +1210,7 @@ mod glow_integration {
|
|||||||
window_id: id,
|
window_id: id,
|
||||||
egui_winit: None,
|
egui_winit: None,
|
||||||
render: Some(render.clone()),
|
render: Some(render.clone()),
|
||||||
|
parent_id: parent,
|
||||||
});
|
});
|
||||||
active_viewports_ids.push(id);
|
active_viewports_ids.push(id);
|
||||||
}
|
}
|
||||||
@@ -1199,10 +1225,15 @@ mod glow_integration {
|
|||||||
control_flow
|
control_flow
|
||||||
};
|
};
|
||||||
|
|
||||||
windows_indexes
|
let mut events = vec![EventResult::Wait];
|
||||||
|
|
||||||
|
for event in windows_indexes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|window_index| inner(window_index))
|
.map(|window_index| inner(window_index))
|
||||||
.collect()
|
{
|
||||||
|
events.extend(event)
|
||||||
|
}
|
||||||
|
events
|
||||||
} else {
|
} else {
|
||||||
vec![EventResult::Wait]
|
vec![EventResult::Wait]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -417,11 +417,19 @@ impl<'open> Window<'open> {
|
|||||||
/// Returns `None` if the window is not open (if [`Window::open`] was called with `&mut false`).
|
/// Returns `None` if the window is not open (if [`Window::open`] was called with `&mut false`).
|
||||||
/// Returns `Some(InnerResponse { inner: None })` if the window is collapsed.
|
/// Returns `Some(InnerResponse { inner: None })` if the window is collapsed.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn show(self, ctx: &Context, add_contents: impl Fn(&mut Ui) + Send + Sync + 'static) {
|
pub fn show(
|
||||||
|
self,
|
||||||
|
ctx: &Context,
|
||||||
|
add_contents: impl Fn(&mut Ui, u64, u64) + Send + Sync + 'static,
|
||||||
|
) {
|
||||||
self.show_dyn(ctx, Box::new(add_contents))
|
self.show_dyn(ctx, Box::new(add_contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_dyn(self, ctx: &Context, add_contents: Box<dyn Fn(&mut Ui) + Send + Sync + 'static>) {
|
fn show_dyn(
|
||||||
|
self,
|
||||||
|
ctx: &Context,
|
||||||
|
add_contents: Box<dyn Fn(&mut Ui, u64, u64) + Send + Sync + 'static>,
|
||||||
|
) {
|
||||||
let Window {
|
let Window {
|
||||||
title,
|
title,
|
||||||
open,
|
open,
|
||||||
@@ -448,16 +456,16 @@ impl<'open> Window<'open> {
|
|||||||
window_builder.with_inner_size((size.x as u32 + 1, size.y as u32 + 1));
|
window_builder.with_inner_size((size.x as u32 + 1, size.y as u32 + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.create_viewport(window_builder, move |ctx| {
|
ctx.create_viewport(
|
||||||
|
window_builder,
|
||||||
|
move |ctx, viewport_id, parent_viewport_id| {
|
||||||
let mut frame = frame.unwrap_or(Frame::window(&ctx.style())).rounding(0.0);
|
let mut frame = frame.unwrap_or(Frame::window(&ctx.style())).rounding(0.0);
|
||||||
CentralPanel::default()
|
CentralPanel::default().frame(frame).show(ctx, |ui| {
|
||||||
.frame(frame)
|
Some(add_contents(ui, viewport_id, parent_viewport_id))
|
||||||
.show(ctx, |ui| Some(add_contents(ui)));
|
});
|
||||||
})
|
},
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if ctx.current_viewport() != ctx.current_rendering_viewport() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
|
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
|
||||||
|
|
||||||
area.show_open_close_animation(ctx, &frame, is_open);
|
area.show_open_close_animation(ctx, &frame, is_open);
|
||||||
@@ -555,9 +563,9 @@ impl<'open> Window<'open> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if scroll.has_any_bar() {
|
if scroll.has_any_bar() {
|
||||||
scroll.show(ui, add_contents).inner
|
scroll.show(ui, |ui| add_contents(ui, 0, 0)).inner
|
||||||
} else {
|
} else {
|
||||||
add_contents(ui)
|
add_contents(ui, 0, 0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ struct Repaint {
|
|||||||
/// even if there's no new events.
|
/// even if there's no new events.
|
||||||
///
|
///
|
||||||
/// Also used to suppress multiple calls to the repaint callback during the same frame.
|
/// Also used to suppress multiple calls to the repaint callback during the same frame.
|
||||||
repaint_after: std::time::Duration,
|
pub repaint_after: HashMap<u64, std::time::Duration>,
|
||||||
|
|
||||||
/// While positive, keep requesting repaints. Decrement at the end of each frame.
|
/// While positive, keep requesting repaints. Decrement at the end of each frame.
|
||||||
repaint_requests: u32,
|
repaint_requests: u32,
|
||||||
@@ -71,9 +71,11 @@ struct Repaint {
|
|||||||
|
|
||||||
impl Default for Repaint {
|
impl Default for Repaint {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut repaint_after = HashMap::default();
|
||||||
|
repaint_after.insert(0, std::time::Duration::from_millis(100));
|
||||||
Self {
|
Self {
|
||||||
frame_nr: 0,
|
frame_nr: 0,
|
||||||
repaint_after: std::time::Duration::from_millis(100),
|
repaint_after,
|
||||||
// Start with painting an extra frame to compensate for some widgets
|
// Start with painting an extra frame to compensate for some widgets
|
||||||
// that take two frames before they "settle":
|
// that take two frames before they "settle":
|
||||||
repaint_requests: 1,
|
repaint_requests: 1,
|
||||||
@@ -88,7 +90,7 @@ impl Repaint {
|
|||||||
self.request_repaint_after(std::time::Duration::ZERO, window_id);
|
self.request_repaint_after(std::time::Duration::ZERO, window_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_repaint_after(&mut self, after: std::time::Duration, window_id: u64) {
|
fn request_repaint_after(&mut self, after: std::time::Duration, viewport_id: u64) {
|
||||||
if after == std::time::Duration::ZERO {
|
if after == std::time::Duration::ZERO {
|
||||||
// Do a few extra frames to let things settle.
|
// Do a few extra frames to let things settle.
|
||||||
// This is a bit of a hack, and we don't support it for `repaint_after` callbacks yet.
|
// This is a bit of a hack, and we don't support it for `repaint_after` callbacks yet.
|
||||||
@@ -97,27 +99,33 @@ impl Repaint {
|
|||||||
|
|
||||||
// We only re-call the callback if we get a lower duration,
|
// We only re-call the callback if we get a lower duration,
|
||||||
// otherwise it's already been covered by the previous callback.
|
// otherwise it's already been covered by the previous callback.
|
||||||
if after < self.repaint_after {
|
if after
|
||||||
self.repaint_after = after;
|
< self
|
||||||
|
.repaint_after
|
||||||
|
.get(&viewport_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(std::time::Duration::MAX)
|
||||||
|
{
|
||||||
|
self.repaint_after.insert(viewport_id, after);
|
||||||
|
|
||||||
if let Some(callback) = &self.request_repaint_callback {
|
if let Some(callback) = &self.request_repaint_callback {
|
||||||
let info = RequestRepaintInfo {
|
let info = RequestRepaintInfo {
|
||||||
after,
|
after,
|
||||||
current_frame_nr: self.frame_nr,
|
current_frame_nr: self.frame_nr,
|
||||||
window_id: window_id,
|
window_id: viewport_id,
|
||||||
};
|
};
|
||||||
(callback)(info);
|
(callback)(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_frame(&mut self) {
|
fn start_frame(&mut self, viewport_id: u64) {
|
||||||
// We are repainting; no need to reschedule a repaint unless the user asks for it again.
|
// We are repainting; no need to reschedule a repaint unless the user asks for it again.
|
||||||
self.repaint_after = std::time::Duration::MAX;
|
self.repaint_after.remove(&viewport_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns how long to wait until repaint
|
// returns how long to wait until repaint
|
||||||
fn end_frame(&mut self) -> std::time::Duration {
|
fn end_frame(&mut self, viewport_id: u64) -> Vec<(u64, std::time::Duration)> {
|
||||||
// if repaint_requests is greater than zero. just set the duration to zero for immediate
|
// if repaint_requests is greater than zero. just set the duration to zero for immediate
|
||||||
// repaint. if there's no repaint requests, then we can use the actual repaint_after instead.
|
// repaint. if there's no repaint requests, then we can use the actual repaint_after instead.
|
||||||
let repaint_after = if self.repaint_requests > 0 {
|
let repaint_after = if self.repaint_requests > 0 {
|
||||||
@@ -125,13 +133,19 @@ impl Repaint {
|
|||||||
std::time::Duration::ZERO
|
std::time::Duration::ZERO
|
||||||
} else {
|
} else {
|
||||||
self.repaint_after
|
self.repaint_after
|
||||||
|
.get(&viewport_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(std::time::Duration::MAX)
|
||||||
};
|
};
|
||||||
self.repaint_after = std::time::Duration::MAX;
|
self.repaint_after.insert(viewport_id, repaint_after);
|
||||||
|
|
||||||
self.requested_repaint_last_frame = repaint_after.is_zero();
|
self.requested_repaint_last_frame = repaint_after.is_zero();
|
||||||
self.frame_nr += 1;
|
self.frame_nr += 1;
|
||||||
|
|
||||||
repaint_after
|
self.repaint_after
|
||||||
|
.iter()
|
||||||
|
.map(|(id, time)| (*id, *time))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,12 +181,11 @@ struct ContextImpl {
|
|||||||
u64,
|
u64,
|
||||||
u64,
|
u64,
|
||||||
bool,
|
bool,
|
||||||
Arc<Box<dyn Fn(&Context) + Sync + Send>>,
|
Arc<Box<dyn Fn(&Context, u64, u64) + Sync + Send>>,
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
viewport_counter: u64,
|
viewport_counter: u64,
|
||||||
current_rendering_viewport: u64,
|
current_rendering_viewport: u64,
|
||||||
viewport_stack: Vec<u64>,
|
|
||||||
is_desktop: bool,
|
is_desktop: bool,
|
||||||
|
|
||||||
/// Written to during the frame.
|
/// Written to during the frame.
|
||||||
@@ -189,7 +202,7 @@ struct ContextImpl {
|
|||||||
|
|
||||||
impl ContextImpl {
|
impl ContextImpl {
|
||||||
fn begin_frame_mut(&mut self, mut new_raw_input: RawInput) {
|
fn begin_frame_mut(&mut self, mut new_raw_input: RawInput) {
|
||||||
self.repaint.start_frame();
|
self.repaint.start_frame(self.current_rendering_viewport);
|
||||||
|
|
||||||
if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() {
|
if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() {
|
||||||
new_raw_input.pixels_per_point = Some(new_pixels_per_point);
|
new_raw_input.pixels_per_point = Some(new_pixels_per_point);
|
||||||
@@ -976,10 +989,11 @@ impl Context {
|
|||||||
/// (this will work on `eframe`).
|
/// (this will work on `eframe`).
|
||||||
pub fn request_repaint(&self) {
|
pub fn request_repaint(&self) {
|
||||||
// request two frames of repaint, just to cover some corner cases (frame delays):
|
// request two frames of repaint, just to cover some corner cases (frame delays):
|
||||||
self.write(|ctx| {
|
self.write(|ctx| ctx.repaint.request_repaint(ctx.current_rendering_viewport));
|
||||||
ctx.repaint
|
}
|
||||||
.request_repaint(ctx.viewport_stack.last().cloned().unwrap_or(0))
|
|
||||||
});
|
pub fn request_repaint_viewport(&self, id: u64) {
|
||||||
|
self.write(|ctx| ctx.repaint.request_repaint(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request repaint after at most the specified duration elapses.
|
/// Request repaint after at most the specified duration elapses.
|
||||||
@@ -1011,9 +1025,16 @@ impl Context {
|
|||||||
/// timeout takes 500 milliseconds AFTER the vsync swap buffer.
|
/// timeout takes 500 milliseconds AFTER the vsync swap buffer.
|
||||||
/// So, its not that we are requesting repaint within X duration. We are rather timing out
|
/// So, its not that we are requesting repaint within X duration. We are rather timing out
|
||||||
/// during app idle time where we are not receiving any new input events.
|
/// during app idle time where we are not receiving any new input events.
|
||||||
pub fn request_repaint_after(&self, duration: std::time::Duration, window_id: u64) {
|
pub fn request_repaint_after(&self, duration: std::time::Duration) {
|
||||||
// Maybe we can check if duration is ZERO, and call self.request_repaint()?
|
// Maybe we can check if duration is ZERO, and call self.request_repaint()?
|
||||||
self.write(|ctx| ctx.repaint.request_repaint_after(duration, window_id));
|
self.write(|ctx| {
|
||||||
|
ctx.repaint
|
||||||
|
.request_repaint_after(duration, ctx.current_rendering_viewport)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_repaint_viewport_after(&self, duration: std::time::Duration, id: u64) {
|
||||||
|
self.write(|ctx| ctx.repaint.request_repaint_after(duration, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`].
|
/// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`].
|
||||||
@@ -1280,7 +1301,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let repaint_after = self.write(|ctx| ctx.repaint.end_frame());
|
let repaint_after = self.write(|ctx| ctx.repaint.end_frame(ctx.current_rendering_viewport));
|
||||||
let shapes = self.drain_paint_lists();
|
let shapes = self.drain_paint_lists();
|
||||||
|
|
||||||
// This is used for,
|
// This is used for,
|
||||||
@@ -1303,7 +1324,7 @@ impl Context {
|
|||||||
*used = false;
|
*used = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewports.push((*id, builder.clone(), render.clone()));
|
viewports.push((*id, *parent, builder.clone(), render.clone()));
|
||||||
(out || ctx.current_rendering_viewport != *parent)
|
(out || ctx.current_rendering_viewport != *parent)
|
||||||
&& avalibile_viewports.contains(parent)
|
&& avalibile_viewports.contains(parent)
|
||||||
})
|
})
|
||||||
@@ -1498,7 +1519,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rect_contains_pointer(&self, layer_id: LayerId, rect: Rect) -> bool {
|
pub(crate) fn rect_contains_pointer(&self, layer_id: LayerId, rect: Rect) -> bool {
|
||||||
rect.is_positive() && self.current_viewport() == self.current_rendering_viewport() && {
|
rect.is_positive() && {
|
||||||
let pointer_pos = self.input(|i| i.pointer.interact_pos());
|
let pointer_pos = self.input(|i| i.pointer.interact_pos());
|
||||||
if let Some(pointer_pos) = pointer_pos {
|
if let Some(pointer_pos) = pointer_pos {
|
||||||
rect.contains(pointer_pos) && self.layer_id_at(pointer_pos) == Some(layer_id)
|
rect.contains(pointer_pos) && self.layer_id_at(pointer_pos) == Some(layer_id)
|
||||||
@@ -1929,10 +1950,6 @@ impl Context {
|
|||||||
self.read(|ctx| ctx.current_rendering_viewport)
|
self.read(|ctx| ctx.current_rendering_viewport)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_viewport(&self) -> u64 {
|
|
||||||
self.read(|ctx| ctx.viewport_stack.last().cloned().unwrap_or(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_desktop(&self) -> bool {
|
pub fn is_desktop(&self) -> bool {
|
||||||
self.read(|ctx| ctx.is_desktop)
|
self.read(|ctx| ctx.is_desktop)
|
||||||
}
|
}
|
||||||
@@ -1944,12 +1961,12 @@ impl Context {
|
|||||||
pub fn create_viewport(
|
pub fn create_viewport(
|
||||||
&self,
|
&self,
|
||||||
window_builder: ViewportBuilder,
|
window_builder: ViewportBuilder,
|
||||||
func: impl Fn(&Context) + Send + Sync + 'static,
|
func: impl Fn(&Context, u64, u64) + Send + Sync + 'static,
|
||||||
) {
|
) {
|
||||||
let id = self.write(|ctx| {
|
let id = self.write(|ctx| {
|
||||||
if ctx.is_desktop {
|
if ctx.is_desktop {
|
||||||
if let Some(window) = ctx.viewports.get_mut(&window_builder.title) {
|
if let Some(window) = ctx.viewports.get_mut(&window_builder.title) {
|
||||||
window.2 = *ctx.viewport_stack.last().unwrap_or(&0);
|
window.2 = ctx.current_rendering_viewport;
|
||||||
window.3 = true;
|
window.3 = true;
|
||||||
window.4 = Arc::new(Box::new(func));
|
window.4 = Arc::new(Box::new(func));
|
||||||
window.1
|
window.1
|
||||||
@@ -1961,7 +1978,7 @@ impl Context {
|
|||||||
(
|
(
|
||||||
window_builder,
|
window_builder,
|
||||||
id,
|
id,
|
||||||
*ctx.viewport_stack.last().unwrap_or(&0),
|
ctx.current_rendering_viewport,
|
||||||
true,
|
true,
|
||||||
Arc::new(Box::new(func)),
|
Arc::new(Box::new(func)),
|
||||||
),
|
),
|
||||||
@@ -1972,13 +1989,6 @@ impl Context {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let should_render = self.write(|ctx| {
|
|
||||||
ctx.viewport_stack.push(id);
|
|
||||||
ctx.viewport_stack.last().cloned().unwrap_or(0) == ctx.current_rendering_viewport
|
|
||||||
});
|
|
||||||
self.write(|ctx| {
|
|
||||||
ctx.viewport_stack.pop();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub struct FullOutput {
|
|||||||
/// duration elapses. when in reactive mode, egui spends forever waiting for input and only then,
|
/// duration elapses. when in reactive mode, egui spends forever waiting for input and only then,
|
||||||
/// will it repaint itself. this can be used to make sure that backend will only wait for a
|
/// will it repaint itself. this can be used to make sure that backend will only wait for a
|
||||||
/// specified amount of time, and repaint egui without any new input.
|
/// specified amount of time, and repaint egui without any new input.
|
||||||
pub repaint_after: std::time::Duration,
|
pub repaint_after: Vec<(u64, std::time::Duration)>,
|
||||||
|
|
||||||
/// Texture changes since last frame (including the font texture).
|
/// Texture changes since last frame (including the font texture).
|
||||||
///
|
///
|
||||||
@@ -35,9 +35,10 @@ pub struct FullOutput {
|
|||||||
pub shapes: Vec<epaint::ClippedShape>,
|
pub shapes: Vec<epaint::ClippedShape>,
|
||||||
|
|
||||||
pub viewports: Vec<(
|
pub viewports: Vec<(
|
||||||
|
u64,
|
||||||
u64,
|
u64,
|
||||||
ViewportBuilder,
|
ViewportBuilder,
|
||||||
Arc<Box<dyn Fn(&Context) + Sync + Send>>,
|
Arc<Box<dyn Fn(&Context, u64, u64) + Sync + Send>>,
|
||||||
)>,
|
)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -283,10 +283,7 @@ impl BackendPanel {
|
|||||||
let ctx = ui.ctx().clone();
|
let ctx = ui.ctx().clone();
|
||||||
call_after_delay(std::time::Duration::from_secs(2), move || {
|
call_after_delay(std::time::Duration::from_secs(2), move || {
|
||||||
log::info!("Request a repaint in 3s...");
|
log::info!("Request a repaint in 3s...");
|
||||||
ctx.request_repaint_after(
|
ctx.request_repaint_after(std::time::Duration::from_secs(3));
|
||||||
std::time::Duration::from_secs(3),
|
|
||||||
ctx.current_rendering_viewport(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -415,7 +412,7 @@ impl EguiWindows {
|
|||||||
egui::Window::new("🔧 Settings")
|
egui::Window::new("🔧 Settings")
|
||||||
.open(settings)
|
.open(settings)
|
||||||
.vscroll(true)
|
.vscroll(true)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
tmp_ctx.settings_ui(ui);
|
tmp_ctx.settings_ui(ui);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -423,7 +420,7 @@ impl EguiWindows {
|
|||||||
egui::Window::new("🔍 Inspection")
|
egui::Window::new("🔍 Inspection")
|
||||||
.open(inspection)
|
.open(inspection)
|
||||||
.vscroll(true)
|
.vscroll(true)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
tmp_ctx.inspection_ui(ui);
|
tmp_ctx.inspection_ui(ui);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -431,7 +428,7 @@ impl EguiWindows {
|
|||||||
egui::Window::new("📝 Memory")
|
egui::Window::new("📝 Memory")
|
||||||
.open(memory)
|
.open(memory)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
tmp_ctx.memory_ui(ui);
|
tmp_ctx.memory_ui(ui);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -440,7 +437,7 @@ impl EguiWindows {
|
|||||||
.open(output_events)
|
.open(output_events)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_width(520.0)
|
.default_width(520.0)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
ui.label(
|
ui.label(
|
||||||
"Recent output events from egui. \
|
"Recent output events from egui. \
|
||||||
These are emitted when you interact with widgets, or move focus between them with TAB. \
|
These are emitted when you interact with widgets, or move focus between them with TAB. \
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ impl WrapApp {
|
|||||||
let dropped_files = self.dropped_files.clone();
|
let dropped_files = self.dropped_files.clone();
|
||||||
egui::Window::new("Dropped files")
|
egui::Window::new("Dropped files")
|
||||||
.open(&mut open)
|
.open(&mut open)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
let dropped_files = &*dropped_files.read().unwrap();
|
let dropped_files = &*dropped_files.read().unwrap();
|
||||||
for file in dropped_files {
|
for file in dropped_files {
|
||||||
let mut info = if let Some(path) = &file.path {
|
let mut info = if let Some(path) = &file.path {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ impl super::Demo for About {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.default_width(320.0)
|
.default_width(320.0)
|
||||||
.open(open)
|
.open(open)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
Self::default().ui(ui);
|
Self::default().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ impl super::Demo for CodeEditor {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.default_height(500.0)
|
.default_height(500.0)
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ impl super::Demo for CodeExample {
|
|||||||
.default_size([800.0, 400.0])
|
.default_size([800.0, 400.0])
|
||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.hscroll(true)
|
.hscroll(true)
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ impl super::Demo for ContextMenus {
|
|||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.open(open)
|
.open(open)
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ impl super::Demo for DancingStrings {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.default_size(vec2(512.0, 256.0))
|
.default_size(vec2(512.0, 256.0))
|
||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.show(ctx, |ui| Self::default().ui(ui));
|
.show(ctx, |ui, _, _| Self::default().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ impl DemoWindows {
|
|||||||
.open(&mut about_is_open)
|
.open(&mut about_is_open)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.collapsible(false)
|
.collapsible(false)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
let close = close.clone();
|
let close = close.clone();
|
||||||
clone.data.write().unwrap().about.ui(ui);
|
clone.data.write().unwrap().about.ui(ui);
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ impl super::Demo for DragAndDropDemo {
|
|||||||
.default_size(vec2(256.0, 256.0))
|
.default_size(vec2(256.0, 256.0))
|
||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ impl super::Demo for FontBook {
|
|||||||
let clone = self.clone();
|
let clone = self.clone();
|
||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ impl super::Demo for Highlighting {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.default_width(320.0)
|
.default_width(320.0)
|
||||||
.open(open)
|
.open(open)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
Self::default().ui(ui);
|
Self::default().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ impl super::Demo for LayoutTest {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ impl Demo for MiscDemoWindow {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.vscroll(true)
|
.vscroll(true)
|
||||||
.hscroll(true)
|
.hscroll(true)
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl super::Demo for MultiTouch {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.default_size(vec2(512.0, 512.0))
|
.default_size(vec2(512.0, 512.0))
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ impl super::Demo for PaintBezier {
|
|||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.default_size([300.0, 350.0])
|
.default_size([300.0, 350.0])
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ impl super::Demo for Painting {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.default_size(vec2(512.0, 512.0))
|
.default_size(vec2(512.0, 512.0))
|
||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ impl super::Demo for PlotDemo {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.default_size(vec2(400.0, 400.0))
|
.default_size(vec2(400.0, 400.0))
|
||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.show(ctx, move |ui| clone.clone().ui(ui));
|
.show(ctx, move |ui, _, _| clone.clone().ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ impl super::Demo for Scrolling {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ impl super::Demo for Sliders {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ impl super::Demo for StripDemo {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_width(400.0)
|
.default_width(400.0)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
Self::default().ui(ui);
|
Self::default().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ impl super::Demo for TableDemo {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_width(400.0)
|
.default_width(400.0)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ impl super::Demo for CursorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||||
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
egui::Window::new(self.name())
|
||||||
|
.open(open)
|
||||||
|
.show(ctx, |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
Self::default().ui(ui);
|
Self::default().ui(ui);
|
||||||
});
|
});
|
||||||
@@ -41,7 +43,9 @@ impl super::Demo for IdTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||||
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
egui::Window::new(self.name())
|
||||||
|
.open(open)
|
||||||
|
.show(ctx, |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
Self::default().ui(ui);
|
Self::default().ui(ui);
|
||||||
});
|
});
|
||||||
@@ -135,7 +139,7 @@ impl super::Demo for ManualLayoutTest {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.open(open)
|
.open(open)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
@@ -232,7 +236,7 @@ impl super::Demo for TableTest {
|
|||||||
let clone = self.clone();
|
let clone = self.clone();
|
||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
@@ -353,7 +357,7 @@ impl super::Demo for InputTest {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
@@ -434,7 +438,7 @@ impl super::Demo for WindowResizeTest {
|
|||||||
Window::new("↔ auto-sized")
|
Window::new("↔ auto-sized")
|
||||||
.open(open)
|
.open(open)
|
||||||
.auto_sized()
|
.auto_sized()
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
ui.label("This window will auto-size based on its contents.");
|
ui.label("This window will auto-size based on its contents.");
|
||||||
ui.heading("Resize this area:");
|
ui.heading("Resize this area:");
|
||||||
Resize::default().show(ui, |ui| {
|
Resize::default().show(ui, |ui| {
|
||||||
@@ -448,7 +452,7 @@ impl super::Demo for WindowResizeTest {
|
|||||||
.vscroll(true)
|
.vscroll(true)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_height(300.0)
|
.default_height(300.0)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
ui.label(
|
ui.label(
|
||||||
"This window is resizable and has a scroll area. You can shrink it to any size.",
|
"This window is resizable and has a scroll area. You can shrink it to any size.",
|
||||||
);
|
);
|
||||||
@@ -461,7 +465,7 @@ impl super::Demo for WindowResizeTest {
|
|||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_height(300.0)
|
.default_height(300.0)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
ui.label("This window is resizable but has no built-in scroll area.");
|
ui.label("This window is resizable but has no built-in scroll area.");
|
||||||
ui.label("However, we have a sub-region with a scroll bar:");
|
ui.label("However, we have a sub-region with a scroll bar:");
|
||||||
ui.separator();
|
ui.separator();
|
||||||
@@ -477,7 +481,7 @@ impl super::Demo for WindowResizeTest {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
ui.label("This window is resizable but has no scroll area. This means it can only be resized to a size where all the contents is visible.");
|
ui.label("This window is resizable but has no scroll area. This means it can only be resized to a size where all the contents is visible.");
|
||||||
ui.label("egui will not clip the contents of a window, nor add whitespace to it.");
|
ui.label("egui will not clip the contents of a window, nor add whitespace to it.");
|
||||||
ui.separator();
|
ui.separator();
|
||||||
@@ -491,7 +495,7 @@ impl super::Demo for WindowResizeTest {
|
|||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_height(300.0)
|
.default_height(300.0)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
ui.label("Shows how you can fill an area with a widget.");
|
ui.label("Shows how you can fill an area with a widget.");
|
||||||
let mut text = clone.text.write().unwrap();
|
let mut text = clone.text.write().unwrap();
|
||||||
ui.add_sized(ui.available_size(), TextEdit::multiline(&mut *text));
|
ui.add_sized(ui.available_size(), TextEdit::multiline(&mut *text));
|
||||||
@@ -502,7 +506,7 @@ impl super::Demo for WindowResizeTest {
|
|||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_size([250.0, 150.0])
|
.default_size([250.0, 150.0])
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui, _, _| {
|
||||||
ui.label("This window has empty space that fills up the available space, preventing auto-shrink.");
|
ui.label("This window has empty space that fills up the available space, preventing auto-shrink.");
|
||||||
ui.allocate_space(ui.available_size());
|
ui.allocate_space(ui.available_size());
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ impl super::Demo for TextEdit {
|
|||||||
egui::Window::new(self.name())
|
egui::Window::new(self.name())
|
||||||
.open(open)
|
.open(open)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ impl super::Demo for WidgetGallery {
|
|||||||
.open(open)
|
.open(open)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.default_width(280.0)
|
.default_width(280.0)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
use super::View as _;
|
use super::View as _;
|
||||||
clone.clone().ui(ui);
|
clone.clone().ui(ui);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ impl super::Demo for WindowOptions {
|
|||||||
window = window.anchor(anchor, anchor_offset);
|
window = window.anchor(anchor, anchor_offset);
|
||||||
}
|
}
|
||||||
let clone = self.clone();
|
let clone = self.clone();
|
||||||
window.show(ctx, move |ui| {
|
window.show(ctx, move |ui, _, _| {
|
||||||
let mut clone = clone.clone();
|
let mut clone = clone.clone();
|
||||||
clone.ui(ui)
|
clone.ui(ui)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ impl super::Demo for WindowWithPanels {
|
|||||||
.default_height(400.0)
|
.default_height(400.0)
|
||||||
.vscroll(false)
|
.vscroll(false)
|
||||||
.open(open);
|
.open(open);
|
||||||
window.show(ctx, |ui| Self {}.ui(ui));
|
window.show(ctx, |ui, _, _| Self {}.ui(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
|
|
||||||
fn main() -> Result<(), eframe::Error> {
|
fn main() -> Result<(), eframe::Error> {
|
||||||
@@ -16,15 +18,20 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MyApp {
|
struct MyAppData {
|
||||||
allowed_to_close: bool,
|
allowed_to_close: bool,
|
||||||
show_confirmation_dialog: bool,
|
show_confirmation_dialog: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct MyApp {
|
||||||
|
data: Arc<RwLock<MyAppData>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn on_close_event(&mut self) -> bool {
|
fn on_close_event(&mut self) -> bool {
|
||||||
self.show_confirmation_dialog = true;
|
self.data.write().unwrap().show_confirmation_dialog = true;
|
||||||
self.allowed_to_close
|
self.data.read().unwrap().allowed_to_close
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
@@ -32,23 +39,27 @@ impl eframe::App for MyApp {
|
|||||||
ui.heading("Try to close the window");
|
ui.heading("Try to close the window");
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.show_confirmation_dialog {
|
let show_confirmation_dialog = self.data.read().unwrap().show_confirmation_dialog;
|
||||||
|
if show_confirmation_dialog {
|
||||||
|
let data = self.data.clone();
|
||||||
// Show confirmation dialog:
|
// Show confirmation dialog:
|
||||||
egui::Window::new("Do you want to quit?")
|
egui::Window::new("Do you want to quit?")
|
||||||
.collapsible(false)
|
.collapsible(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui.button("Cancel").clicked() {
|
if ui.button("Cancel").clicked() {
|
||||||
self.show_confirmation_dialog = false;
|
data.write().unwrap().show_confirmation_dialog = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ui.button("Yes!").clicked() {
|
if ui.button("Yes!").clicked() {
|
||||||
self.allowed_to_close = true;
|
data.write().unwrap().allowed_to_close = true;
|
||||||
frame.close();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if self.data.read().unwrap().allowed_to_close {
|
||||||
|
frame.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ publish = false
|
|||||||
eframe = { path = "../../crates/eframe", default-features = false, features = [
|
eframe = { path = "../../crates/eframe", default-features = false, features = [
|
||||||
# accesskit struggles with threading
|
# accesskit struggles with threading
|
||||||
"default_fonts",
|
"default_fonts",
|
||||||
"wgpu",
|
"glow",
|
||||||
|
# "wgpu",
|
||||||
] }
|
] }
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use std::sync::mpsc;
|
use std::sync::{mpsc, Arc, RwLock};
|
||||||
use std::thread::JoinHandle;
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
@@ -20,39 +20,50 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State per thread.
|
struct ThreadStateData {
|
||||||
struct ThreadState {
|
|
||||||
thread_nr: usize,
|
thread_nr: usize,
|
||||||
title: String,
|
title: String,
|
||||||
name: String,
|
name: String,
|
||||||
age: u32,
|
age: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State per thread.
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ThreadState {
|
||||||
|
data: Arc<RwLock<ThreadStateData>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ThreadState {
|
impl ThreadState {
|
||||||
fn new(thread_nr: usize) -> Self {
|
fn new(thread_nr: usize) -> Self {
|
||||||
let title = format!("Background thread {thread_nr}");
|
let title = format!("Background thread {thread_nr}");
|
||||||
Self {
|
Self {
|
||||||
|
data: Arc::new(RwLock::new(ThreadStateData {
|
||||||
thread_nr,
|
thread_nr,
|
||||||
title,
|
title,
|
||||||
name: "Arthur".into(),
|
name: "Arthur".into(),
|
||||||
age: 12 + thread_nr as u32 * 10,
|
age: 12 + thread_nr as u32 * 10,
|
||||||
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &egui::Context) {
|
fn show(&mut self, ctx: &egui::Context) {
|
||||||
let pos = egui::pos2(16.0, 128.0 * (self.thread_nr as f32 + 1.0));
|
let thread_nr = self.data.read().unwrap().thread_nr;
|
||||||
egui::Window::new(&self.title)
|
let pos = egui::pos2(16.0, 128.0 * (thread_nr as f32 + 1.0));
|
||||||
|
let clone = self.clone();
|
||||||
|
let title = self.data.read().unwrap().title.clone();
|
||||||
|
egui::Window::new(title)
|
||||||
.default_pos(pos)
|
.default_pos(pos)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
|
let data = &mut *clone.data.write().unwrap();
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Your name: ");
|
ui.label("Your name: ");
|
||||||
ui.text_edit_singleline(&mut self.name);
|
ui.text_edit_singleline(&mut data.name);
|
||||||
});
|
});
|
||||||
ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
|
ui.add(egui::Slider::new(&mut data.age, 0..=120).text("age"));
|
||||||
if ui.button("Click each year").clicked() {
|
if ui.button("Click each year").clicked() {
|
||||||
self.age += 1;
|
data.age += 1;
|
||||||
}
|
}
|
||||||
ui.label(format!("Hello '{}', age {}", self.name, self.age));
|
ui.label(format!("Hello '{}', age {}", data.name, data.age));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,10 +85,13 @@ fn new_worker(
|
|||||||
.expect("failed to spawn thread");
|
.expect("failed to spawn thread");
|
||||||
(handle, show_tx)
|
(handle, show_tx)
|
||||||
}
|
}
|
||||||
|
struct MyAppData {
|
||||||
struct MyApp {
|
|
||||||
threads: Vec<(JoinHandle<()>, mpsc::SyncSender<egui::Context>)>,
|
threads: Vec<(JoinHandle<()>, mpsc::SyncSender<egui::Context>)>,
|
||||||
on_done_tx: mpsc::SyncSender<()>,
|
on_done_tx: mpsc::SyncSender<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyApp {
|
||||||
|
data: Arc<RwLock<MyAppData>>,
|
||||||
on_done_rc: mpsc::Receiver<()>,
|
on_done_rc: mpsc::Receiver<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,17 +101,24 @@ impl MyApp {
|
|||||||
let (on_done_tx, on_done_rc) = mpsc::sync_channel(0);
|
let (on_done_tx, on_done_rc) = mpsc::sync_channel(0);
|
||||||
|
|
||||||
let mut slf = Self {
|
let mut slf = Self {
|
||||||
|
data: Arc::new(RwLock::new(MyAppData {
|
||||||
threads,
|
threads,
|
||||||
on_done_tx,
|
on_done_tx,
|
||||||
|
})),
|
||||||
on_done_rc,
|
on_done_rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
slf.spawn_thread();
|
{
|
||||||
slf.spawn_thread();
|
let mut data = slf.data.write().unwrap();
|
||||||
|
data.spawn_thread();
|
||||||
|
data.spawn_thread();
|
||||||
|
}
|
||||||
|
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyAppData {
|
||||||
fn spawn_thread(&mut self) {
|
fn spawn_thread(&mut self) {
|
||||||
let thread_nr = self.threads.len();
|
let thread_nr = self.threads.len();
|
||||||
self.threads
|
self.threads
|
||||||
@@ -107,7 +128,7 @@ impl MyApp {
|
|||||||
|
|
||||||
impl std::ops::Drop for MyApp {
|
impl std::ops::Drop for MyApp {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
for (handle, show_tx) in self.threads.drain(..) {
|
for (handle, show_tx) in self.data.write().unwrap().threads.drain(..) {
|
||||||
std::mem::drop(show_tx);
|
std::mem::drop(show_tx);
|
||||||
handle.join().unwrap();
|
handle.join().unwrap();
|
||||||
}
|
}
|
||||||
@@ -116,17 +137,25 @@ impl std::ops::Drop for MyApp {
|
|||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::Window::new("Main thread").show(ctx, |ui| {
|
let data = self.data.clone();
|
||||||
|
egui::Window::new("Main thread").show(ctx, move |ui, _, parent_id| {
|
||||||
if ui.button("Spawn another thread").clicked() {
|
if ui.button("Spawn another thread").clicked() {
|
||||||
self.spawn_thread();
|
data.write().unwrap().spawn_thread();
|
||||||
|
ui.ctx().request_repaint_viewport(parent_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (_handle, show_tx) in &self.threads {
|
let threads_len;
|
||||||
|
{
|
||||||
|
let data = self.data.read().unwrap();
|
||||||
|
threads_len = data.threads.len();
|
||||||
|
|
||||||
|
for (_handle, show_tx) in &data.threads {
|
||||||
let _ = show_tx.send(ctx.clone());
|
let _ = show_tx.send(ctx.clone());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _ in 0..self.threads.len() {
|
for _ in 0..threads_len {
|
||||||
let _ = self.on_done_rc.recv();
|
let _ = self.on_done_rc.recv();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
|
eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
"Current window: {}, Current rendering window: {}",
|
"Current rendering window: {}",
|
||||||
ctx.current_viewport(),
|
|
||||||
ctx.current_rendering_viewport()
|
ctx.current_rendering_viewport()
|
||||||
));
|
));
|
||||||
ui.heading("My egui Application");
|
ui.heading("My egui Application");
|
||||||
@@ -42,12 +41,11 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
egui::CollapsingHeader::new("Show Test1").show(ui, |ui| {
|
egui::CollapsingHeader::new("Show Test1").show(ui, |ui| {
|
||||||
egui::Window::new("Test1")
|
egui::Window::new("Test1")
|
||||||
.embedded(embedded)
|
.embedded(embedded)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
ui.checkbox(&mut *clone.write().unwrap(), "Should embedd?");
|
ui.checkbox(&mut *clone.write().unwrap(), "Should embedd?");
|
||||||
let ctx = ui.ctx().clone();
|
let ctx = ui.ctx().clone();
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
"Current window: {}, Current rendering window: {}",
|
"Current rendering window: {}",
|
||||||
ctx.current_viewport(),
|
|
||||||
ctx.current_rendering_viewport()
|
ctx.current_rendering_viewport()
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
@@ -57,12 +55,11 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
egui::CollapsingHeader::new("Shout Test2").show(ui, |ui| {
|
egui::CollapsingHeader::new("Shout Test2").show(ui, |ui| {
|
||||||
egui::Window::new("Test2")
|
egui::Window::new("Test2")
|
||||||
.embedded(embedded)
|
.embedded(embedded)
|
||||||
.show(ctx, move |ui| {
|
.show(ctx, move |ui, _, _| {
|
||||||
ui.checkbox(&mut *clone.write().unwrap(), "Should embedd?");
|
ui.checkbox(&mut *clone.write().unwrap(), "Should embedd?");
|
||||||
let ctx = ui.ctx().clone();
|
let ctx = ui.ctx().clone();
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
"Current window: {}, Current rendering window: {}",
|
"Current rendering window: {}",
|
||||||
ctx.current_viewport(),
|
|
||||||
ctx.current_rendering_viewport()
|
ctx.current_rendering_viewport()
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -128,9 +128,6 @@ impl eframe::App for Application {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.request_repaint_after(
|
ctx.request_repaint_after(Self::repaint_max_timeout());
|
||||||
Self::repaint_max_timeout(),
|
|
||||||
ctx.current_rendering_viewport(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user