Use a lot more let-else (#7582)

This commit is contained in:
Emil Ernerfeldt 2025-10-02 19:47:00 +02:00 committed by GitHub
parent 4c1f344ef8
commit bd45406fad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 812 additions and 847 deletions

View File

@ -5,7 +5,7 @@ name: Rust
env: env:
RUSTFLAGS: -D warnings RUSTFLAGS: -D warnings
RUSTDOCFLAGS: -D warnings RUSTDOCFLAGS: -D warnings
NIGHTLY_VERSION: nightly-2025-04-22 NIGHTLY_VERSION: nightly-2025-09-16
jobs: jobs:
fmt-crank-check-test: fmt-crank-check-test:

View File

@ -14,10 +14,10 @@ pub struct AppTitleIconSetter {
impl AppTitleIconSetter { impl AppTitleIconSetter {
pub fn new(title: String, mut icon_data: Option<Arc<IconData>>) -> Self { pub fn new(title: String, mut icon_data: Option<Arc<IconData>>) -> Self {
if let Some(icon) = &icon_data { if let Some(icon) = &icon_data
if **icon == IconData::default() { && **icon == IconData::default()
icon_data = None; {
} icon_data = None;
} }
Self { Self {
@ -275,13 +275,12 @@ fn set_title_and_icon_mac(title: &str, icon_data: Option<&IconData>) -> AppIconS
} }
// Change the title in the top bar - for python processes this would be again "python" otherwise. // Change the title in the top bar - for python processes this would be again "python" otherwise.
if let Some(main_menu) = app.mainMenu() { if let Some(main_menu) = app.mainMenu()
if let Some(item) = main_menu.itemAtIndex(0) { && let Some(item) = main_menu.itemAtIndex(0)
if let Some(app_menu) = item.submenu() { && let Some(app_menu) = item.submenu()
profiling::scope!("setTitle_"); {
app_menu.setTitle(&NSString::from_str(title)); profiling::scope!("setTitle_");
} app_menu.setTitle(&NSString::from_str(title));
}
} }
// The title in the Dock apparently can't be changed. // The title in the Dock apparently can't be changed.

View File

@ -52,14 +52,13 @@ pub fn viewport_builder(
viewport_builder = viewport_builder.with_position(pos); viewport_builder = viewport_builder.with_position(pos);
} }
if clamp_size_to_monitor_size { if clamp_size_to_monitor_size && let Some(initial_window_size) = viewport_builder.inner_size
if let Some(initial_window_size) = viewport_builder.inner_size { {
let initial_window_size = egui::NumExt::at_most( let initial_window_size = egui::NumExt::at_most(
initial_window_size, initial_window_size,
largest_monitor_point_size(egui_zoom_factor, event_loop), largest_monitor_point_size(egui_zoom_factor, event_loop),
); );
viewport_builder = viewport_builder.with_inner_size(initial_window_size); viewport_builder = viewport_builder.with_inner_size(initial_window_size);
}
} }
viewport_builder.inner_size viewport_builder.inner_size
@ -332,15 +331,15 @@ impl EpiIntegration {
if let Some(storage) = self.frame.storage_mut() { if let Some(storage) = self.frame.storage_mut() {
profiling::function_scope!(); profiling::function_scope!();
if let Some(window) = _window { if let Some(window) = _window
if self.persist_window { && self.persist_window
profiling::scope!("native_window"); {
epi::set_value( profiling::scope!("native_window");
storage, epi::set_value(
STORAGE_WINDOW_KEY, storage,
&WindowSettings::from_window(self.egui_ctx.zoom_factor(), window), STORAGE_WINDOW_KEY,
); &WindowSettings::from_window(self.egui_ctx.zoom_factor(), window),
} );
} }
if _app.persist_egui_memory() { if _app.persist_egui_memory() {
profiling::scope!("egui_memory"); profiling::scope!("egui_memory");

View File

@ -193,12 +193,11 @@ impl crate::Storage for FileStorage {
fn save_to_disk(file_path: &PathBuf, kv: &HashMap<String, String>) { fn save_to_disk(file_path: &PathBuf, kv: &HashMap<String, String>) {
profiling::function_scope!(); profiling::function_scope!();
if let Some(parent_dir) = file_path.parent() { if let Some(parent_dir) = file_path.parent()
if !parent_dir.exists() { && !parent_dir.exists()
if let Err(err) = std::fs::create_dir_all(parent_dir) { && let Err(err) = std::fs::create_dir_all(parent_dir)
log::warn!("Failed to create directory {parent_dir:?}: {err}"); {
} log::warn!("Failed to create directory {parent_dir:?}: {err}");
}
} }
match std::fs::File::create(file_path) { match std::fs::File::create(file_path) {

View File

@ -281,10 +281,9 @@ impl<'app> GlowWinitApp<'app> {
.viewport .viewport
.mouse_passthrough .mouse_passthrough
.unwrap_or(false) .unwrap_or(false)
&& let Err(err) = glutin.window(ViewportId::ROOT).set_cursor_hittest(false)
{ {
if let Err(err) = glutin.window(ViewportId::ROOT).set_cursor_hittest(false) { log::warn!("set_cursor_hittest(false) failed: {err}");
log::warn!("set_cursor_hittest(false) failed: {err}");
}
} }
let app_creator = std::mem::take(&mut self.app_creator) let app_creator = std::mem::take(&mut self.app_creator)
@ -440,20 +439,20 @@ impl WinitApp for GlowWinitApp<'_> {
_: winit::event::DeviceId, _: winit::event::DeviceId,
event: winit::event::DeviceEvent, event: winit::event::DeviceEvent,
) -> crate::Result<EventResult> { ) -> crate::Result<EventResult> {
if let winit::event::DeviceEvent::MouseMotion { delta } = event { if let winit::event::DeviceEvent::MouseMotion { delta } = event
if let Some(running) = &mut self.running { && let Some(running) = &mut self.running
let mut glutin = running.glutin.borrow_mut(); {
if let Some(viewport) = glutin let mut glutin = running.glutin.borrow_mut();
.focused_viewport if let Some(viewport) = glutin
.and_then(|viewport| glutin.viewports.get_mut(&viewport)) .focused_viewport
{ .and_then(|viewport| glutin.viewports.get_mut(&viewport))
if let Some(egui_winit) = viewport.egui_winit.as_mut() { {
egui_winit.on_mouse_motion(delta); if let Some(egui_winit) = viewport.egui_winit.as_mut() {
} egui_winit.on_mouse_motion(delta);
}
if let Some(window) = viewport.window.as_ref() { if let Some(window) = viewport.window.as_ref() {
return Ok(EventResult::RepaintNext(window.id())); return Ok(EventResult::RepaintNext(window.id()));
}
} }
} }
} }
@ -480,16 +479,15 @@ impl WinitApp for GlowWinitApp<'_> {
if let Some(running) = &self.running { if let Some(running) = &self.running {
let mut glutin = running.glutin.borrow_mut(); let mut glutin = running.glutin.borrow_mut();
if let Some(viewport_id) = glutin.viewport_from_window.get(&event.window_id).copied() { if let Some(viewport_id) = glutin.viewport_from_window.get(&event.window_id).copied()
if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) { && let Some(viewport) = glutin.viewports.get_mut(&viewport_id)
if let Some(egui_winit) = &mut viewport.egui_winit { && let Some(egui_winit) = &mut viewport.egui_winit
return Ok(winit_integration::on_accesskit_window_event( {
egui_winit, return Ok(winit_integration::on_accesskit_window_event(
event.window_id, egui_winit,
&event.window_event, event.window_id,
)); &event.window_event,
} ));
}
} }
} }
@ -527,10 +525,10 @@ impl GlowWinitRunning<'_> {
if is_immediate && viewport_id != ViewportId::ROOT { if is_immediate && viewport_id != ViewportId::ROOT {
// This will only happen if this is an immediate viewport. // This will only happen if this is an immediate viewport.
// That means that the viewport cannot be rendered by itself and needs his parent to be rendered. // That means that the viewport cannot be rendered by itself and needs his parent to be rendered.
if let Some(parent_viewport) = glutin.viewports.get(&viewport.ids.parent) { if let Some(parent_viewport) = glutin.viewports.get(&viewport.ids.parent)
if let Some(window) = parent_viewport.window.as_ref() { && let Some(window) = parent_viewport.window.as_ref()
return Ok(EventResult::RepaintNext(window.id())); {
} return Ok(EventResult::RepaintNext(window.id()));
} }
return Ok(EventResult::Wait); return Ok(EventResult::Wait);
} }
@ -727,10 +725,10 @@ impl GlowWinitRunning<'_> {
// give it time to settle: // give it time to settle:
#[cfg(feature = "__screenshot")] #[cfg(feature = "__screenshot")]
if integration.egui_ctx.cumulative_pass_nr() == 2 { if integration.egui_ctx.cumulative_pass_nr() == 2
if let Ok(path) = std::env::var("EFRAME_SCREENSHOT_TO") { && let Ok(path) = std::env::var("EFRAME_SCREENSHOT_TO")
save_screenshot_and_exit(&path, &painter, screen_size_in_pixels); {
} save_screenshot_and_exit(&path, &painter, screen_size_in_pixels);
} }
glutin.handle_viewport_output(event_loop, &integration.egui_ctx, &viewport_output); glutin.handle_viewport_output(event_loop, &integration.egui_ctx, &viewport_output);
@ -785,11 +783,12 @@ impl GlowWinitRunning<'_> {
// Resize with 0 width and height is used by winit to signal a minimize event on Windows. // Resize with 0 width and height is used by winit to signal a minimize event on Windows.
// See: https://github.com/rust-windowing/winit/issues/208 // See: https://github.com/rust-windowing/winit/issues/208
// This solves an issue where the app would panic when minimizing on Windows. // This solves an issue where the app would panic when minimizing on Windows.
if 0 < physical_size.width && 0 < physical_size.height { if 0 < physical_size.width
if let Some(viewport_id) = viewport_id { && 0 < physical_size.height
repaint_asap = true; && let Some(viewport_id) = viewport_id
glutin.resize(viewport_id, *physical_size); {
} repaint_asap = true;
glutin.resize(viewport_id, *physical_size);
} }
} }
@ -803,19 +802,19 @@ impl GlowWinitRunning<'_> {
log::debug!("Received WindowEvent::CloseRequested for viewport {viewport_id:?}"); log::debug!("Received WindowEvent::CloseRequested for viewport {viewport_id:?}");
if let Some(viewport_id) = viewport_id { if let Some(viewport_id) = viewport_id
if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) { && let Some(viewport) = glutin.viewports.get_mut(&viewport_id)
// Tell viewport it should close: {
viewport.info.events.push(egui::ViewportEvent::Close); // Tell viewport it should close:
viewport.info.events.push(egui::ViewportEvent::Close);
// We may need to repaint both us and our parent to close the window, // We may need to repaint both us and our parent to close the window,
// and perhaps twice (once to notice the close-event, once again to enforce it). // and perhaps twice (once to notice the close-event, once again to enforce it).
// `request_repaint_of` does a double-repaint though: // `request_repaint_of` does a double-repaint though:
self.integration.egui_ctx.request_repaint_of(viewport_id); self.integration.egui_ctx.request_repaint_of(viewport_id);
self.integration self.integration
.egui_ctx .egui_ctx
.request_repaint_of(viewport.ids.parent); .request_repaint_of(viewport.ids.parent);
}
} }
} }
_ => {} _ => {}
@ -1232,21 +1231,21 @@ impl GlutinWindowContext {
let width_px = NonZeroU32::new(physical_size.width).unwrap_or(NonZeroU32::MIN); let width_px = NonZeroU32::new(physical_size.width).unwrap_or(NonZeroU32::MIN);
let height_px = NonZeroU32::new(physical_size.height).unwrap_or(NonZeroU32::MIN); let height_px = NonZeroU32::new(physical_size.height).unwrap_or(NonZeroU32::MIN);
if let Some(viewport) = self.viewports.get(&viewport_id) { if let Some(viewport) = self.viewports.get(&viewport_id)
if let Some(gl_surface) = &viewport.gl_surface { && let Some(gl_surface) = &viewport.gl_surface
change_gl_context( {
&mut self.current_gl_context, change_gl_context(
&mut self.not_current_gl_context, &mut self.current_gl_context,
gl_surface, &mut self.not_current_gl_context,
); gl_surface,
gl_surface.resize( );
self.current_gl_context gl_surface.resize(
.as_ref() self.current_gl_context
.expect("failed to get current context to resize surface"), .as_ref()
width_px, .expect("failed to get current context to resize surface"),
height_px, width_px,
); height_px,
} );
} }
} }

View File

@ -94,15 +94,15 @@ impl<T: WinitApp> WinitAppWrapper<T> {
let mut event_result = event_result; let mut event_result = event_result;
if cfg!(target_os = "windows") { if cfg!(target_os = "windows")
if let Ok(EventResult::RepaintNow(window_id)) = event_result { && let Ok(EventResult::RepaintNow(window_id)) = event_result
log::trace!("RepaintNow of {window_id:?}"); {
self.windows_next_repaint_times log::trace!("RepaintNow of {window_id:?}");
.insert(window_id, Instant::now()); self.windows_next_repaint_times
.insert(window_id, Instant::now());
// Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280
event_result = self.winit_app.run_ui_and_paint(event_loop, window_id); event_result = self.winit_app.run_ui_and_paint(event_loop, window_id);
}
} }
let combined_result = event_result.map(|event_result| match event_result { let combined_result = event_result.map(|event_result| match event_result {

View File

@ -429,20 +429,20 @@ impl WinitApp for WgpuWinitApp<'_> {
_: winit::event::DeviceId, _: winit::event::DeviceId,
event: winit::event::DeviceEvent, event: winit::event::DeviceEvent,
) -> crate::Result<EventResult> { ) -> crate::Result<EventResult> {
if let winit::event::DeviceEvent::MouseMotion { delta } = event { if let winit::event::DeviceEvent::MouseMotion { delta } = event
if let Some(running) = &mut self.running { && let Some(running) = &mut self.running
let mut shared = running.shared.borrow_mut(); {
if let Some(viewport) = shared let mut shared = running.shared.borrow_mut();
.focused_viewport if let Some(viewport) = shared
.and_then(|viewport| shared.viewports.get_mut(&viewport)) .focused_viewport
{ .and_then(|viewport| shared.viewports.get_mut(&viewport))
if let Some(egui_winit) = viewport.egui_winit.as_mut() { {
egui_winit.on_mouse_motion(delta); if let Some(egui_winit) = viewport.egui_winit.as_mut() {
} egui_winit.on_mouse_motion(delta);
}
if let Some(window) = viewport.window.as_ref() { if let Some(window) = viewport.window.as_ref() {
return Ok(EventResult::RepaintNext(window.id())); return Ok(EventResult::RepaintNext(window.id()));
}
} }
} }
} }
@ -478,14 +478,13 @@ impl WinitApp for WgpuWinitApp<'_> {
if let Some(viewport) = viewport_from_window if let Some(viewport) = viewport_from_window
.get(&event.window_id) .get(&event.window_id)
.and_then(|id| viewports.get_mut(id)) .and_then(|id| viewports.get_mut(id))
&& let Some(egui_winit) = &mut viewport.egui_winit
{ {
if let Some(egui_winit) = &mut viewport.egui_winit { return Ok(winit_integration::on_accesskit_window_event(
return Ok(winit_integration::on_accesskit_window_event( egui_winit,
egui_winit, event.window_id,
event.window_id, &event.window_event,
&event.window_event, ));
));
}
} }
} }
@ -563,10 +562,10 @@ impl WgpuWinitRunning<'_> {
if viewport.viewport_ui_cb.is_none() { if viewport.viewport_ui_cb.is_none() {
// This will only happen if this is an immediate viewport. // This will only happen if this is an immediate viewport.
// That means that the viewport cannot be rendered by itself and needs his parent to be rendered. // That means that the viewport cannot be rendered by itself and needs his parent to be rendered.
if let Some(viewport) = viewports.get(&viewport.ids.parent) { if let Some(viewport) = viewports.get(&viewport.ids.parent)
if let Some(window) = viewport.window.as_ref() { && let Some(window) = viewport.window.as_ref()
return Ok(EventResult::RepaintNext(window.id())); {
} return Ok(EventResult::RepaintNext(window.id()));
} }
return Ok(EventResult::Wait); return Ok(EventResult::Wait);
} }
@ -730,13 +729,13 @@ impl WgpuWinitRunning<'_> {
integration.maybe_autosave(app.as_mut(), window.map(|w| w.as_ref())); integration.maybe_autosave(app.as_mut(), window.map(|w| w.as_ref()));
if let Some(window) = window { if let Some(window) = window
if window.is_minimized() == Some(true) { && window.is_minimized() == Some(true)
// On Mac, a minimized Window uses up all CPU: {
// https://github.com/emilk/egui/issues/325 // On Mac, a minimized Window uses up all CPU:
profiling::scope!("minimized_sleep"); // https://github.com/emilk/egui/issues/325
std::thread::sleep(std::time::Duration::from_millis(10)); profiling::scope!("minimized_sleep");
} std::thread::sleep(std::time::Duration::from_millis(10));
} }
if integration.should_close() { if integration.should_close() {
@ -784,14 +783,14 @@ impl WgpuWinitRunning<'_> {
// Resize with 0 width and height is used by winit to signal a minimize event on Windows. // Resize with 0 width and height is used by winit to signal a minimize event on Windows.
// See: https://github.com/rust-windowing/winit/issues/208 // See: https://github.com/rust-windowing/winit/issues/208
// This solves an issue where the app would panic when minimizing on Windows. // This solves an issue where the app would panic when minimizing on Windows.
if let Some(viewport_id) = viewport_id { if let Some(viewport_id) = viewport_id
if let (Some(width), Some(height)) = ( && let (Some(width), Some(height)) = (
NonZeroU32::new(physical_size.width), NonZeroU32::new(physical_size.width),
NonZeroU32::new(physical_size.height), NonZeroU32::new(physical_size.height),
) { )
repaint_asap = true; {
shared.painter.on_window_resized(viewport_id, width, height); repaint_asap = true;
} shared.painter.on_window_resized(viewport_id, width, height);
} }
} }
@ -805,17 +804,17 @@ impl WgpuWinitRunning<'_> {
log::debug!("Received WindowEvent::CloseRequested for viewport {viewport_id:?}"); log::debug!("Received WindowEvent::CloseRequested for viewport {viewport_id:?}");
if let Some(viewport_id) = viewport_id { if let Some(viewport_id) = viewport_id
if let Some(viewport) = shared.viewports.get_mut(&viewport_id) { && let Some(viewport) = shared.viewports.get_mut(&viewport_id)
// Tell viewport it should close: {
viewport.info.events.push(egui::ViewportEvent::Close); // Tell viewport it should close:
viewport.info.events.push(egui::ViewportEvent::Close);
// We may need to repaint both us and our parent to close the window, // We may need to repaint both us and our parent to close the window,
// and perhaps twice (once to notice the close-event, once again to enforce it). // and perhaps twice (once to notice the close-event, once again to enforce it).
// `request_repaint_of` does a double-repaint though: // `request_repaint_of` does a double-repaint though:
integration.egui_ctx.request_repaint_of(viewport_id); integration.egui_ctx.request_repaint_of(viewport_id);
integration.egui_ctx.request_repaint_of(viewport.ids.parent); integration.egui_ctx.request_repaint_of(viewport.ids.parent);
}
} }
} }
@ -1087,13 +1086,13 @@ fn handle_viewport_output(
// For Wayland : https://github.com/emilk/egui/issues/4196 // For Wayland : https://github.com/emilk/egui/issues/4196
if cfg!(target_os = "linux") { if cfg!(target_os = "linux") {
let new_inner_size = window.inner_size(); let new_inner_size = window.inner_size();
if new_inner_size != old_inner_size { if new_inner_size != old_inner_size
if let (Some(width), Some(height)) = ( && let (Some(width), Some(height)) = (
NonZeroU32::new(new_inner_size.width), NonZeroU32::new(new_inner_size.width),
NonZeroU32::new(new_inner_size.height), NonZeroU32::new(new_inner_size.height),
) { )
painter.on_window_resized(viewport_id, width, height); {
} painter.on_window_resized(viewport_id, width, height);
} }
} }
} }

View File

@ -498,14 +498,12 @@ impl Painter {
&screen_descriptor, &screen_descriptor,
); );
if capture { if capture && let Some(capture_state) = &mut self.screen_capture_state {
if let Some(capture_state) = &mut self.screen_capture_state { capture_buffer = Some(capture_state.copy_textures(
capture_buffer = Some(capture_state.copy_textures( &render_state.device,
&render_state.device, &output_frame,
&output_frame, &mut encoder,
&mut encoder, ));
));
}
} }
} }
@ -535,16 +533,16 @@ impl Painter {
} }
} }
if let Some(capture_buffer) = capture_buffer { if let Some(capture_buffer) = capture_buffer
if let Some(screen_capture_state) = &mut self.screen_capture_state { && let Some(screen_capture_state) = &mut self.screen_capture_state
screen_capture_state.read_screen_rgba( {
self.context.clone(), screen_capture_state.read_screen_rgba(
capture_buffer, self.context.clone(),
capture_data, capture_buffer,
self.capture_tx.clone(), capture_data,
viewport_id, self.capture_tx.clone(),
); viewport_id,
} );
} }
{ {

View File

@ -574,41 +574,41 @@ impl State {
state: winit::event::ElementState, state: winit::event::ElementState,
button: winit::event::MouseButton, button: winit::event::MouseButton,
) { ) {
if let Some(pos) = self.pointer_pos_in_points { if let Some(pos) = self.pointer_pos_in_points
if let Some(button) = translate_mouse_button(button) { && let Some(button) = translate_mouse_button(button)
let pressed = state == winit::event::ElementState::Pressed; {
let pressed = state == winit::event::ElementState::Pressed;
self.egui_input.events.push(egui::Event::PointerButton { self.egui_input.events.push(egui::Event::PointerButton {
pos, pos,
button, button,
pressed, pressed,
modifiers: self.egui_input.modifiers, modifiers: self.egui_input.modifiers,
}); });
if self.simulate_touch_screen { if self.simulate_touch_screen {
if pressed { if pressed {
self.any_pointer_button_down = true; self.any_pointer_button_down = true;
self.egui_input.events.push(egui::Event::Touch { self.egui_input.events.push(egui::Event::Touch {
device_id: egui::TouchDeviceId(0), device_id: egui::TouchDeviceId(0),
id: egui::TouchId(0), id: egui::TouchId(0),
phase: egui::TouchPhase::Start, phase: egui::TouchPhase::Start,
pos, pos,
force: None, force: None,
}); });
} else { } else {
self.any_pointer_button_down = false; self.any_pointer_button_down = false;
self.egui_input.events.push(egui::Event::PointerGone); self.egui_input.events.push(egui::Event::PointerGone);
self.egui_input.events.push(egui::Event::Touch { self.egui_input.events.push(egui::Event::Touch {
device_id: egui::TouchDeviceId(0), device_id: egui::TouchDeviceId(0),
id: egui::TouchId(0), id: egui::TouchId(0),
phase: egui::TouchPhase::End, phase: egui::TouchPhase::End,
pos, pos,
force: None, force: None,
}); });
}
} }
} }
} }
@ -913,11 +913,11 @@ impl State {
} }
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
if let Some(accesskit) = self.accesskit.as_mut() { if let Some(accesskit) = self.accesskit.as_mut()
if let Some(update) = accesskit_update { && let Some(update) = accesskit_update
profiling::scope!("accesskit"); {
accesskit.update_if_active(|| update); profiling::scope!("accesskit");
} accesskit.update_if_active(|| update);
} }
} }
@ -1378,10 +1378,10 @@ fn process_viewport_command(
} }
ViewportCommand::StartDrag => { ViewportCommand::StartDrag => {
// If `.has_focus()` is not checked on x11 the input will be permanently taken until the app is killed! // If `.has_focus()` is not checked on x11 the input will be permanently taken until the app is killed!
if window.has_focus() { if window.has_focus()
if let Err(err) = window.drag_window() { && let Err(err) = window.drag_window()
log::warn!("{command:?}: {err}"); {
} log::warn!("{command:?}: {err}");
} }
} }
ViewportCommand::InnerSize(size) => { ViewportCommand::InnerSize(size) => {
@ -1795,10 +1795,10 @@ pub fn apply_viewport_builder_to_window(
window: &Window, window: &Window,
builder: &ViewportBuilder, builder: &ViewportBuilder,
) { ) {
if let Some(mouse_passthrough) = builder.mouse_passthrough { if let Some(mouse_passthrough) = builder.mouse_passthrough
if let Err(err) = window.set_cursor_hittest(!mouse_passthrough) { && let Err(err) = window.set_cursor_hittest(!mouse_passthrough)
log::warn!("set_cursor_hittest failed: {err}"); {
} log::warn!("set_cursor_hittest failed: {err}");
} }
{ {
@ -1809,16 +1809,15 @@ pub fn apply_viewport_builder_to_window(
let pixels_per_point = pixels_per_point(egui_ctx, window); let pixels_per_point = pixels_per_point(egui_ctx, window);
if let Some(size) = builder.inner_size { if let Some(size) = builder.inner_size
if window && window
.request_inner_size(PhysicalSize::new( .request_inner_size(PhysicalSize::new(
pixels_per_point * size.x, pixels_per_point * size.x,
pixels_per_point * size.y, pixels_per_point * size.y,
)) ))
.is_some() .is_some()
{ {
log::debug!("Failed to set window size"); log::debug!("Failed to set window size");
}
} }
if let Some(size) = builder.min_inner_size { if let Some(size) = builder.min_inner_size {
window.set_min_inner_size(Some(PhysicalSize::new( window.set_min_inner_size(Some(PhysicalSize::new(

View File

@ -20,10 +20,10 @@ pub fn capture() -> String {
backtrace::resolve_frame(frame, |symbol| { backtrace::resolve_frame(frame, |symbol| {
let mut file_and_line = symbol.filename().map(shorten_source_file_path); let mut file_and_line = symbol.filename().map(shorten_source_file_path);
if let Some(file_and_line) = &mut file_and_line { if let Some(file_and_line) = &mut file_and_line
if let Some(line_nr) = symbol.lineno() { && let Some(line_nr) = symbol.lineno()
file_and_line.push_str(&format!(":{line_nr}")); {
} file_and_line.push_str(&format!(":{line_nr}"));
} }
let file_and_line = file_and_line.unwrap_or_default(); let file_and_line = file_and_line.unwrap_or_default();

View File

@ -525,10 +525,11 @@ impl Area {
true, true,
); );
if movable && move_response.dragged() { if movable
if let Some(pivot_pos) = &mut state.pivot_pos { && move_response.dragged()
*pivot_pos += move_response.drag_delta(); && let Some(pivot_pos) = &mut state.pivot_pos
} {
*pivot_pos += move_response.drag_delta();
} }
if (move_response.dragged() || move_response.clicked()) if (move_response.dragged() || move_response.clicked())
@ -606,16 +607,16 @@ impl Prepared {
let mut ui = Ui::new(ctx.clone(), self.layer_id.id, ui_builder); let mut ui = Ui::new(ctx.clone(), self.layer_id.id, ui_builder);
ui.set_clip_rect(self.constrain_rect); // Don't paint outside our bounds ui.set_clip_rect(self.constrain_rect); // Don't paint outside our bounds
if self.fade_in { if self.fade_in
if let Some(last_became_visible_at) = self.state.last_became_visible_at { && let Some(last_became_visible_at) = self.state.last_became_visible_at
let age = {
ctx.input(|i| (i.time - last_became_visible_at) as f32 + i.predicted_dt / 2.0); let age =
let opacity = crate::remap_clamp(age, 0.0..=ctx.style().animation_time, 0.0..=1.0); ctx.input(|i| (i.time - last_became_visible_at) as f32 + i.predicted_dt / 2.0);
let opacity = emath::easing::quadratic_out(opacity); // slow fade-out = quick fade-in let opacity = crate::remap_clamp(age, 0.0..=ctx.style().animation_time, 0.0..=1.0);
ui.multiply_opacity(opacity); let opacity = emath::easing::quadratic_out(opacity); // slow fade-out = quick fade-in
if opacity < 1.0 { ui.multiply_opacity(opacity);
ctx.request_repaint(); if opacity < 1.0 {
} ctx.request_repaint();
} }
} }

View File

@ -266,12 +266,10 @@ impl SidePanel {
resize_hover = resize_response.hovered(); resize_hover = resize_response.hovered();
is_resizing = resize_response.dragged(); is_resizing = resize_response.dragged();
if is_resizing { if is_resizing && let Some(pointer) = resize_response.interact_pointer_pos() {
if let Some(pointer) = resize_response.interact_pointer_pos() { width = (pointer.x - side.side_x(panel_rect)).abs();
width = (pointer.x - side.side_x(panel_rect)).abs(); width = clamp_to_range(width, width_range).at_most(available_rect.width());
width = clamp_to_range(width, width_range).at_most(available_rect.width()); side.set_rect_width(&mut panel_rect, width);
side.set_rect_width(&mut panel_rect, width);
}
} }
} }
} }
@ -765,13 +763,10 @@ impl TopBottomPanel {
resize_hover = resize_response.hovered(); resize_hover = resize_response.hovered();
is_resizing = resize_response.dragged(); is_resizing = resize_response.dragged();
if is_resizing { if is_resizing && let Some(pointer) = resize_response.interact_pointer_pos() {
if let Some(pointer) = resize_response.interact_pointer_pos() { height = (pointer.y - side.side_y(panel_rect)).abs();
height = (pointer.y - side.side_y(panel_rect)).abs(); height = clamp_to_range(height, height_range).at_most(available_rect.height());
height = side.set_rect_height(&mut panel_rect, height);
clamp_to_range(height, height_range).at_most(available_rect.height());
side.set_rect_height(&mut panel_rect, height);
}
} }
} }
} }

View File

@ -241,14 +241,12 @@ impl Resize {
let corner_id = self.resizable.any().then(|| id.with("__resize_corner")); let corner_id = self.resizable.any().then(|| id.with("__resize_corner"));
if let Some(corner_id) = corner_id { if let Some(corner_id) = corner_id
if let Some(corner_response) = ui.ctx().read_response(corner_id) { && let Some(corner_response) = ui.ctx().read_response(corner_id)
if let Some(pointer_pos) = corner_response.interact_pointer_pos() { && let Some(pointer_pos) = corner_response.interact_pointer_pos()
// Respond to the interaction early to avoid frame delay. {
user_requested_size = // Respond to the interaction early to avoid frame delay.
Some(pointer_pos - position + 0.5 * corner_response.rect.size()); user_requested_size = Some(pointer_pos - position + 0.5 * corner_response.rect.size());
}
}
} }
if let Some(user_requested_size) = user_requested_size { if let Some(user_requested_size) = user_requested_size {

View File

@ -240,38 +240,38 @@ impl Scene {
resp.mark_changed(); resp.mark_changed();
} }
if let Some(mouse_pos) = ui.input(|i| i.pointer.latest_pos()) { if let Some(mouse_pos) = ui.input(|i| i.pointer.latest_pos())
if resp.contains_pointer() { && resp.contains_pointer()
let pointer_in_scene = to_global.inverse() * mouse_pos; {
let zoom_delta = ui.ctx().input(|i| i.zoom_delta()); let pointer_in_scene = to_global.inverse() * mouse_pos;
let pan_delta = ui.ctx().input(|i| i.smooth_scroll_delta); let zoom_delta = ui.ctx().input(|i| i.zoom_delta());
let pan_delta = ui.ctx().input(|i| i.smooth_scroll_delta);
// Most of the time we can return early. This is also important to // Most of the time we can return early. This is also important to
// avoid `ui_from_scene` to change slightly due to floating point errors. // avoid `ui_from_scene` to change slightly due to floating point errors.
if zoom_delta == 1.0 && pan_delta == Vec2::ZERO { if zoom_delta == 1.0 && pan_delta == Vec2::ZERO {
return; return;
}
if zoom_delta != 1.0 {
// Zoom in on pointer, but only if we are not zoomed in or out too far.
let zoom_delta = zoom_delta.clamp(
self.zoom_range.min / to_global.scaling,
self.zoom_range.max / to_global.scaling,
);
*to_global = *to_global
* TSTransform::from_translation(pointer_in_scene.to_vec2())
* TSTransform::from_scaling(zoom_delta)
* TSTransform::from_translation(-pointer_in_scene.to_vec2());
// Clamp to exact zoom range.
to_global.scaling = self.zoom_range.clamp(to_global.scaling);
}
// Pan:
*to_global = TSTransform::from_translation(pan_delta) * *to_global;
resp.mark_changed();
} }
if zoom_delta != 1.0 {
// Zoom in on pointer, but only if we are not zoomed in or out too far.
let zoom_delta = zoom_delta.clamp(
self.zoom_range.min / to_global.scaling,
self.zoom_range.max / to_global.scaling,
);
*to_global = *to_global
* TSTransform::from_translation(pointer_in_scene.to_vec2())
* TSTransform::from_scaling(zoom_delta)
* TSTransform::from_translation(-pointer_in_scene.to_vec2());
// Clamp to exact zoom range.
to_global.scaling = self.zoom_range.clamp(to_global.scaling);
}
// Pan:
*to_global = TSTransform::from_translation(pan_delta) * *to_global;
resp.mark_changed();
} }
} }
} }

View File

@ -829,10 +829,10 @@ impl ScrollArea {
if let Some(cursor) = on_drag_cursor { if let Some(cursor) = on_drag_cursor {
response.on_hover_cursor(cursor); response.on_hover_cursor(cursor);
} }
} else if response.hovered() { } else if response.hovered()
if let Some(cursor) = on_hover_cursor { && let Some(cursor) = on_hover_cursor
response.on_hover_cursor(cursor); {
} response.on_hover_cursor(cursor);
} }
} }
} }

View File

@ -645,10 +645,10 @@ impl Window<'_> {
let full_response = area.end(ctx, area_content_ui); let full_response = area.end(ctx, area_content_ui);
if full_response.should_close() { if full_response.should_close()
if let Some(open) = open { && let Some(open) = open
*open = false; {
} *open = false;
} }
let inner_response = InnerResponse { let inner_response = InnerResponse {
@ -839,11 +839,11 @@ fn resize_response(
// TODO(emilk): add this to a Window state instead as a command "move here next frame" // TODO(emilk): add this to a Window state instead as a command "move here next frame"
area.state_mut().set_left_top_pos(new_rect.left_top()); area.state_mut().set_left_top_pos(new_rect.left_top());
if resize_interaction.any_dragged() { if resize_interaction.any_dragged()
if let Some(mut state) = resize::State::load(ctx, resize_id) { && let Some(mut state) = resize::State::load(ctx, resize_id)
state.requested_size = Some(new_rect.size() - margins); {
state.store(ctx, resize_id); state.requested_size = Some(new_rect.size() - margins);
} state.store(ctx, resize_id);
} }
ctx.memory_mut(|mem| mem.areas_mut().move_to_top(area_layer_id)); ctx.memory_mut(|mem| mem.areas_mut().move_to_top(area_layer_id));

View File

@ -426,20 +426,18 @@ impl ContextImpl {
let viewport = self.viewports.entry(viewport_id).or_default(); let viewport = self.viewports.entry(viewport_id).or_default();
if is_outermost_viewport { if is_outermost_viewport && let Some(new_zoom_factor) = self.new_zoom_factor.take() {
if let Some(new_zoom_factor) = self.new_zoom_factor.take() { let ratio = self.memory.options.zoom_factor / new_zoom_factor;
let ratio = self.memory.options.zoom_factor / new_zoom_factor; self.memory.options.zoom_factor = new_zoom_factor;
self.memory.options.zoom_factor = new_zoom_factor;
let input = &viewport.input; let input = &viewport.input;
// This is a bit hacky, but is required to avoid jitter: // This is a bit hacky, but is required to avoid jitter:
let mut rect = input.screen_rect; let mut rect = input.screen_rect;
rect.min = (ratio * rect.min.to_vec2()).to_pos2(); rect.min = (ratio * rect.min.to_vec2()).to_pos2();
rect.max = (ratio * rect.max.to_vec2()).to_pos2(); rect.max = (ratio * rect.max.to_vec2()).to_pos2();
new_raw_input.screen_rect = Some(rect); new_raw_input.screen_rect = Some(rect);
// We should really scale everything else in the input too, // We should really scale everything else in the input too,
// but the `screen_rect` is the most important part. // but the `screen_rect` is the most important part.
}
} }
let native_pixels_per_point = new_raw_input let native_pixels_per_point = new_raw_input
.viewport() .viewport()
@ -1105,15 +1103,16 @@ impl Context {
) )
}; };
if let Some(pointer_pos) = self.pointer_hover_pos() { if let Some(pointer_pos) = self.pointer_hover_pos()
if text_rect.contains(pointer_pos) { && text_rect.contains(pointer_pos)
let tooltip_pos = if below { {
text_rect.left_bottom() + vec2(2.0, 4.0) let tooltip_pos = if below {
} else { text_rect.left_bottom() + vec2(2.0, 4.0)
text_rect.left_top() + vec2(2.0, -4.0) } else {
}; text_rect.left_top() + vec2(2.0, -4.0)
};
painter.error( painter.error(
tooltip_pos, tooltip_pos,
format!("Widget is {} this text.\n\n\ format!("Widget is {} this text.\n\n\
ID clashes happens when things like Windows or CollapsingHeaders share names,\n\ ID clashes happens when things like Windows or CollapsingHeaders share names,\n\
@ -1121,7 +1120,6 @@ impl Context {
Sometimes the solution is to use ui.push_id.", Sometimes the solution is to use ui.push_id.",
if below { "above" } else { "below" }), if below { "above" } else { "below" }),
); );
}
} }
}; };
@ -1253,10 +1251,10 @@ impl Context {
widget_rect.map(|mut rect| { widget_rect.map(|mut rect| {
// If the Rect is invalid the Ui hasn't registered its final Rect yet. // If the Rect is invalid the Ui hasn't registered its final Rect yet.
// We return the Rect from last frame instead. // We return the Rect from last frame instead.
if !(rect.rect.is_positive() && rect.rect.is_finite()) { if !(rect.rect.is_positive() && rect.rect.is_finite())
if let Some(prev_rect) = viewport.prev_pass.widgets.get(id) { && let Some(prev_rect) = viewport.prev_pass.widgets.get(id)
rect.rect = prev_rect.rect; {
} rect.rect = prev_rect.rect;
} }
rect rect
}) })
@ -1961,14 +1959,13 @@ impl Context {
let mut update_fonts = true; let mut update_fonts = true;
self.read(|ctx| { self.read(|ctx| {
if let Some(current_fonts) = ctx.fonts.as_ref() { if let Some(current_fonts) = ctx.fonts.as_ref()
if current_fonts && current_fonts
.definitions() .definitions()
.font_data .font_data
.contains_key(&new_font.name) .contains_key(&new_font.name)
{ {
update_fonts = false; // no need to update update_fonts = false; // no need to update
}
} }
}); });

View File

@ -317,19 +317,18 @@ fn hit_test_on_close(close: &[WidgetRect], pos: Pos2) -> WidgetHits {
pos, pos,
); );
if let Some(closest_drag) = closest_drag { if let Some(closest_drag) = closest_drag
if hit_drag && hit_drag
.interact_rect .interact_rect
.contains_rect(closest_drag.interact_rect) .contains_rect(closest_drag.interact_rect)
{ {
// `hit_drag` is a big background thing and `closest_drag` is something small on top of it. // `hit_drag` is a big background thing and `closest_drag` is something small on top of it.
// Be helpful and return the small things: // Be helpful and return the small things:
return WidgetHits { return WidgetHits {
click: None, click: None,
drag: Some(closest_drag), drag: Some(closest_drag),
..Default::default() ..Default::default()
}; };
}
} }
WidgetHits { WidgetHits {
@ -425,13 +424,13 @@ fn find_closest_within(
let dist_sq = widget.interact_rect.distance_sq_to_pos(pos); let dist_sq = widget.interact_rect.distance_sq_to_pos(pos);
if let Some(closest) = closest { if let Some(closest) = closest
if dist_sq == closest_dist_sq { && dist_sq == closest_dist_sq
// It's a tie! Pick the thin candidate over the thick one. {
// This makes it easier to hit a thin resize-handle, for instance: // It's a tie! Pick the thin candidate over the thick one.
if should_prioritize_hits_on_back(closest.interact_rect, widget.interact_rect) { // This makes it easier to hit a thin resize-handle, for instance:
continue; if should_prioritize_hits_on_back(closest.interact_rect, widget.interact_rect) {
} continue;
} }
} }

View File

@ -884,10 +884,11 @@ impl InputState {
) -> impl Iterator<Item = &accesskit::ActionRequest> { ) -> impl Iterator<Item = &accesskit::ActionRequest> {
let accesskit_id = id.accesskit_id(); let accesskit_id = id.accesskit_id();
self.events.iter().filter_map(move |event| { self.events.iter().filter_map(move |event| {
if let Event::AccessKitActionRequest(request) = event { if let Event::AccessKitActionRequest(request) = event
if request.target == accesskit_id && request.action == action { && request.target == accesskit_id
return Some(request); && request.action == action
} {
return Some(request);
} }
None None
}) })
@ -901,10 +902,10 @@ impl InputState {
) { ) {
let accesskit_id = id.accesskit_id(); let accesskit_id = id.accesskit_id();
self.events.retain(|event| { self.events.retain(|event| {
if let Event::AccessKitActionRequest(request) = event { if let Event::AccessKitActionRequest(request) = event
if request.target == accesskit_id { && request.target == accesskit_id
return !consume(request); {
} return !consume(request);
} }
true true
}); });
@ -1468,10 +1469,10 @@ impl PointerState {
return false; return false;
} }
if let Some(press_start_time) = self.press_start_time { if let Some(press_start_time) = self.press_start_time
if self.time - press_start_time > self.options.max_click_duration { && self.time - press_start_time > self.options.max_click_duration
return false; {
} return false;
} }
true true

View File

@ -115,19 +115,19 @@ pub(crate) fn interact(
) -> InteractionSnapshot { ) -> InteractionSnapshot {
profiling::function_scope!(); profiling::function_scope!();
if let Some(id) = interaction.potential_click_id { if let Some(id) = interaction.potential_click_id
if !widgets.contains(id) { && !widgets.contains(id)
// The widget we were interested in clicking is gone. {
interaction.potential_click_id = None; // The widget we were interested in clicking is gone.
} interaction.potential_click_id = None;
} }
if let Some(id) = interaction.potential_drag_id { if let Some(id) = interaction.potential_drag_id
if !widgets.contains(id) { && !widgets.contains(id)
// The widget we were interested in dragging is gone. {
// This is fine! This could be drag-and-drop, // The widget we were interested in dragging is gone.
// and the widget being dragged is now "in the air" and thus // This is fine! This could be drag-and-drop,
// not registered in the new frame. // and the widget being dragged is now "in the air" and thus
} // not registered in the new frame.
} }
let mut clicked = None; let mut clicked = None;
@ -172,13 +172,13 @@ pub(crate) fn interact(
} }
PointerEvent::Released { click, button: _ } => { PointerEvent::Released { click, button: _ } => {
if click.is_some() && !input.pointer.is_decidedly_dragging() { if click.is_some()
if let Some(widget) = interaction && !input.pointer.is_decidedly_dragging()
&& let Some(widget) = interaction
.potential_click_id .potential_click_id
.and_then(|id| widgets.get(id)) .and_then(|id| widgets.get(id))
{ {
clicked = Some(widget.id); clicked = Some(widget.id);
}
} }
interaction.potential_drag_id = None; interaction.potential_drag_id = None;
@ -190,21 +190,21 @@ pub(crate) fn interact(
if dragged.is_none() { if dragged.is_none() {
// Check if we started dragging something new: // Check if we started dragging something new:
if let Some(widget) = interaction.potential_drag_id.and_then(|id| widgets.get(id)) { if let Some(widget) = interaction.potential_drag_id.and_then(|id| widgets.get(id))
if widget.enabled { && widget.enabled
let is_dragged = if widget.sense.senses_click() && widget.sense.senses_drag() { {
// This widget is sensitive to both clicks and drags. let is_dragged = if widget.sense.senses_click() && widget.sense.senses_drag() {
// When the mouse first is pressed, it could be either, // This widget is sensitive to both clicks and drags.
// so we postpone the decision until we know. // When the mouse first is pressed, it could be either,
input.pointer.is_decidedly_dragging() // so we postpone the decision until we know.
} else { input.pointer.is_decidedly_dragging()
// This widget is just sensitive to drags, so we can mark it as dragged right away: } else {
widget.sense.senses_drag() // This widget is just sensitive to drags, so we can mark it as dragged right away:
}; widget.sense.senses_drag()
};
if is_dragged { if is_dragged {
dragged = Some(widget.id); dragged = Some(widget.id);
}
} }
} }
} }

View File

@ -236,15 +236,15 @@ impl GraphicLayers {
// First do the layers part of area_order: // First do the layers part of area_order:
for layer_id in area_order { for layer_id in area_order {
if layer_id.order == order { if layer_id.order == order
if let Some(list) = order_map.get_mut(&layer_id.id) { && let Some(list) = order_map.get_mut(&layer_id.id)
if let Some(to_global) = to_global.get(layer_id) { {
for clipped_shape in &mut list.0 { if let Some(to_global) = to_global.get(layer_id) {
clipped_shape.transform(*to_global); for clipped_shape in &mut list.0 {
} clipped_shape.transform(*to_global);
} }
all_shapes.append(&mut list.0);
} }
all_shapes.append(&mut list.0);
} }
} }

View File

@ -535,36 +535,34 @@ impl Focus {
self.focus_direction = FocusDirection::None; self.focus_direction = FocusDirection::None;
for event in &new_input.events { for event in &new_input.events {
if !event_filter.matches(event) { if !event_filter.matches(event)
if let crate::Event::Key { && let crate::Event::Key {
key, key,
pressed: true, pressed: true,
modifiers, modifiers,
.. ..
} = event } = event
{ && let Some(cardinality) = match key {
if let Some(cardinality) = match key { crate::Key::ArrowUp => Some(FocusDirection::Up),
crate::Key::ArrowUp => Some(FocusDirection::Up), crate::Key::ArrowRight => Some(FocusDirection::Right),
crate::Key::ArrowRight => Some(FocusDirection::Right), crate::Key::ArrowDown => Some(FocusDirection::Down),
crate::Key::ArrowDown => Some(FocusDirection::Down), crate::Key::ArrowLeft => Some(FocusDirection::Left),
crate::Key::ArrowLeft => Some(FocusDirection::Left),
crate::Key::Tab => { crate::Key::Tab => {
if modifiers.shift { if modifiers.shift {
Some(FocusDirection::Previous) Some(FocusDirection::Previous)
} else { } else {
Some(FocusDirection::Next) Some(FocusDirection::Next)
}
} }
crate::Key::Escape => {
self.focused_widget = None;
Some(FocusDirection::None)
}
_ => None,
} {
self.focus_direction = cardinality;
} }
crate::Key::Escape => {
self.focused_widget = None;
Some(FocusDirection::None)
}
_ => None,
} }
{
self.focus_direction = cardinality;
} }
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
@ -582,10 +580,10 @@ impl Focus {
} }
pub(crate) fn end_pass(&mut self, used_ids: &IdMap<Rect>) { pub(crate) fn end_pass(&mut self, used_ids: &IdMap<Rect>) {
if self.focus_direction.is_cardinal() { if self.focus_direction.is_cardinal()
if let Some(found_widget) = self.find_widget_in_direction(used_ids) { && let Some(found_widget) = self.find_widget_in_direction(used_ids)
self.focused_widget = Some(FocusWidget::new(found_widget)); {
} self.focused_widget = Some(FocusWidget::new(found_widget));
} }
if let Some(focused_widget) = self.focused_widget { if let Some(focused_widget) = self.focused_widget {
@ -858,12 +856,12 @@ impl Memory {
/// ///
/// You must first give focus to the widget before calling this. /// You must first give focus to the widget before calling this.
pub fn set_focus_lock_filter(&mut self, id: Id, event_filter: EventFilter) { pub fn set_focus_lock_filter(&mut self, id: Id, event_filter: EventFilter) {
if self.had_focus_last_frame(id) && self.has_focus(id) { if self.had_focus_last_frame(id)
if let Some(focused) = &mut self.focus_mut().focused_widget { && self.has_focus(id)
if focused.id == id { && let Some(focused) = &mut self.focus_mut().focused_widget
focused.filter = event_filter; && focused.id == id
} {
} focused.filter = event_filter;
} }
} }
@ -933,13 +931,13 @@ impl Memory {
/// Limit focus to widgets on the given layer and above. /// Limit focus to widgets on the given layer and above.
/// If this is called multiple times per frame, the top layer wins. /// If this is called multiple times per frame, the top layer wins.
pub fn set_modal_layer(&mut self, layer_id: LayerId) { pub fn set_modal_layer(&mut self, layer_id: LayerId) {
if let Some(current) = self.focus().and_then(|f| f.top_modal_layer_current_frame) { if let Some(current) = self.focus().and_then(|f| f.top_modal_layer_current_frame)
if matches!( && matches!(
self.areas().compare_order(layer_id, current), self.areas().compare_order(layer_id, current),
std::cmp::Ordering::Less std::cmp::Ordering::Less
) { )
return; {
} return;
} }
self.focus_mut().set_modal_layer(layer_id); self.focus_mut().set_modal_layer(layer_id);
@ -1047,10 +1045,10 @@ impl Memory {
/// being rendered. /// being rendered.
#[deprecated = "Use Popup::show instead"] #[deprecated = "Use Popup::show instead"]
pub fn keep_popup_open(&mut self, popup_id: Id) { pub fn keep_popup_open(&mut self, popup_id: Id) {
if let Some(state) = self.popups.get_mut(&self.viewport_id) { if let Some(state) = self.popups.get_mut(&self.viewport_id)
if state.id == popup_id { && state.id == popup_id
state.open_this_frame = true; {
} state.open_this_frame = true;
} }
} }
@ -1200,17 +1198,17 @@ impl Areas {
layer_to_global: &HashMap<LayerId, TSTransform>, layer_to_global: &HashMap<LayerId, TSTransform>,
) -> Option<LayerId> { ) -> Option<LayerId> {
for layer in self.order.iter().rev() { for layer in self.order.iter().rev() {
if self.is_visible(layer) { if self.is_visible(layer)
if let Some(state) = self.areas.get(&layer.id) { && let Some(state) = self.areas.get(&layer.id)
let mut rect = state.rect(); {
if state.interactable { let mut rect = state.rect();
if let Some(to_global) = layer_to_global.get(layer) { if state.interactable {
rect = *to_global * rect; if let Some(to_global) = layer_to_global.get(layer) {
} rect = *to_global * rect;
}
if rect.contains(pos) { if rect.contains(pos) {
return Some(*layer); return Some(*layer);
}
} }
} }
} }

View File

@ -420,17 +420,14 @@ impl MenuRoot {
} else if button } else if button
.ctx .ctx
.input(|i| i.pointer.any_pressed() && i.pointer.primary_down()) .input(|i| i.pointer.any_pressed() && i.pointer.primary_down())
&& let Some(pos) = button.ctx.input(|i| i.pointer.interact_pos())
&& let Some(root) = root.inner.as_mut()
&& root.id == id
{ {
if let Some(pos) = button.ctx.input(|i| i.pointer.interact_pos()) { // pressed somewhere while this menu is open
if let Some(root) = root.inner.as_mut() { let in_menu = root.menu_state.read().area_contains(pos);
if root.id == id { if !in_menu {
// pressed somewhere while this menu is open return MenuResponse::Close;
let in_menu = root.menu_state.read().area_contains(pos);
if !in_menu {
return MenuResponse::Close;
}
}
}
} }
} }
MenuResponse::Stay MenuResponse::Stay
@ -728,21 +725,21 @@ impl MenuState {
return false; return false;
} }
if let Some(sub_menu) = self.current_submenu() { if let Some(sub_menu) = self.current_submenu()
if let Some(pos) = pointer.hover_pos() { && let Some(pos) = pointer.hover_pos()
let rect = sub_menu.read().rect; {
return rect.intersects_ray(pos, pointer.direction().normalized()); let rect = sub_menu.read().rect;
} return rect.intersects_ray(pos, pointer.direction().normalized());
} }
false false
} }
/// Check if pointer is hovering current submenu. /// Check if pointer is hovering current submenu.
fn hovering_current_submenu(&self, pointer: &PointerState) -> bool { fn hovering_current_submenu(&self, pointer: &PointerState) -> bool {
if let Some(sub_menu) = self.current_submenu() { if let Some(sub_menu) = self.current_submenu()
if let Some(pos) = pointer.hover_pos() { && let Some(pos) = pointer.hover_pos()
return sub_menu.read().area_contains(pos); {
} return sub_menu.read().area_contains(pos);
} }
false false
} }

View File

@ -316,74 +316,74 @@ impl LabelSelectionState {
let may_select_widget = let may_select_widget =
multi_widget_text_select || selection.primary.widget_id == response.id; multi_widget_text_select || selection.primary.widget_id == response.id;
if self.is_dragging && may_select_widget { if self.is_dragging
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() { && may_select_widget
let galley_rect = && let Some(pointer_pos) = ui.ctx().pointer_interact_pos()
global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size()); {
let galley_rect = galley_rect.intersect(ui.clip_rect()); let galley_rect = global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size());
let galley_rect = galley_rect.intersect(ui.clip_rect());
let is_in_same_column = galley_rect let is_in_same_column = galley_rect
.x_range() .x_range()
.intersects(self.selection_bbox_last_frame.x_range()); .intersects(self.selection_bbox_last_frame.x_range());
let has_reached_primary = let has_reached_primary =
self.has_reached_primary || response.id == selection.primary.widget_id; self.has_reached_primary || response.id == selection.primary.widget_id;
let has_reached_secondary = let has_reached_secondary =
self.has_reached_secondary || response.id == selection.secondary.widget_id; self.has_reached_secondary || response.id == selection.secondary.widget_id;
let new_primary = if response.contains_pointer() { let new_primary = if response.contains_pointer() {
// Dragging into this widget - easy case: // Dragging into this widget - easy case:
Some(galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2())) Some(galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2()))
} else if is_in_same_column } else if is_in_same_column
&& !self.has_reached_primary && !self.has_reached_primary
&& selection.primary.pos.y <= selection.secondary.pos.y && selection.primary.pos.y <= selection.secondary.pos.y
&& pointer_pos.y <= galley_rect.top() && pointer_pos.y <= galley_rect.top()
&& galley_rect.top() <= selection.secondary.pos.y && galley_rect.top() <= selection.secondary.pos.y
{ {
// The user is dragging the text selection upwards, above the first selected widget (this one): // The user is dragging the text selection upwards, above the first selected widget (this one):
if DEBUG { if DEBUG {
ui.ctx() ui.ctx()
.debug_text(format!("Upwards drag; include {:?}", response.id)); .debug_text(format!("Upwards drag; include {:?}", response.id));
} }
Some(galley.begin()) Some(galley.begin())
} else if is_in_same_column } else if is_in_same_column
&& has_reached_secondary && has_reached_secondary
&& has_reached_primary && has_reached_primary
&& selection.secondary.pos.y <= selection.primary.pos.y && selection.secondary.pos.y <= selection.primary.pos.y
&& selection.secondary.pos.y <= galley_rect.bottom() && selection.secondary.pos.y <= galley_rect.bottom()
&& galley_rect.bottom() <= pointer_pos.y && galley_rect.bottom() <= pointer_pos.y
{ {
// The user is dragging the text selection downwards, below this widget. // The user is dragging the text selection downwards, below this widget.
// We move the cursor to the end of this widget, // We move the cursor to the end of this widget,
// (and we may do the same for the next widget too). // (and we may do the same for the next widget too).
if DEBUG { if DEBUG {
ui.ctx() ui.ctx()
.debug_text(format!("Downwards drag; include {:?}", response.id)); .debug_text(format!("Downwards drag; include {:?}", response.id));
} }
Some(galley.end()) Some(galley.end())
} else { } else {
None None
}; };
if let Some(new_primary) = new_primary { if let Some(new_primary) = new_primary {
selection.primary = selection.primary =
WidgetTextCursor::new(response.id, new_primary, global_from_galley, galley); WidgetTextCursor::new(response.id, new_primary, global_from_galley, galley);
// We don't want the latency of `drag_started`. // We don't want the latency of `drag_started`.
let drag_started = ui.input(|i| i.pointer.any_pressed()); let drag_started = ui.input(|i| i.pointer.any_pressed());
if drag_started { if drag_started {
if selection.layer_id == response.layer_id { if selection.layer_id == response.layer_id {
if ui.input(|i| i.modifiers.shift) { if ui.input(|i| i.modifiers.shift) {
// A continuation of a previous selection. // A continuation of a previous selection.
} else {
// A new selection in the same layer.
selection.secondary = selection.primary;
}
} else { } else {
// A new selection in a new layer. // A new selection in the same layer.
selection.layer_id = response.layer_id;
selection.secondary = selection.primary; selection.secondary = selection.primary;
} }
} else {
// A new selection in a new layer.
selection.layer_id = response.layer_id;
selection.secondary = selection.primary;
} }
} }
} }
@ -511,26 +511,26 @@ impl LabelSelectionState {
let old_range = cursor_state.range(galley); let old_range = cursor_state.range(galley);
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() { if let Some(pointer_pos) = ui.ctx().pointer_interact_pos()
if response.contains_pointer() { && response.contains_pointer()
let cursor_at_pointer = {
galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2()); let cursor_at_pointer =
galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2());
// This is where we handle start-of-drag and double-click-to-select. // This is where we handle start-of-drag and double-click-to-select.
// Actual drag-to-select happens elsewhere. // Actual drag-to-select happens elsewhere.
let dragged = false; let dragged = false;
cursor_state.pointer_interaction(ui, response, cursor_at_pointer, galley, dragged); cursor_state.pointer_interaction(ui, response, cursor_at_pointer, galley, dragged);
}
} }
if let Some(mut cursor_range) = cursor_state.range(galley) { if let Some(mut cursor_range) = cursor_state.range(galley) {
let galley_rect = global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size()); let galley_rect = global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size());
self.selection_bbox_this_frame |= galley_rect; self.selection_bbox_this_frame |= galley_rect;
if let Some(selection) = &self.selection { if let Some(selection) = &self.selection
if selection.primary.widget_id == response.id { && selection.primary.widget_id == response.id
process_selection_key_events(ui.ctx(), galley, response.id, &mut cursor_range); {
} process_selection_key_events(ui.ctx(), galley, response.id, &mut cursor_range);
} }
if got_copy_event(ui.ctx()) { if got_copy_event(ui.ctx()) {

View File

@ -705,74 +705,74 @@ impl ViewportBuilder {
let mut commands = Vec::new(); let mut commands = Vec::new();
if let Some(new_title) = new_title { if let Some(new_title) = new_title
if Some(&new_title) != self.title.as_ref() { && Some(&new_title) != self.title.as_ref()
self.title = Some(new_title.clone()); {
commands.push(ViewportCommand::Title(new_title)); self.title = Some(new_title.clone());
} commands.push(ViewportCommand::Title(new_title));
} }
if let Some(new_position) = new_position { if let Some(new_position) = new_position
if Some(new_position) != self.position { && Some(new_position) != self.position
self.position = Some(new_position); {
commands.push(ViewportCommand::OuterPosition(new_position)); self.position = Some(new_position);
} commands.push(ViewportCommand::OuterPosition(new_position));
} }
if let Some(new_inner_size) = new_inner_size { if let Some(new_inner_size) = new_inner_size
if Some(new_inner_size) != self.inner_size { && Some(new_inner_size) != self.inner_size
self.inner_size = Some(new_inner_size); {
commands.push(ViewportCommand::InnerSize(new_inner_size)); self.inner_size = Some(new_inner_size);
} commands.push(ViewportCommand::InnerSize(new_inner_size));
} }
if let Some(new_min_inner_size) = new_min_inner_size { if let Some(new_min_inner_size) = new_min_inner_size
if Some(new_min_inner_size) != self.min_inner_size { && Some(new_min_inner_size) != self.min_inner_size
self.min_inner_size = Some(new_min_inner_size); {
commands.push(ViewportCommand::MinInnerSize(new_min_inner_size)); self.min_inner_size = Some(new_min_inner_size);
} commands.push(ViewportCommand::MinInnerSize(new_min_inner_size));
} }
if let Some(new_max_inner_size) = new_max_inner_size { if let Some(new_max_inner_size) = new_max_inner_size
if Some(new_max_inner_size) != self.max_inner_size { && Some(new_max_inner_size) != self.max_inner_size
self.max_inner_size = Some(new_max_inner_size); {
commands.push(ViewportCommand::MaxInnerSize(new_max_inner_size)); self.max_inner_size = Some(new_max_inner_size);
} commands.push(ViewportCommand::MaxInnerSize(new_max_inner_size));
} }
if let Some(new_fullscreen) = new_fullscreen { if let Some(new_fullscreen) = new_fullscreen
if Some(new_fullscreen) != self.fullscreen { && Some(new_fullscreen) != self.fullscreen
self.fullscreen = Some(new_fullscreen); {
commands.push(ViewportCommand::Fullscreen(new_fullscreen)); self.fullscreen = Some(new_fullscreen);
} commands.push(ViewportCommand::Fullscreen(new_fullscreen));
} }
if let Some(new_maximized) = new_maximized { if let Some(new_maximized) = new_maximized
if Some(new_maximized) != self.maximized { && Some(new_maximized) != self.maximized
self.maximized = Some(new_maximized); {
commands.push(ViewportCommand::Maximized(new_maximized)); self.maximized = Some(new_maximized);
} commands.push(ViewportCommand::Maximized(new_maximized));
} }
if let Some(new_resizable) = new_resizable { if let Some(new_resizable) = new_resizable
if Some(new_resizable) != self.resizable { && Some(new_resizable) != self.resizable
self.resizable = Some(new_resizable); {
commands.push(ViewportCommand::Resizable(new_resizable)); self.resizable = Some(new_resizable);
} commands.push(ViewportCommand::Resizable(new_resizable));
} }
if let Some(new_transparent) = new_transparent { if let Some(new_transparent) = new_transparent
if Some(new_transparent) != self.transparent { && Some(new_transparent) != self.transparent
self.transparent = Some(new_transparent); {
commands.push(ViewportCommand::Transparent(new_transparent)); self.transparent = Some(new_transparent);
} commands.push(ViewportCommand::Transparent(new_transparent));
} }
if let Some(new_decorations) = new_decorations { if let Some(new_decorations) = new_decorations
if Some(new_decorations) != self.decorations { && Some(new_decorations) != self.decorations
self.decorations = Some(new_decorations); {
commands.push(ViewportCommand::Decorations(new_decorations)); self.decorations = Some(new_decorations);
} commands.push(ViewportCommand::Decorations(new_decorations));
} }
if let Some(new_icon) = new_icon { if let Some(new_icon) = new_icon {
@ -787,25 +787,25 @@ impl ViewportBuilder {
} }
} }
if let Some(new_visible) = new_visible { if let Some(new_visible) = new_visible
if Some(new_visible) != self.visible { && Some(new_visible) != self.visible
self.visible = Some(new_visible); {
commands.push(ViewportCommand::Visible(new_visible)); self.visible = Some(new_visible);
} commands.push(ViewportCommand::Visible(new_visible));
} }
if let Some(new_mouse_passthrough) = new_mouse_passthrough { if let Some(new_mouse_passthrough) = new_mouse_passthrough
if Some(new_mouse_passthrough) != self.mouse_passthrough { && Some(new_mouse_passthrough) != self.mouse_passthrough
self.mouse_passthrough = Some(new_mouse_passthrough); {
commands.push(ViewportCommand::MousePassthrough(new_mouse_passthrough)); self.mouse_passthrough = Some(new_mouse_passthrough);
} commands.push(ViewportCommand::MousePassthrough(new_mouse_passthrough));
} }
if let Some(new_window_level) = new_window_level { if let Some(new_window_level) = new_window_level
if Some(new_window_level) != self.window_level { && Some(new_window_level) != self.window_level
self.window_level = Some(new_window_level); {
commands.push(ViewportCommand::WindowLevel(new_window_level)); self.window_level = Some(new_window_level);
} commands.push(ViewportCommand::WindowLevel(new_window_level));
} }
// -------------------------------------------------------------- // --------------------------------------------------------------

View File

@ -573,41 +573,39 @@ impl TextEdit<'_> {
let text_clip_rect = rect; let text_clip_rect = rect;
let painter = ui.painter_at(text_clip_rect.expand(1.0)); // expand to avoid clipping cursor let painter = ui.painter_at(text_clip_rect.expand(1.0)); // expand to avoid clipping cursor
if interactive { if interactive && let Some(pointer_pos) = response.interact_pointer_pos() {
if let Some(pointer_pos) = response.interact_pointer_pos() { if response.hovered() && text.is_mutable() {
if response.hovered() && text.is_mutable() { ui.output_mut(|o| o.mutable_text_under_cursor = true);
ui.output_mut(|o| o.mutable_text_under_cursor = true); }
}
// TODO(emilk): drag selected text to either move or clone (ctrl on windows, alt on mac) // TODO(emilk): drag selected text to either move or clone (ctrl on windows, alt on mac)
let cursor_at_pointer = let cursor_at_pointer =
galley.cursor_from_pos(pointer_pos - rect.min + state.text_offset); galley.cursor_from_pos(pointer_pos - rect.min + state.text_offset);
if ui.visuals().text_cursor.preview if ui.visuals().text_cursor.preview
&& response.hovered() && response.hovered()
&& ui.input(|i| i.pointer.is_moving()) && ui.input(|i| i.pointer.is_moving())
{ {
// text cursor preview: // text cursor preview:
let cursor_rect = TSTransform::from_translation(rect.min.to_vec2()) let cursor_rect = TSTransform::from_translation(rect.min.to_vec2())
* cursor_rect(&galley, &cursor_at_pointer, row_height); * cursor_rect(&galley, &cursor_at_pointer, row_height);
text_selection::visuals::paint_cursor_end(&painter, ui.visuals(), cursor_rect); text_selection::visuals::paint_cursor_end(&painter, ui.visuals(), cursor_rect);
} }
let is_being_dragged = ui.ctx().is_being_dragged(response.id); let is_being_dragged = ui.ctx().is_being_dragged(response.id);
let did_interact = state.cursor.pointer_interaction( let did_interact = state.cursor.pointer_interaction(
ui, ui,
&response, &response,
cursor_at_pointer, cursor_at_pointer,
&galley, &galley,
is_being_dragged, is_being_dragged,
); );
if did_interact || response.clicked() { if did_interact || response.clicked() {
ui.memory_mut(|mem| mem.request_focus(response.id)); ui.memory_mut(|mem| mem.request_focus(response.id));
state.last_interaction_time = ui.ctx().input(|i| i.time); state.last_interaction_time = ui.ctx().input(|i| i.time);
}
} }
} }
@ -718,11 +716,9 @@ impl TextEdit<'_> {
let has_focus = ui.memory(|mem| mem.has_focus(id)); let has_focus = ui.memory(|mem| mem.has_focus(id));
if has_focus { if has_focus && let Some(cursor_range) = state.cursor.range(&galley) {
if let Some(cursor_range) = state.cursor.range(&galley) { // Add text selection rectangles to the galley:
// Add text selection rectangles to the galley: paint_text_selection(&mut galley, ui.visuals(), &cursor_range, None);
paint_text_selection(&mut galley, ui.visuals(), &cursor_range, None);
}
} }
if !clip_text { if !clip_text {
@ -762,50 +758,47 @@ impl TextEdit<'_> {
painter.galley(galley_pos, galley.clone(), text_color); painter.galley(galley_pos, galley.clone(), text_color);
if has_focus { if has_focus && let Some(cursor_range) = state.cursor.range(&galley) {
if let Some(cursor_range) = state.cursor.range(&galley) { let primary_cursor_rect = cursor_rect(&galley, &cursor_range.primary, row_height)
let primary_cursor_rect = .translate(galley_pos.to_vec2());
cursor_rect(&galley, &cursor_range.primary, row_height)
.translate(galley_pos.to_vec2());
if response.changed() || selection_changed {
// Scroll to keep primary cursor in view:
ui.scroll_to_rect(primary_cursor_rect + margin, None);
}
if text.is_mutable() && interactive {
let now = ui.ctx().input(|i| i.time);
if response.changed() || selection_changed { if response.changed() || selection_changed {
// Scroll to keep primary cursor in view: state.last_interaction_time = now;
ui.scroll_to_rect(primary_cursor_rect + margin, None);
} }
if text.is_mutable() && interactive { // Only show (and blink) cursor if the egui viewport has focus.
let now = ui.ctx().input(|i| i.time); // This is for two reasons:
if response.changed() || selection_changed { // * Don't give the impression that the user can type into a window without focus
state.last_interaction_time = now; // * Don't repaint the ui because of a blinking cursor in an app that is not in focus
} let viewport_has_focus = ui.ctx().input(|i| i.focused);
if viewport_has_focus {
text_selection::visuals::paint_text_cursor(
ui,
&painter,
primary_cursor_rect,
now - state.last_interaction_time,
);
}
// Only show (and blink) cursor if the egui viewport has focus. // Set IME output (in screen coords) when text is editable and visible
// This is for two reasons: let to_global = ui
// * Don't give the impression that the user can type into a window without focus .ctx()
// * Don't repaint the ui because of a blinking cursor in an app that is not in focus .layer_transform_to_global(ui.layer_id())
let viewport_has_focus = ui.ctx().input(|i| i.focused); .unwrap_or_default();
if viewport_has_focus {
text_selection::visuals::paint_text_cursor(
ui,
&painter,
primary_cursor_rect,
now - state.last_interaction_time,
);
}
// Set IME output (in screen coords) when text is editable and visible ui.ctx().output_mut(|o| {
let to_global = ui o.ime = Some(crate::output::IMEOutput {
.ctx() rect: to_global * rect,
.layer_transform_to_global(ui.layer_id()) cursor_rect: to_global * primary_cursor_rect,
.unwrap_or_default();
ui.ctx().output_mut(|o| {
o.ime = Some(crate::output::IMEOutput {
rect: to_global * rect,
cursor_rect: to_global * primary_cursor_rect,
});
}); });
} });
} }
} }
} }

View File

@ -64,11 +64,11 @@ impl eframe::App for ImageViewer {
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
if ui.button("file…").clicked() { if ui.button("file…").clicked()
if let Some(path) = rfd::FileDialog::new().pick_file() { && let Some(path) = rfd::FileDialog::new().pick_file()
self.uri_edit_text = format!("file://{}", path.display()); {
self.current_uri = self.uri_edit_text.clone(); self.uri_edit_text = format!("file://{}", path.display());
} self.current_uri = self.uri_edit_text.clone();
} }
}); });
}); });

View File

@ -194,10 +194,10 @@ impl WrapApp {
}; };
#[cfg(feature = "persistence")] #[cfg(feature = "persistence")]
if let Some(storage) = cc.storage { if let Some(storage) = cc.storage
if let Some(state) = eframe::get_value(storage, eframe::APP_KEY) { && let Some(state) = eframe::get_value(storage, eframe::APP_KEY)
slf.state = state; {
} slf.state = state;
} }
slf slf

View File

@ -421,10 +421,11 @@ mod tests {
} }
fn remove_leading_emoji(full_name: &str) -> &str { fn remove_leading_emoji(full_name: &str) -> &str {
if let Some((start, name)) = full_name.split_once(' ') { if let Some((start, name)) = full_name.split_once(' ')
if start.len() <= 4 && start.bytes().next().is_some_and(|byte| byte >= 128) { && start.len() <= 4
return name; && start.bytes().next().is_some_and(|byte| byte >= 128)
} {
return name;
} }
full_name full_name
} }

View File

@ -336,5 +336,5 @@ fn long_text(row_index: usize) -> String {
} }
fn thick_row(row_index: usize) -> bool { fn thick_row(row_index: usize) -> bool {
row_index % 6 == 0 row_index.is_multiple_of(6)
} }

View File

@ -67,10 +67,9 @@ impl crate::View for ClipboardTest {
if let Ok(egui::load::ImagePoll::Ready { image }) = if let Ok(egui::load::ImagePoll::Ready { image }) =
ui.ctx().try_load_image(&uri, Default::default()) ui.ctx().try_load_image(&uri, Default::default())
&& ui.button("📋").clicked()
{ {
if ui.button("📋").clicked() { ui.ctx().copy_image((*image).clone());
ui.ctx().copy_image((*image).clone());
}
} }
}); });

View File

@ -12,11 +12,11 @@ struct DeduplicatedHistory {
impl DeduplicatedHistory { impl DeduplicatedHistory {
fn add(&mut self, summary: String, full: String) { fn add(&mut self, summary: String, full: String) {
if let Some(entry) = self.history.back_mut() { if let Some(entry) = self.history.back_mut()
if entry.summary == summary { && entry.summary == summary
entry.entries.push(full); {
return; entry.entries.push(full);
} return;
} }
self.history.push_back(HistoryEntry { self.history.push_back(HistoryEntry {
summary, summary,

View File

@ -10,11 +10,11 @@ struct DeduplicatedHistory {
impl DeduplicatedHistory { impl DeduplicatedHistory {
fn add(&mut self, text: String) { fn add(&mut self, text: String) {
if let Some(entry) = self.history.back_mut() { if let Some(entry) = self.history.back_mut()
if entry.text == text { && entry.text == text
entry.repeated += 1; {
return; entry.repeated += 1;
} return;
} }
self.history.push_back(HistoryEntry { text, repeated: 1 }); self.history.push_back(HistoryEntry { text, repeated: 1 });
if self.history.len() > 100 { if self.history.len() > 100 {

View File

@ -65,20 +65,20 @@ impl crate::View for TextEditDemo {
egui::Label::new("Press ctrl+Y to toggle the case of selected text (cmd+Y on Mac)"), egui::Label::new("Press ctrl+Y to toggle the case of selected text (cmd+Y on Mac)"),
); );
if ui.input_mut(|i| i.consume_key(egui::Modifiers::COMMAND, egui::Key::Y)) { if ui.input_mut(|i| i.consume_key(egui::Modifiers::COMMAND, egui::Key::Y))
if let Some(text_cursor_range) = output.cursor_range { && let Some(text_cursor_range) = output.cursor_range
use egui::TextBuffer as _; {
let selected_chars = text_cursor_range.as_sorted_char_range(); use egui::TextBuffer as _;
let selected_text = text.char_range(selected_chars.clone()); let selected_chars = text_cursor_range.as_sorted_char_range();
let upper_case = selected_text.to_uppercase(); let selected_text = text.char_range(selected_chars.clone());
let new_text = if selected_text == upper_case { let upper_case = selected_text.to_uppercase();
selected_text.to_lowercase() let new_text = if selected_text == upper_case {
} else { selected_text.to_lowercase()
upper_case } else {
}; upper_case
text.delete_char_range(selected_chars.clone()); };
text.insert_text(&new_text, selected_chars.start); text.delete_char_range(selected_chars.clone());
} text.insert_text(&new_text, selected_chars.start);
} }
ui.horizontal(|ui| { ui.horizontal(|ui| {

View File

@ -60,15 +60,11 @@ impl crate::View for UndoRedoDemo {
let undo = ui.add_enabled(can_undo, Button::new("⟲ Undo")).clicked(); let undo = ui.add_enabled(can_undo, Button::new("⟲ Undo")).clicked();
let redo = ui.add_enabled(can_redo, Button::new("⟳ Redo")).clicked(); let redo = ui.add_enabled(can_redo, Button::new("⟳ Redo")).clicked();
if undo { if undo && let Some(undo_text) = self.undoer.undo(&self.state) {
if let Some(undo_text) = self.undoer.undo(&self.state) { self.state = undo_text.clone();
self.state = undo_text.clone();
}
} }
if redo { if redo && let Some(redo_text) = self.undoer.redo(&self.state) {
if let Some(redo_text) = self.undoer.redo(&self.state) { self.state = redo_text.clone();
self.state = redo_text.clone();
}
} }
}); });

View File

@ -96,13 +96,13 @@ impl EasyMarkEditor {
ui.add(egui::TextEdit::multiline(code).desired_width(f32::INFINITY)) ui.add(egui::TextEdit::multiline(code).desired_width(f32::INFINITY))
}; };
if let Some(mut state) = TextEdit::load_state(ui.ctx(), response.id) { if let Some(mut state) = TextEdit::load_state(ui.ctx(), response.id)
if let Some(mut ccursor_range) = state.cursor.char_range() { && let Some(mut ccursor_range) = state.cursor.char_range()
let any_change = shortcuts(ui, code, &mut ccursor_range); {
if any_change { let any_change = shortcuts(ui, code, &mut ccursor_range);
state.cursor.set_char_range(Some(ccursor_range)); if any_change {
state.store(ui.ctx(), response.id); state.cursor.set_char_range(Some(ccursor_range));
} state.store(ui.ctx(), response.id);
} }
} }
} }

View File

@ -113,19 +113,19 @@ impl<'a> Parser<'a> {
// ```{language}\n{code}``` // ```{language}\n{code}```
fn code_block(&mut self) -> Option<Item<'a>> { fn code_block(&mut self) -> Option<Item<'a>> {
if let Some(language_start) = self.s.strip_prefix("```") { if let Some(language_start) = self.s.strip_prefix("```")
if let Some(newline) = language_start.find('\n') { && let Some(newline) = language_start.find('\n')
let language = &language_start[..newline]; {
let code_start = &language_start[newline + 1..]; let language = &language_start[..newline];
if let Some(end) = code_start.find("\n```") { let code_start = &language_start[newline + 1..];
let code = &code_start[..end].trim(); if let Some(end) = code_start.find("\n```") {
self.s = &code_start[end + 4..]; let code = &code_start[..end].trim();
self.start_of_line = false; self.s = &code_start[end + 4..];
return Some(Item::CodeBlock(language, code)); self.start_of_line = false;
} else { return Some(Item::CodeBlock(language, code));
self.s = ""; } else {
return Some(Item::CodeBlock(language, code_start)); self.s = "";
} return Some(Item::CodeBlock(language, code_start));
} }
} }
None None
@ -171,14 +171,14 @@ impl<'a> Parser<'a> {
let this_line = &self.s[..self.s.find('\n').unwrap_or(self.s.len())]; let this_line = &self.s[..self.s.find('\n').unwrap_or(self.s.len())];
if let Some(bracket_end) = this_line.find(']') { if let Some(bracket_end) = this_line.find(']') {
let text = &this_line[1..bracket_end]; let text = &this_line[1..bracket_end];
if this_line[bracket_end + 1..].starts_with('(') { if this_line[bracket_end + 1..].starts_with('(')
if let Some(parens_end) = this_line[bracket_end + 2..].find(')') { && let Some(parens_end) = this_line[bracket_end + 2..].find(')')
let parens_end = bracket_end + 2 + parens_end; {
let url = &self.s[bracket_end + 2..parens_end]; let parens_end = bracket_end + 2 + parens_end;
self.s = &self.s[parens_end + 1..]; let url = &self.s[bracket_end + 2..parens_end];
self.start_of_line = false; self.s = &self.s[parens_end + 1..];
return Some(Item::Hyperlink(self.style, text, url)); self.start_of_line = false;
} return Some(Item::Hyperlink(self.style, text, url));
} }
} }
} }

View File

@ -161,12 +161,12 @@ impl ImageLoader for ImageCrateLoader {
match ctx.try_load_bytes(uri) { match ctx.try_load_bytes(uri) {
Ok(BytesPoll::Ready { bytes, mime, .. }) => { Ok(BytesPoll::Ready { bytes, mime, .. }) => {
// (2) // (2)
if let Some(mime) = mime { if let Some(mime) = mime
if !is_supported_mime(&mime) { && !is_supported_mime(&mime)
return Err(LoadError::FormatNotSupported { {
detected_format: Some(mime), return Err(LoadError::FormatNotSupported {
}); detected_format: Some(mime),
} });
} }
load_image(ctx, uri, &self.cache, &bytes) load_image(ctx, uri, &self.cache, &bytes)
} }

View File

@ -144,11 +144,11 @@ impl Sizing {
let mut remainder_length = length - sum_non_remainder; let mut remainder_length = length - sum_non_remainder;
let avg_remainder_length = 0.0f32.max(remainder_length / num_remainders as f32).floor(); let avg_remainder_length = 0.0f32.max(remainder_length / num_remainders as f32).floor();
for &size in &self.sizes { for &size in &self.sizes {
if let Size::Remainder { range } = size { if let Size::Remainder { range } = size
if avg_remainder_length < range.min { && avg_remainder_length < range.min
remainder_length -= range.min; {
num_remainders -= 1; remainder_length -= range.min;
} num_remainders -= 1;
} }
} }
if num_remainders > 0 { if num_remainders > 0 {

View File

@ -472,10 +472,10 @@ impl<'a> TableBuilder<'a> {
for (i, column) in columns.iter_mut().enumerate() { for (i, column) in columns.iter_mut().enumerate() {
let column_resize_id = ui.id().with("resize_column").with(i); let column_resize_id = ui.id().with("resize_column").with(i);
if let Some(response) = ui.ctx().read_response(column_resize_id) { if let Some(response) = ui.ctx().read_response(column_resize_id)
if response.double_clicked() { && response.double_clicked()
column.auto_size_this_frame = true; {
} column.auto_size_this_frame = true;
} }
} }
@ -864,27 +864,27 @@ impl Table<'_> {
if column.auto_size_this_frame { if column.auto_size_this_frame {
// Auto-size: resize to what is needed. // Auto-size: resize to what is needed.
*column_width = width_range.clamp(max_used_widths[i]); *column_width = width_range.clamp(max_used_widths[i]);
} else if resize_response.dragged() { } else if resize_response.dragged()
if let Some(pointer) = ui.ctx().pointer_latest_pos() { && let Some(pointer) = ui.ctx().pointer_latest_pos()
let mut new_width = *column_width + pointer.x - x; {
if !column.clip { let mut new_width = *column_width + pointer.x - x;
// Unless we clip we don't want to shrink below the if !column.clip {
// size that was actually used. // Unless we clip we don't want to shrink below the
// However, we still want to allow content that shrinks when you try // size that was actually used.
// to make the column less wide, so we allow some small shrinkage each frame: // However, we still want to allow content that shrinks when you try
// big enough to allow shrinking over time, small enough not to look ugly when // to make the column less wide, so we allow some small shrinkage each frame:
// shrinking fails. This is a bit of a HACK around immediate mode. // big enough to allow shrinking over time, small enough not to look ugly when
let max_shrinkage_per_frame = 8.0; // shrinking fails. This is a bit of a HACK around immediate mode.
new_width = let max_shrinkage_per_frame = 8.0;
new_width.at_least(max_used_widths[i] - max_shrinkage_per_frame); new_width =
} new_width.at_least(max_used_widths[i] - max_shrinkage_per_frame);
new_width = width_range.clamp(new_width);
let x = x - *column_width + new_width;
(p0.x, p1.x) = (x, x);
*column_width = new_width;
} }
new_width = width_range.clamp(new_width);
let x = x - *column_width + new_width;
(p0.x, p1.x) = (x, x);
*column_width = new_width;
} }
let dragging_something_else = let dragging_something_else =
@ -991,7 +991,7 @@ impl<'a> TableBody<'a> {
row_index: self.row_index, row_index: self.row_index,
col_index: 0, col_index: 0,
height, height,
striped: self.striped && self.row_index % 2 == 0, striped: self.striped && self.row_index.is_multiple_of(2),
hovered: self.hovered_row_index == Some(self.row_index), hovered: self.hovered_row_index == Some(self.row_index),
selected: false, selected: false,
overline: false, overline: false,
@ -1073,7 +1073,7 @@ impl<'a> TableBody<'a> {
row_index, row_index,
col_index: 0, col_index: 0,
height: row_height_sans_spacing, height: row_height_sans_spacing,
striped: self.striped && (row_index + self.row_index) % 2 == 0, striped: self.striped && (row_index + self.row_index).is_multiple_of(2),
hovered: self.hovered_row_index == Some(row_index), hovered: self.hovered_row_index == Some(row_index),
selected: false, selected: false,
overline: false, overline: false,
@ -1155,7 +1155,7 @@ impl<'a> TableBody<'a> {
row_index, row_index,
col_index: 0, col_index: 0,
height: row_height, height: row_height,
striped: self.striped && (row_index + self.row_index) % 2 == 0, striped: self.striped && (row_index + self.row_index).is_multiple_of(2),
hovered: self.hovered_row_index == Some(row_index), hovered: self.hovered_row_index == Some(row_index),
selected: false, selected: false,
overline: false, overline: false,
@ -1178,7 +1178,7 @@ impl<'a> TableBody<'a> {
row_index, row_index,
col_index: 0, col_index: 0,
height: row_height, height: row_height,
striped: self.striped && (row_index + self.row_index) % 2 == 0, striped: self.striped && (row_index + self.row_index).is_multiple_of(2),
hovered: self.hovered_row_index == Some(row_index), hovered: self.hovered_row_index == Some(row_index),
overline: false, overline: false,
selected: false, selected: false,

View File

@ -239,17 +239,17 @@ impl FontImpl {
return None; // these will result in the replacement character when rendering return None; // these will result in the replacement character when rendering
} }
if c == '\t' { if c == '\t'
if let Some(space) = self.glyph_info(' ') { && let Some(space) = self.glyph_info(' ')
let glyph_info = GlyphInfo { {
advance_width_unscaled: (crate::text::TAB_SIZE as f32 let glyph_info = GlyphInfo {
* space.advance_width_unscaled.0) advance_width_unscaled: (crate::text::TAB_SIZE as f32
.into(), * space.advance_width_unscaled.0)
..space .into(),
}; ..space
self.glyph_info_cache.insert(c, glyph_info); };
return Some(glyph_info); self.glyph_info_cache.insert(c, glyph_info);
} return Some(glyph_info);
} }
if c == '\u{2009}' { if c == '\u{2009}' {

View File

@ -113,13 +113,11 @@ pub fn layout(fonts: &mut FontsImpl, pixels_per_point: f32, job: Arc<LayoutJob>)
let mut elided = false; let mut elided = false;
let mut rows = rows_from_paragraphs(paragraphs, &job, &mut elided); let mut rows = rows_from_paragraphs(paragraphs, &job, &mut elided);
if elided { if elided && let Some(last_placed) = rows.last_mut() {
if let Some(last_placed) = rows.last_mut() { let last_row = Arc::make_mut(&mut last_placed.row);
let last_row = Arc::make_mut(&mut last_placed.row); replace_last_glyph_with_overflow_character(fonts, pixels_per_point, &job, last_row);
replace_last_glyph_with_overflow_character(fonts, pixels_per_point, &job, last_row); if let Some(last) = last_row.glyphs.last() {
if let Some(last) = last_row.glyphs.last() { last_row.size.x = last.max_x();
last_row.size.x = last.max_x();
}
} }
} }

View File

@ -957,15 +957,15 @@ impl Galley {
// Vertical margin around galley improves text selection UX // Vertical margin around galley improves text selection UX
const VMARGIN: f32 = 5.0; const VMARGIN: f32 = 5.0;
if let Some(first_row) = self.rows.first() { if let Some(first_row) = self.rows.first()
if pos.y < first_row.min_y() - VMARGIN { && pos.y < first_row.min_y() - VMARGIN
return self.begin(); {
} return self.begin();
} }
if let Some(last_row) = self.rows.last() { if let Some(last_row) = self.rows.last()
if last_row.max_y() + VMARGIN < pos.y { && last_row.max_y() + VMARGIN < pos.y
return self.end(); {
} return self.end();
} }
let mut best_y_dist = f32::INFINITY; let mut best_y_dist = f32::INFINITY;

View File

@ -29,10 +29,10 @@ impl eframe::App for MyApp {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.label("Drag-and-drop files onto the window!"); ui.label("Drag-and-drop files onto the window!");
if ui.button("Open file…").clicked() { if ui.button("Open file…").clicked()
if let Some(path) = rfd::FileDialog::new().pick_file() { && let Some(path) = rfd::FileDialog::new().pick_file()
self.picked_path = Some(path.display().to_string()); {
} self.picked_path = Some(path.display().to_string());
} }
if let Some(picked_path) = &self.picked_path { if let Some(picked_path) = &self.picked_path {

View File

@ -56,24 +56,24 @@ impl Application {
impl eframe::App for Application { impl eframe::App for Application {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
if let Some(request_at) = self.request_at { if let Some(request_at) = self.request_at
if request_at < SystemTime::now() { && request_at < SystemTime::now()
self.request_at = None; {
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention)); self.request_at = None;
if self.auto_reset { ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention));
self.auto_reset = false; if self.auto_reset {
self.reset_at = Some(SystemTime::now() + Self::attention_reset_timeout()); self.auto_reset = false;
} self.reset_at = Some(SystemTime::now() + Self::attention_reset_timeout());
} }
} }
if let Some(reset_at) = self.reset_at { if let Some(reset_at) = self.reset_at
if reset_at < SystemTime::now() { && reset_at < SystemTime::now()
self.reset_at = None; {
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention( self.reset_at = None;
UserAttentionType::Reset, ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(
)); UserAttentionType::Reset,
} ));
} }
CentralPanel::default().show(ctx, |ui| { CentralPanel::default().show(ctx, |ui| {