use core::ptr;
use crate::{LogicalRect, LogicalSize, PopupDesc, PopupInput, ShellError, WindowId};
use super::ffi::{self, Id, NSRect, NSSize, Sel};
use super::geometry;
use super::shell::AppKitShell;
const ORDERED_ABOVE: ffi::NSInteger = 1;
impl AppKitShell {
pub(super) fn popup_frame_for(
&self,
popup: &PopupDesc,
size: NSSize,
) -> Result<NSRect, ShellError> {
let parent = self.window(popup.parent)?.window;
let content = unsafe {
let frame = ffi::msg_rect(parent, ffi::sel(c"frame"));
let content_of: unsafe extern "C" fn(Id, Sel, NSRect) -> NSRect = ffi::msg_send_stret();
content_of(parent, ffi::sel(c"contentRectForFrameRect:"), frame)
};
let anchor = popup.anchor;
let anchor = NSRect::new(
content.origin.x + anchor.origin.x,
content.max_y() - anchor.origin.y - anchor.size.height,
anchor.size.width,
anchor.size.height,
);
let visible = self
.screen_of(parent)
.and_then(|id| self.screens.iter().find(|screen| screen.id == id))
.or_else(|| self.screens.first())
.map_or(content, |screen| screen.visible);
Ok(geometry::popup_frame(
anchor,
size,
popup.placement,
visible,
))
}
pub(super) fn move_popup(
&mut self,
window: WindowId,
anchor: LogicalRect,
size: LogicalSize,
) -> Result<(), ShellError> {
let state = self.window(window)?;
let ns_window = state.window;
let mut popup = state
.popup
.ok_or_else(|| crate::role::not_a_popup(window))?;
popup.anchor = anchor;
let frame = self.popup_frame_for(&popup, geometry::points(size))?;
unsafe {
let set: unsafe extern "C" fn(Id, Sel, NSRect, ffi::ObjcBool) = ffi::msg_send();
set(ns_window, ffi::sel(c"setFrame:display:"), frame, ffi::YES);
}
let state = self.window_mut(window)?;
state.popup = Some(popup);
state.requested_size = size;
Ok(())
}
pub(super) unsafe fn configure_popup(window: Id, input: PopupInput) {
unsafe {
ffi::msg_set_bool(window, ffi::sel(c"setHidesOnDeactivate:"), false);
ffi::msg_set_bool(
window,
ffi::sel(c"setIgnoresMouseEvents:"),
input == PopupInput::Passthrough,
);
}
}
pub(super) unsafe fn show_popup(parent: Id, window: Id, input: PopupInput) {
unsafe {
if input == PopupInput::Grab {
ffi::msg1_void(window, ffi::sel(c"makeKeyAndOrderFront:"), ptr::null_mut());
} else {
ffi::msg_void(window, ffi::sel(c"orderFrontRegardless"));
}
let add: unsafe extern "C" fn(Id, Sel, Id, ffi::NSInteger) = ffi::msg_send();
add(
parent,
ffi::sel(c"addChildWindow:ordered:"),
window,
ORDERED_ABOVE,
);
}
}
}