mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 05:10:03 -04:00
This PR is a continuation of #4915 by @frederik-uni and @lucasmerlin that introduces support for keeping egui content within the 'safe area' on iOS (avoiding the notch / dynamic island / menu bar etc.), with the following changes: - `SafeArea` now wraps `MarginF32` and has been renamed to `SafeAreaInsets` to clarify its purpose. - `InputState::screen_rect` is now marked as deprecated in favour of either `viewport_rect` (which contains the entire screen), or `content_rect` (which is the viewport rect with the safe area insets removed). - I added some comments to the safe area insets logic pointing out the [safe area API coming in winit v0.31](https://github.com/rust-windowing/winit/issues/3910). --------- Co-authored-by: frederik-uni <147479464+frederik-uni@users.noreply.github.com> Co-authored-by: Lucas Meurer <hi@lucasmerlin.me> Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
57 lines
2.3 KiB
Rust
57 lines
2.3 KiB
Rust
#[cfg(target_os = "ios")]
|
||
pub use ios::get_safe_area_insets;
|
||
|
||
#[cfg(target_os = "ios")]
|
||
mod ios {
|
||
use egui::{SafeAreaInsets, epaint::MarginF32};
|
||
use objc2::{ClassType, rc::Retained};
|
||
use objc2_foundation::{MainThreadMarker, NSObjectProtocol};
|
||
use objc2_ui_kit::{UIApplication, UISceneActivationState, UIWindowScene};
|
||
|
||
/// Gets the ios safe area insets.
|
||
///
|
||
/// A safe area defines the area within a view that isn’t covered by a navigation bar, tab bar,
|
||
/// toolbar, or other views a window might provide. Safe areas are essential for avoiding a
|
||
/// device’s interactive and display features, like Dynamic Island on iPhone or the camera
|
||
/// housing on some Mac models.
|
||
///
|
||
/// Once winit v0.31 has been released this can be removed in favor of
|
||
/// `winit::Window::safe_area`.
|
||
pub fn get_safe_area_insets() -> SafeAreaInsets {
|
||
let Some(main_thread_marker) = MainThreadMarker::new() else {
|
||
log::error!("Getting safe area insets needs to be performed on the main thread");
|
||
return SafeAreaInsets::default();
|
||
};
|
||
|
||
let app = UIApplication::sharedApplication(main_thread_marker);
|
||
|
||
#[allow(unsafe_code)]
|
||
unsafe {
|
||
// Look for the first window scene that's in the foreground
|
||
for scene in app.connectedScenes() {
|
||
if scene.isKindOfClass(UIWindowScene::class())
|
||
&& matches!(
|
||
scene.activationState(),
|
||
UISceneActivationState::ForegroundActive
|
||
| UISceneActivationState::ForegroundInactive
|
||
)
|
||
{
|
||
// Safe to cast, the class kind was checked above
|
||
let window_scene = Retained::cast::<UIWindowScene>(scene.clone());
|
||
if let Some(window) = window_scene.keyWindow() {
|
||
let insets = window.safeAreaInsets();
|
||
return SafeAreaInsets(MarginF32 {
|
||
top: insets.top as f32,
|
||
left: insets.left as f32,
|
||
right: insets.right as f32,
|
||
bottom: insets.bottom as f32,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
SafeAreaInsets::default()
|
||
}
|
||
}
|