Use a lot more let-else (#7582)
This commit is contained in:
parent
4c1f344ef8
commit
bd45406fad
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ 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 {
|
||||||
title,
|
title,
|
||||||
|
|
@ -275,14 +275,13 @@ 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_");
|
profiling::scope!("setTitle_");
|
||||||
app_menu.setTitle(&NSString::from_str(title));
|
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.
|
||||||
// At least these people didn't figure it out either:
|
// At least these people didn't figure it out either:
|
||||||
|
|
|
||||||
|
|
@ -52,15 +52,14 @@ 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,8 +331,9 @@ 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");
|
profiling::scope!("native_window");
|
||||||
epi::set_value(
|
epi::set_value(
|
||||||
storage,
|
storage,
|
||||||
|
|
@ -341,7 +341,6 @@ impl EpiIntegration {
|
||||||
&WindowSettings::from_window(self.egui_ctx.zoom_factor(), window),
|
&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");
|
||||||
self.egui_ctx
|
self.egui_ctx
|
||||||
|
|
|
||||||
|
|
@ -193,13 +193,12 @@ 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) {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
|
|
|
||||||
|
|
@ -281,11 +281,10 @@ 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)
|
||||||
.expect("Single-use AppCreator has unexpectedly already been taken");
|
.expect("Single-use AppCreator has unexpectedly already been taken");
|
||||||
|
|
@ -440,8 +439,9 @@ 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();
|
let mut glutin = running.glutin.borrow_mut();
|
||||||
if let Some(viewport) = glutin
|
if let Some(viewport) = glutin
|
||||||
.focused_viewport
|
.focused_viewport
|
||||||
|
|
@ -456,7 +456,6 @@ impl WinitApp for GlowWinitApp<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(EventResult::Wait)
|
Ok(EventResult::Wait)
|
||||||
}
|
}
|
||||||
|
|
@ -480,9 +479,10 @@ 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(
|
return Ok(winit_integration::on_accesskit_window_event(
|
||||||
egui_winit,
|
egui_winit,
|
||||||
event.window_id,
|
event.window_id,
|
||||||
|
|
@ -490,8 +490,6 @@ impl WinitApp for GlowWinitApp<'_> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(EventResult::Wait)
|
Ok(EventResult::Wait)
|
||||||
}
|
}
|
||||||
|
|
@ -527,11 +525,11 @@ 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,11 +725,11 @@ 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,13 +783,14 @@ 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
|
||||||
|
&& let Some(viewport_id) = viewport_id
|
||||||
|
{
|
||||||
repaint_asap = true;
|
repaint_asap = true;
|
||||||
glutin.resize(viewport_id, *physical_size);
|
glutin.resize(viewport_id, *physical_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
winit::event::WindowEvent::CloseRequested => {
|
winit::event::WindowEvent::CloseRequested => {
|
||||||
if viewport_id == Some(ViewportId::ROOT) && self.integration.should_close() {
|
if viewport_id == Some(ViewportId::ROOT) && self.integration.should_close() {
|
||||||
|
|
@ -803,8 +802,9 @@ 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:
|
// Tell viewport it should close:
|
||||||
viewport.info.events.push(egui::ViewportEvent::Close);
|
viewport.info.events.push(egui::ViewportEvent::Close);
|
||||||
|
|
||||||
|
|
@ -817,7 +817,6 @@ impl GlowWinitRunning<'_> {
|
||||||
.request_repaint_of(viewport.ids.parent);
|
.request_repaint_of(viewport.ids.parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1232,8 +1231,9 @@ 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(
|
change_gl_context(
|
||||||
&mut self.current_gl_context,
|
&mut self.current_gl_context,
|
||||||
&mut self.not_current_gl_context,
|
&mut self.not_current_gl_context,
|
||||||
|
|
@ -1248,7 +1248,6 @@ impl GlutinWindowContext {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn get_proc_address(&self, addr: &std::ffi::CStr) -> *const std::ffi::c_void {
|
fn get_proc_address(&self, addr: &std::ffi::CStr) -> *const std::ffi::c_void {
|
||||||
self.gl_config.display().get_proc_address(addr)
|
self.gl_config.display().get_proc_address(addr)
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,9 @@ 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:?}");
|
log::trace!("RepaintNow of {window_id:?}");
|
||||||
self.windows_next_repaint_times
|
self.windows_next_repaint_times
|
||||||
.insert(window_id, Instant::now());
|
.insert(window_id, Instant::now());
|
||||||
|
|
@ -103,7 +104,6 @@ impl<T: WinitApp> WinitAppWrapper<T> {
|
||||||
// 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 {
|
||||||
EventResult::Wait => {
|
EventResult::Wait => {
|
||||||
|
|
|
||||||
|
|
@ -429,8 +429,9 @@ 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();
|
let mut shared = running.shared.borrow_mut();
|
||||||
if let Some(viewport) = shared
|
if let Some(viewport) = shared
|
||||||
.focused_viewport
|
.focused_viewport
|
||||||
|
|
@ -445,7 +446,6 @@ impl WinitApp for WgpuWinitApp<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(EventResult::Wait)
|
Ok(EventResult::Wait)
|
||||||
}
|
}
|
||||||
|
|
@ -478,8 +478,8 @@ 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,
|
||||||
|
|
@ -487,7 +487,6 @@ impl WinitApp for WgpuWinitApp<'_> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(EventResult::Wait)
|
Ok(EventResult::Wait)
|
||||||
}
|
}
|
||||||
|
|
@ -563,11 +562,11 @@ 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,14 +729,14 @@ 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:
|
// On Mac, a minimized Window uses up all CPU:
|
||||||
// https://github.com/emilk/egui/issues/325
|
// https://github.com/emilk/egui/issues/325
|
||||||
profiling::scope!("minimized_sleep");
|
profiling::scope!("minimized_sleep");
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if integration.should_close() {
|
if integration.should_close() {
|
||||||
Ok(EventResult::CloseRequested)
|
Ok(EventResult::CloseRequested)
|
||||||
|
|
@ -784,16 +783,16 @@ 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;
|
repaint_asap = true;
|
||||||
shared.painter.on_window_resized(viewport_id, width, height);
|
shared.painter.on_window_resized(viewport_id, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
winit::event::WindowEvent::CloseRequested => {
|
winit::event::WindowEvent::CloseRequested => {
|
||||||
if viewport_id == Some(ViewportId::ROOT) && integration.should_close() {
|
if viewport_id == Some(ViewportId::ROOT) && integration.should_close() {
|
||||||
|
|
@ -805,8 +804,9 @@ 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:
|
// Tell viewport it should close:
|
||||||
viewport.info.events.push(egui::ViewportEvent::Close);
|
viewport.info.events.push(egui::ViewportEvent::Close);
|
||||||
|
|
||||||
|
|
@ -817,7 +817,6 @@ impl WgpuWinitRunning<'_> {
|
||||||
integration.egui_ctx.request_repaint_of(viewport.ids.parent);
|
integration.egui_ctx.request_repaint_of(viewport.ids.parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -1087,17 +1086,17 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
remove_viewports_not_in(viewports, painter, viewport_from_window, viewport_output);
|
remove_viewports_not_in(viewports, painter, viewport_from_window, viewport_output);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,8 +498,7 @@ 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,
|
||||||
|
|
@ -507,7 +506,6 @@ impl Painter {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let encoded = {
|
let encoded = {
|
||||||
profiling::scope!("CommandEncoder::finish");
|
profiling::scope!("CommandEncoder::finish");
|
||||||
|
|
@ -535,8 +533,9 @@ 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(
|
screen_capture_state.read_screen_rgba(
|
||||||
self.context.clone(),
|
self.context.clone(),
|
||||||
capture_buffer,
|
capture_buffer,
|
||||||
|
|
@ -545,7 +544,6 @@ impl Painter {
|
||||||
viewport_id,
|
viewport_id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
profiling::scope!("present");
|
profiling::scope!("present");
|
||||||
|
|
|
||||||
|
|
@ -574,8 +574,9 @@ 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 {
|
||||||
|
|
@ -612,7 +613,6 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn on_cursor_moved(
|
fn on_cursor_moved(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -913,13 +913,13 @@ 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");
|
profiling::scope!("accesskit");
|
||||||
accesskit.update_if_active(|| update);
|
accesskit.update_if_active(|| update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn set_cursor_icon(&mut self, window: &Window, cursor_icon: egui::CursorIcon) {
|
fn set_cursor_icon(&mut self, window: &Window, cursor_icon: egui::CursorIcon) {
|
||||||
if self.current_cursor_icon == Some(cursor_icon) {
|
if self.current_cursor_icon == Some(cursor_icon) {
|
||||||
|
|
@ -1378,12 +1378,12 @@ 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) => {
|
||||||
let width_px = pixels_per_point * size.x.max(1.0);
|
let width_px = pixels_per_point * size.x.max(1.0);
|
||||||
let height_px = pixels_per_point * size.y.max(1.0);
|
let height_px = pixels_per_point * size.y.max(1.0);
|
||||||
|
|
@ -1795,11 +1795,11 @@ 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}");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// In `create_winit_window_builder` we didn't know
|
// In `create_winit_window_builder` we didn't know
|
||||||
|
|
@ -1809,8 +1809,8 @@ 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,
|
||||||
|
|
@ -1819,7 +1819,6 @@ pub fn apply_viewport_builder_to_window(
|
||||||
{
|
{
|
||||||
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(
|
||||||
pixels_per_point * size.x,
|
pixels_per_point * size.x,
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@ 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();
|
||||||
|
|
||||||
let name = symbol
|
let name = symbol
|
||||||
|
|
|
||||||
|
|
@ -525,11 +525,12 @@ impl Area {
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
if movable && move_response.dragged() {
|
if movable
|
||||||
if let Some(pivot_pos) = &mut state.pivot_pos {
|
&& move_response.dragged()
|
||||||
|
&& let Some(pivot_pos) = &mut state.pivot_pos
|
||||||
|
{
|
||||||
*pivot_pos += move_response.drag_delta();
|
*pivot_pos += move_response.drag_delta();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (move_response.dragged() || move_response.clicked())
|
if (move_response.dragged() || move_response.clicked())
|
||||||
|| pointer_pressed_on_area(ctx, layer_id)
|
|| pointer_pressed_on_area(ctx, layer_id)
|
||||||
|
|
@ -606,8 +607,9 @@ 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 =
|
let age =
|
||||||
ctx.input(|i| (i.time - last_became_visible_at) as f32 + i.predicted_dt / 2.0);
|
ctx.input(|i| (i.time - last_became_visible_at) as f32 + i.predicted_dt / 2.0);
|
||||||
let opacity = crate::remap_clamp(age, 0.0..=ctx.style().animation_time, 0.0..=1.0);
|
let opacity = crate::remap_clamp(age, 0.0..=ctx.style().animation_time, 0.0..=1.0);
|
||||||
|
|
@ -617,7 +619,6 @@ impl Prepared {
|
||||||
ctx.request_repaint();
|
ctx.request_repaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ui
|
ui
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -266,15 +266,13 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
panel_rect = panel_rect.round_ui();
|
panel_rect = panel_rect.round_ui();
|
||||||
|
|
||||||
|
|
@ -765,16 +763,13 @@ 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 =
|
height = clamp_to_range(height, height_range).at_most(available_rect.height());
|
||||||
clamp_to_range(height, height_range).at_most(available_rect.height());
|
|
||||||
side.set_rect_height(&mut panel_rect, height);
|
side.set_rect_height(&mut panel_rect, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
panel_rect = panel_rect.round_ui();
|
panel_rect = panel_rect.round_ui();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// Respond to the interaction early to avoid frame delay.
|
||||||
user_requested_size =
|
user_requested_size = Some(pointer_pos - position + 0.5 * corner_response.rect.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 {
|
||||||
|
|
|
||||||
|
|
@ -240,8 +240,9 @@ 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 pointer_in_scene = to_global.inverse() * mouse_pos;
|
||||||
let zoom_delta = ui.ctx().input(|i| i.zoom_delta());
|
let zoom_delta = ui.ctx().input(|i| i.zoom_delta());
|
||||||
let pan_delta = ui.ctx().input(|i| i.smooth_scroll_delta);
|
let pan_delta = ui.ctx().input(|i| i.smooth_scroll_delta);
|
||||||
|
|
@ -273,5 +274,4 @@ impl Scene {
|
||||||
resp.mark_changed();
|
resp.mark_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -829,13 +829,13 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll with an animation if we have a target offset (that hasn't been cleared by the code
|
// Scroll with an animation if we have a target offset (that hasn't been cleared by the code
|
||||||
// above).
|
// above).
|
||||||
|
|
|
||||||
|
|
@ -645,11 +645,11 @@ 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 {
|
||||||
inner: content_inner,
|
inner: content_inner,
|
||||||
|
|
@ -839,12 +839,12 @@ 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.requested_size = Some(new_rect.size() - margins);
|
||||||
state.store(ctx, resize_id);
|
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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -426,8 +426,7 @@ 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;
|
||||||
|
|
||||||
|
|
@ -440,7 +439,6 @@ impl ContextImpl {
|
||||||
// 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()
|
||||||
.native_pixels_per_point
|
.native_pixels_per_point
|
||||||
|
|
@ -1105,8 +1103,9 @@ 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 {
|
let tooltip_pos = if below {
|
||||||
text_rect.left_bottom() + vec2(2.0, 4.0)
|
text_rect.left_bottom() + vec2(2.0, 4.0)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1122,7 +1121,6 @@ impl Context {
|
||||||
if below { "above" } else { "below" }),
|
if below { "above" } else { "below" }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let id_str = id.short_debug_format();
|
let id_str = id.short_debug_format();
|
||||||
|
|
@ -1253,11 +1251,11 @@ 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,15 +1959,14 @@ 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
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if update_fonts {
|
if update_fonts {
|
||||||
|
|
|
||||||
|
|
@ -317,8 +317,8 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
@ -330,7 +330,6 @@ fn hit_test_on_close(close: &[WidgetRect], pos: Pos2) -> WidgetHits {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
WidgetHits {
|
WidgetHits {
|
||||||
click: None,
|
click: None,
|
||||||
|
|
@ -425,15 +424,15 @@ 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.
|
// It's a tie! Pick the thin candidate over the thick one.
|
||||||
// This makes it easier to hit a thin resize-handle, for instance:
|
// This makes it easier to hit a thin resize-handle, for instance:
|
||||||
if should_prioritize_hits_on_back(closest.interact_rect, widget.interact_rect) {
|
if should_prioritize_hits_on_back(closest.interact_rect, widget.interact_rect) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// In case of a tie, take the last one = the one on top.
|
// In case of a tie, take the last one = the one on top.
|
||||||
if dist_sq <= closest_dist_sq {
|
if dist_sq <= closest_dist_sq {
|
||||||
|
|
|
||||||
|
|
@ -884,11 +884,12 @@ 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
|
||||||
|
&& request.action == action
|
||||||
|
{
|
||||||
return Some(request);
|
return Some(request);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -901,11 +902,11 @@ 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,11 +1469,11 @@ 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
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -115,20 +115,20 @@ 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.
|
// The widget we were interested in clicking is gone.
|
||||||
interaction.potential_click_id = None;
|
interaction.potential_click_id = None;
|
||||||
}
|
}
|
||||||
}
|
if let Some(id) = interaction.potential_drag_id
|
||||||
if let Some(id) = interaction.potential_drag_id {
|
&& !widgets.contains(id)
|
||||||
if !widgets.contains(id) {
|
{
|
||||||
// The widget we were interested in dragging is gone.
|
// The widget we were interested in dragging is gone.
|
||||||
// This is fine! This could be drag-and-drop,
|
// This is fine! This could be drag-and-drop,
|
||||||
// and the widget being dragged is now "in the air" and thus
|
// and the widget being dragged is now "in the air" and thus
|
||||||
// not registered in the new frame.
|
// not registered in the new frame.
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut clicked = None;
|
let mut clicked = None;
|
||||||
let mut dragged = prev_snapshot.dragged;
|
let mut dragged = prev_snapshot.dragged;
|
||||||
|
|
@ -172,14 +172,14 @@ 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;
|
||||||
interaction.potential_click_id = None;
|
interaction.potential_click_id = None;
|
||||||
|
|
@ -190,8 +190,9 @@ 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() {
|
let is_dragged = if widget.sense.senses_click() && widget.sense.senses_drag() {
|
||||||
// This widget is sensitive to both clicks and drags.
|
// This widget is sensitive to both clicks and drags.
|
||||||
// When the mouse first is pressed, it could be either,
|
// When the mouse first is pressed, it could be either,
|
||||||
|
|
@ -207,7 +208,6 @@ pub(crate) fn interact(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !input.pointer.could_any_button_be_click() {
|
if !input.pointer.could_any_button_be_click() {
|
||||||
interaction.potential_click_id = None;
|
interaction.potential_click_id = None;
|
||||||
|
|
|
||||||
|
|
@ -236,8 +236,9 @@ 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) {
|
if let Some(to_global) = to_global.get(layer_id) {
|
||||||
for clipped_shape in &mut list.0 {
|
for clipped_shape in &mut list.0 {
|
||||||
clipped_shape.transform(*to_global);
|
clipped_shape.transform(*to_global);
|
||||||
|
|
@ -246,7 +247,6 @@ impl GraphicLayers {
|
||||||
all_shapes.append(&mut list.0);
|
all_shapes.append(&mut list.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Also draw areas that are missing in `area_order`:
|
// Also draw areas that are missing in `area_order`:
|
||||||
// NOTE: We don't think we end up here in normal situations.
|
// NOTE: We don't think we end up here in normal situations.
|
||||||
|
|
|
||||||
|
|
@ -535,15 +535,14 @@ 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),
|
||||||
|
|
@ -561,11 +560,10 @@ impl Focus {
|
||||||
Some(FocusDirection::None)
|
Some(FocusDirection::None)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
} {
|
}
|
||||||
|
{
|
||||||
self.focus_direction = cardinality;
|
self.focus_direction = cardinality;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "accesskit")]
|
#[cfg(feature = "accesskit")]
|
||||||
{
|
{
|
||||||
|
|
@ -582,11 +580,11 @@ 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 {
|
||||||
// Allow calling `request_focus` one frame and not using it until next frame
|
// Allow calling `request_focus` one frame and not using it until next frame
|
||||||
|
|
@ -858,14 +856,14 @@ 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.id == id
|
||||||
|
{
|
||||||
focused.filter = event_filter;
|
focused.filter = event_filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Give keyboard focus to a specific widget.
|
/// Give keyboard focus to a specific widget.
|
||||||
/// See also [`crate::Response::request_focus`].
|
/// See also [`crate::Response::request_focus`].
|
||||||
|
|
@ -933,14 +931,14 @@ 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,12 +1045,12 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Open the popup and remember its position.
|
/// Open the popup and remember its position.
|
||||||
#[deprecated = "Use Popup with PopupAnchor::Position instead"]
|
#[deprecated = "Use Popup with PopupAnchor::Position instead"]
|
||||||
|
|
@ -1200,8 +1198,9 @@ 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();
|
let mut rect = state.rect();
|
||||||
if state.interactable {
|
if state.interactable {
|
||||||
if let Some(to_global) = layer_to_global.get(layer) {
|
if let Some(to_global) = layer_to_global.get(layer) {
|
||||||
|
|
@ -1214,7 +1213,6 @@ impl Areas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -420,19 +420,16 @@ 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()) {
|
|
||||||
if let Some(root) = root.inner.as_mut() {
|
|
||||||
if root.id == id {
|
|
||||||
// pressed somewhere while this menu is open
|
// pressed somewhere while this menu is open
|
||||||
let in_menu = root.menu_state.read().area_contains(pos);
|
let in_menu = root.menu_state.read().area_contains(pos);
|
||||||
if !in_menu {
|
if !in_menu {
|
||||||
return MenuResponse::Close;
|
return MenuResponse::Close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MenuResponse::Stay
|
MenuResponse::Stay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -728,22 +725,22 @@ 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;
|
let rect = sub_menu.read().rect;
|
||||||
return rect.intersects_ray(pos, pointer.direction().normalized());
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -316,10 +316,11 @@ 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 = global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size());
|
||||||
let galley_rect = galley_rect.intersect(ui.clip_rect());
|
let galley_rect = galley_rect.intersect(ui.clip_rect());
|
||||||
|
|
||||||
let is_in_same_column = galley_rect
|
let is_in_same_column = galley_rect
|
||||||
|
|
@ -387,7 +388,6 @@ impl LabelSelectionState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let has_primary = response.id == selection.primary.widget_id;
|
let has_primary = response.id == selection.primary.widget_id;
|
||||||
let has_secondary = response.id == selection.secondary.widget_id;
|
let has_secondary = response.id == selection.secondary.widget_id;
|
||||||
|
|
@ -511,8 +511,9 @@ 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 =
|
let cursor_at_pointer =
|
||||||
galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2());
|
galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2());
|
||||||
|
|
||||||
|
|
@ -521,17 +522,16 @@ impl LabelSelectionState {
|
||||||
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()) {
|
||||||
self.copy_text(galley_rect, galley, &cursor_range);
|
self.copy_text(galley_rect, galley, &cursor_range);
|
||||||
|
|
|
||||||
|
|
@ -705,75 +705,75 @@ 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());
|
self.title = Some(new_title.clone());
|
||||||
commands.push(ViewportCommand::Title(new_title));
|
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);
|
self.position = Some(new_position);
|
||||||
commands.push(ViewportCommand::OuterPosition(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);
|
self.inner_size = Some(new_inner_size);
|
||||||
commands.push(ViewportCommand::InnerSize(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);
|
self.min_inner_size = Some(new_min_inner_size);
|
||||||
commands.push(ViewportCommand::MinInnerSize(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);
|
self.max_inner_size = Some(new_max_inner_size);
|
||||||
commands.push(ViewportCommand::MaxInnerSize(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);
|
self.fullscreen = Some(new_fullscreen);
|
||||||
commands.push(ViewportCommand::Fullscreen(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);
|
self.maximized = Some(new_maximized);
|
||||||
commands.push(ViewportCommand::Maximized(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);
|
self.resizable = Some(new_resizable);
|
||||||
commands.push(ViewportCommand::Resizable(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);
|
self.transparent = Some(new_transparent);
|
||||||
commands.push(ViewportCommand::Transparent(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);
|
self.decorations = Some(new_decorations);
|
||||||
commands.push(ViewportCommand::Decorations(new_decorations));
|
commands.push(ViewportCommand::Decorations(new_decorations));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(new_icon) = new_icon {
|
if let Some(new_icon) = new_icon {
|
||||||
let is_new = match &self.icon {
|
let is_new = match &self.icon {
|
||||||
|
|
@ -787,26 +787,26 @@ 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);
|
self.visible = Some(new_visible);
|
||||||
commands.push(ViewportCommand::Visible(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);
|
self.mouse_passthrough = Some(new_mouse_passthrough);
|
||||||
commands.push(ViewportCommand::MousePassthrough(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);
|
self.window_level = Some(new_window_level);
|
||||||
commands.push(ViewportCommand::WindowLevel(new_window_level));
|
commands.push(ViewportCommand::WindowLevel(new_window_level));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
// Things we don't have commands for require a full window recreation.
|
// Things we don't have commands for require a full window recreation.
|
||||||
|
|
|
||||||
|
|
@ -573,8 +573,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
@ -609,7 +608,6 @@ impl TextEdit<'_> {
|
||||||
state.last_interaction_time = ui.ctx().input(|i| i.time);
|
state.last_interaction_time = ui.ctx().input(|i| i.time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if interactive && response.hovered() {
|
if interactive && response.hovered() {
|
||||||
ui.ctx().set_cursor_icon(CursorIcon::Text);
|
ui.ctx().set_cursor_icon(CursorIcon::Text);
|
||||||
|
|
@ -718,12 +716,10 @@ 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 {
|
||||||
// Allocate additional space if edits were made this frame that changed the size. This is important so that,
|
// Allocate additional space if edits were made this frame that changed the size. This is important so that,
|
||||||
|
|
@ -762,10 +758,8 @@ 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 =
|
|
||||||
cursor_rect(&galley, &cursor_range.primary, row_height)
|
|
||||||
.translate(galley_pos.to_vec2());
|
.translate(galley_pos.to_vec2());
|
||||||
|
|
||||||
if response.changed() || selection_changed {
|
if response.changed() || selection_changed {
|
||||||
|
|
@ -808,7 +802,6 @@ impl TextEdit<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures correct IME behavior when the text input area gains or loses focus.
|
// Ensures correct IME behavior when the text input area gains or loses focus.
|
||||||
if state.ime_enabled && (response.gained_focus() || response.lost_focus()) {
|
if state.ime_enabled && (response.gained_focus() || response.lost_focus()) {
|
||||||
|
|
|
||||||
|
|
@ -64,12 +64,12 @@ 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.uri_edit_text = format!("file://{}", path.display());
|
||||||
self.current_uri = self.uri_edit_text.clone();
|
self.current_uri = self.uri_edit_text.clone();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,11 +194,11 @@ 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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -421,11 +421,12 @@ 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
|
||||||
|
&& start.bytes().next().is_some_and(|byte| byte >= 128)
|
||||||
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
full_name
|
full_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,11 +67,10 @@ 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());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,12 @@ 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);
|
entry.entries.push(full);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.history.push_back(HistoryEntry {
|
self.history.push_back(HistoryEntry {
|
||||||
summary,
|
summary,
|
||||||
entries: vec![full],
|
entries: vec![full],
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ 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;
|
entry.repeated += 1;
|
||||||
return;
|
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 {
|
||||||
self.history.pop_front();
|
self.history.pop_front();
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,9 @@ 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 _;
|
use egui::TextBuffer as _;
|
||||||
let selected_chars = text_cursor_range.as_sorted_char_range();
|
let selected_chars = text_cursor_range.as_sorted_char_range();
|
||||||
let selected_text = text.char_range(selected_chars.clone());
|
let selected_text = text.char_range(selected_chars.clone());
|
||||||
|
|
@ -79,7 +80,6 @@ impl crate::View for TextEditDemo {
|
||||||
text.delete_char_range(selected_chars.clone());
|
text.delete_char_range(selected_chars.clone());
|
||||||
text.insert_text(&new_text, selected_chars.start);
|
text.insert_text(&new_text, selected_chars.start);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Move cursor to the:");
|
ui.label("Move cursor to the:");
|
||||||
|
|
|
||||||
|
|
@ -60,16 +60,12 @@ 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 && let Some(redo_text) = self.undoer.redo(&self.state) {
|
||||||
if redo {
|
|
||||||
if let Some(redo_text) = self.undoer.redo(&self.state) {
|
|
||||||
self.state = redo_text.clone();
|
self.state = redo_text.clone();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.undoer
|
self.undoer
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,9 @@ 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);
|
let any_change = shortcuts(ui, code, &mut ccursor_range);
|
||||||
if any_change {
|
if any_change {
|
||||||
state.cursor.set_char_range(Some(ccursor_range));
|
state.cursor.set_char_range(Some(ccursor_range));
|
||||||
|
|
@ -105,7 +106,6 @@ impl EasyMarkEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SHORTCUT_BOLD: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::B);
|
pub const SHORTCUT_BOLD: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::B);
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,9 @@ 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 language = &language_start[..newline];
|
||||||
let code_start = &language_start[newline + 1..];
|
let code_start = &language_start[newline + 1..];
|
||||||
if let Some(end) = code_start.find("\n```") {
|
if let Some(end) = code_start.find("\n```") {
|
||||||
|
|
@ -127,7 +128,6 @@ impl<'a> Parser<'a> {
|
||||||
return Some(Item::CodeBlock(language, code_start));
|
return Some(Item::CodeBlock(language, code_start));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,8 +171,9 @@ 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 parens_end = bracket_end + 2 + parens_end;
|
||||||
let url = &self.s[bracket_end + 2..parens_end];
|
let url = &self.s[bracket_end + 2..parens_end];
|
||||||
self.s = &self.s[parens_end + 1..];
|
self.s = &self.s[parens_end + 1..];
|
||||||
|
|
@ -181,7 +182,6 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -161,13 +161,13 @@ 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 {
|
return Err(LoadError::FormatNotSupported {
|
||||||
detected_format: Some(mime),
|
detected_format: Some(mime),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
load_image(ctx, uri, &self.cache, &bytes)
|
load_image(ctx, uri, &self.cache, &bytes)
|
||||||
}
|
}
|
||||||
Ok(BytesPoll::Pending { size }) => Ok(ImagePoll::Pending { size }),
|
Ok(BytesPoll::Pending { size }) => Ok(ImagePoll::Pending { size }),
|
||||||
|
|
|
||||||
|
|
@ -144,13 +144,13 @@ 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;
|
remainder_length -= range.min;
|
||||||
num_remainders -= 1;
|
num_remainders -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if num_remainders > 0 {
|
if num_remainders > 0 {
|
||||||
0.0f32.max(remainder_length / num_remainders as f32)
|
0.0f32.max(remainder_length / num_remainders as f32)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -472,12 +472,12 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let striped = striped.unwrap_or(ui.visuals().striped);
|
let striped = striped.unwrap_or(ui.visuals().striped);
|
||||||
|
|
||||||
|
|
@ -864,8 +864,9 @@ 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;
|
let mut new_width = *column_width + pointer.x - x;
|
||||||
if !column.clip {
|
if !column.clip {
|
||||||
// Unless we clip we don't want to shrink below the
|
// Unless we clip we don't want to shrink below the
|
||||||
|
|
@ -885,7 +886,6 @@ impl Table<'_> {
|
||||||
|
|
||||||
*column_width = new_width;
|
*column_width = new_width;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let dragging_something_else =
|
let dragging_something_else =
|
||||||
ui.input(|i| i.pointer.any_down() || i.pointer.any_pressed());
|
ui.input(|i| i.pointer.any_down() || i.pointer.any_pressed());
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -239,8 +239,9 @@ 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 {
|
let glyph_info = GlyphInfo {
|
||||||
advance_width_unscaled: (crate::text::TAB_SIZE as f32
|
advance_width_unscaled: (crate::text::TAB_SIZE as f32
|
||||||
* space.advance_width_unscaled.0)
|
* space.advance_width_unscaled.0)
|
||||||
|
|
@ -250,7 +251,6 @@ impl FontImpl {
|
||||||
self.glyph_info_cache.insert(c, glyph_info);
|
self.glyph_info_cache.insert(c, glyph_info);
|
||||||
return Some(glyph_info);
|
return Some(glyph_info);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if c == '\u{2009}' {
|
if c == '\u{2009}' {
|
||||||
// Thin space, often used as thousands deliminator: 1 234 567 890
|
// Thin space, often used as thousands deliminator: 1 234 567 890
|
||||||
|
|
|
||||||
|
|
@ -113,15 +113,13 @@ 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let justify = job.justify && job.wrap.max_width.is_finite();
|
let justify = job.justify && job.wrap.max_width.is_finite();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -957,16 +957,16 @@ 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() {
|
&& last_row.max_y() + VMARGIN < pos.y
|
||||||
if 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;
|
||||||
let mut cursor = CCursor::default();
|
let mut cursor = CCursor::default();
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,11 @@ 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 {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,9 @@ 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;
|
self.request_at = None;
|
||||||
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention));
|
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention));
|
||||||
if self.auto_reset {
|
if self.auto_reset {
|
||||||
|
|
@ -65,16 +66,15 @@ impl eframe::App for Application {
|
||||||
self.reset_at = Some(SystemTime::now() + Self::attention_reset_timeout());
|
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;
|
self.reset_at = None;
|
||||||
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(
|
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(
|
||||||
UserAttentionType::Reset,
|
UserAttentionType::Reset,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
CentralPanel::default().show(ctx, |ui| {
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue