use core::ptr::NonNull;
use std::ffi::c_void;
use crate::commands::AsCommand;
use crate::ffi::{
noesis_base_component_release, noesis_focus_manager_get_focus_scope,
noesis_focus_manager_get_focused_element, noesis_focus_manager_get_is_focus_scope,
noesis_focus_manager_set_focused_element, noesis_focus_manager_set_is_focus_scope,
noesis_input_binding_create, noesis_key_binding_create, noesis_key_gesture_create,
noesis_keyboard_navigation_get_accepts_return,
noesis_keyboard_navigation_get_control_tab_navigation,
noesis_keyboard_navigation_get_directional_navigation,
noesis_keyboard_navigation_get_is_tab_stop, noesis_keyboard_navigation_get_tab_index,
noesis_keyboard_navigation_get_tab_navigation, noesis_keyboard_navigation_set_accepts_return,
noesis_keyboard_navigation_set_control_tab_navigation,
noesis_keyboard_navigation_set_directional_navigation,
noesis_keyboard_navigation_set_is_tab_stop, noesis_keyboard_navigation_set_tab_index,
noesis_keyboard_navigation_set_tab_navigation, noesis_mouse_binding_create,
noesis_mouse_gesture_create, noesis_ui_element_add_input_binding,
noesis_ui_element_remove_input_binding,
};
use crate::view::{FrameworkElement, Key};
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct ModifierKeys(pub i32);
impl ModifierKeys {
pub const NONE: Self = Self(0);
pub const ALT: Self = Self(1);
pub const CONTROL: Self = Self(2);
pub const SHIFT: Self = Self(4);
pub const WINDOWS: Self = Self(8);
#[must_use]
pub const fn from_bits(bits: i32) -> Self {
Self(bits)
}
#[must_use]
pub const fn bits(self) -> i32 {
self.0
}
#[must_use]
pub const fn with(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[must_use]
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
}
impl core::ops::BitOr for ModifierKeys {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
impl FromIterator<ModifierKeys> for ModifierKeys {
fn from_iter<I: IntoIterator<Item = ModifierKeys>>(iter: I) -> Self {
let mut acc = 0;
for m in iter {
acc |= m.0;
}
Self(acc)
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct KeyStates(pub i32);
impl KeyStates {
pub const NONE: Self = Self(0);
pub const DOWN: Self = Self(1);
pub const TOGGLED: Self = Self(2);
#[must_use]
pub const fn from_bits(bits: i32) -> Self {
Self(bits)
}
#[must_use]
pub const fn bits(self) -> i32 {
self.0
}
#[must_use]
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum MouseAction {
None = 0,
LeftClick = 1,
RightClick = 2,
MiddleClick = 3,
WheelClick = 4,
LeftDoubleClick = 5,
RightDoubleClick = 6,
MiddleDoubleClick = 7,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum CaptureMode {
None = 0,
Element = 1,
SubTree = 2,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum FocusNavigationDirection {
Next = 0,
Previous = 1,
First = 2,
Last = 3,
Left = 4,
Right = 5,
Up = 6,
Down = 7,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum KeyboardNavigationMode {
Continue = 0,
Once = 1,
Cycle = 2,
None = 3,
Contained = 4,
Local = 5,
}
pub struct KeyGesture {
ptr: NonNull<c_void>,
}
unsafe impl Send for KeyGesture {}
impl KeyGesture {
#[must_use]
pub fn new(key: Key, modifiers: ModifierKeys) -> Self {
let ptr = unsafe { noesis_key_gesture_create(key as i32, modifiers.bits()) };
Self {
ptr: NonNull::new(ptr).expect("noesis_key_gesture_create returned null"),
}
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Drop for KeyGesture {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
pub struct MouseGesture {
ptr: NonNull<c_void>,
}
unsafe impl Send for MouseGesture {}
impl MouseGesture {
#[must_use]
pub fn new(action: MouseAction, modifiers: ModifierKeys) -> Self {
let ptr = unsafe { noesis_mouse_gesture_create(action as i32, modifiers.bits()) };
Self {
ptr: NonNull::new(ptr).expect("noesis_mouse_gesture_create returned null"),
}
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Drop for MouseGesture {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
pub struct KeyBinding {
ptr: NonNull<c_void>,
}
unsafe impl Send for KeyBinding {}
impl KeyBinding {
#[must_use]
pub fn new<C: AsCommand>(command: &C, key: Key, modifiers: ModifierKeys) -> Option<Self> {
let ptr = unsafe {
noesis_key_binding_create(command.command_ptr(), key as i32, modifiers.bits())
};
NonNull::new(ptr).map(|ptr| Self { ptr })
}
pub fn add_to(&self, element: &FrameworkElement) -> bool {
unsafe { noesis_ui_element_add_input_binding(element.raw(), self.ptr.as_ptr()) }
}
pub fn remove_from(&self, element: &FrameworkElement) -> bool {
unsafe { noesis_ui_element_remove_input_binding(element.raw(), self.ptr.as_ptr()) }
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Drop for KeyBinding {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
pub struct MouseBinding {
ptr: NonNull<c_void>,
}
unsafe impl Send for MouseBinding {}
impl MouseBinding {
#[must_use]
pub fn new<C: AsCommand>(
command: &C,
action: MouseAction,
modifiers: ModifierKeys,
) -> Option<Self> {
let ptr = unsafe {
noesis_mouse_binding_create(command.command_ptr(), action as i32, modifiers.bits())
};
NonNull::new(ptr).map(|ptr| Self { ptr })
}
pub fn add_to(&self, element: &FrameworkElement) -> bool {
unsafe { noesis_ui_element_add_input_binding(element.raw(), self.ptr.as_ptr()) }
}
pub fn remove_from(&self, element: &FrameworkElement) -> bool {
unsafe { noesis_ui_element_remove_input_binding(element.raw(), self.ptr.as_ptr()) }
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Drop for MouseBinding {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
pub struct InputBinding {
ptr: NonNull<c_void>,
}
unsafe impl Send for InputBinding {}
impl InputBinding {
#[must_use]
pub fn with_gesture<C: AsCommand>(command: &C, gesture: &KeyGesture) -> Option<Self> {
let ptr = unsafe { noesis_input_binding_create(command.command_ptr(), gesture.raw()) };
NonNull::new(ptr).map(|ptr| Self { ptr })
}
#[must_use]
pub fn with_mouse_gesture<C: AsCommand>(command: &C, gesture: &MouseGesture) -> Option<Self> {
let ptr = unsafe { noesis_input_binding_create(command.command_ptr(), gesture.raw()) };
NonNull::new(ptr).map(|ptr| Self { ptr })
}
pub fn add_to(&self, element: &FrameworkElement) -> bool {
unsafe { noesis_ui_element_add_input_binding(element.raw(), self.ptr.as_ptr()) }
}
pub fn remove_from(&self, element: &FrameworkElement) -> bool {
unsafe { noesis_ui_element_remove_input_binding(element.raw(), self.ptr.as_ptr()) }
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Drop for InputBinding {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
pub struct FocusManager;
impl FocusManager {
#[must_use]
pub fn focused_element(scope: &FrameworkElement) -> Option<NonNull<c_void>> {
let p = unsafe { noesis_focus_manager_get_focused_element(scope.raw()) };
NonNull::new(p)
}
#[must_use = "a false return means focus was not set (element is not a UIElement / DependencyObject)"]
pub fn set_focused_element(
scope: &FrameworkElement,
element: Option<&FrameworkElement>,
) -> bool {
let e = element.map_or(core::ptr::null_mut(), FrameworkElement::raw);
unsafe { noesis_focus_manager_set_focused_element(scope.raw(), e) }
}
#[must_use]
pub fn is_focus_scope(element: &FrameworkElement) -> bool {
unsafe { noesis_focus_manager_get_is_focus_scope(element.raw()) }
}
#[must_use = "a false return means the property was not set (unknown name / type mismatch / read-only)"]
pub fn set_is_focus_scope(element: &FrameworkElement, value: bool) -> bool {
unsafe { noesis_focus_manager_set_is_focus_scope(element.raw(), value) }
}
#[must_use]
pub fn focus_scope(element: &FrameworkElement) -> Option<NonNull<c_void>> {
let p = unsafe { noesis_focus_manager_get_focus_scope(element.raw()) };
NonNull::new(p)
}
}
pub struct KeyboardNavigation;
impl KeyboardNavigation {
#[must_use]
pub fn tab_index(element: &FrameworkElement) -> Option<i32> {
let mut out = 0;
unsafe { noesis_keyboard_navigation_get_tab_index(element.raw(), &mut out) }.then_some(out)
}
#[must_use = "a false return means the property was not set (unknown name / type mismatch / read-only)"]
pub fn set_tab_index(element: &FrameworkElement, value: i32) -> bool {
unsafe { noesis_keyboard_navigation_set_tab_index(element.raw(), value) }
}
#[must_use]
pub fn is_tab_stop(element: &FrameworkElement) -> Option<bool> {
let mut out = false;
unsafe { noesis_keyboard_navigation_get_is_tab_stop(element.raw(), &mut out) }
.then_some(out)
}
#[must_use = "a false return means the property was not set (unknown name / type mismatch / read-only)"]
pub fn set_is_tab_stop(element: &FrameworkElement, value: bool) -> bool {
unsafe { noesis_keyboard_navigation_set_is_tab_stop(element.raw(), value) }
}
#[must_use]
pub fn tab_navigation(element: &FrameworkElement) -> Option<KeyboardNavigationMode> {
Self::get_mode(element, noesis_keyboard_navigation_get_tab_navigation)
}
#[must_use = "a false return means the property was not set (unknown name / type mismatch / read-only)"]
pub fn set_tab_navigation(element: &FrameworkElement, mode: KeyboardNavigationMode) -> bool {
unsafe { noesis_keyboard_navigation_set_tab_navigation(element.raw(), mode as i32) }
}
#[must_use]
pub fn control_tab_navigation(element: &FrameworkElement) -> Option<KeyboardNavigationMode> {
Self::get_mode(
element,
noesis_keyboard_navigation_get_control_tab_navigation,
)
}
#[must_use = "a false return means the property was not set (unknown name / type mismatch / read-only)"]
pub fn set_control_tab_navigation(
element: &FrameworkElement,
mode: KeyboardNavigationMode,
) -> bool {
unsafe { noesis_keyboard_navigation_set_control_tab_navigation(element.raw(), mode as i32) }
}
#[must_use]
pub fn directional_navigation(element: &FrameworkElement) -> Option<KeyboardNavigationMode> {
Self::get_mode(
element,
noesis_keyboard_navigation_get_directional_navigation,
)
}
#[must_use = "a false return means the property was not set (unknown name / type mismatch / read-only)"]
pub fn set_directional_navigation(
element: &FrameworkElement,
mode: KeyboardNavigationMode,
) -> bool {
unsafe { noesis_keyboard_navigation_set_directional_navigation(element.raw(), mode as i32) }
}
#[must_use]
pub fn accepts_return(element: &FrameworkElement) -> Option<bool> {
let mut out = false;
unsafe { noesis_keyboard_navigation_get_accepts_return(element.raw(), &mut out) }
.then_some(out)
}
#[must_use = "a false return means the property was not set (unknown name / type mismatch / read-only)"]
pub fn set_accepts_return(element: &FrameworkElement, value: bool) -> bool {
unsafe { noesis_keyboard_navigation_set_accepts_return(element.raw(), value) }
}
fn get_mode(
element: &FrameworkElement,
getter: unsafe extern "C" fn(*mut c_void, *mut i32) -> bool,
) -> Option<KeyboardNavigationMode> {
let mut out = 0;
if !unsafe { getter(element.raw(), &mut out) } {
return None;
}
Some(match out {
0 => KeyboardNavigationMode::Continue,
1 => KeyboardNavigationMode::Once,
2 => KeyboardNavigationMode::Cycle,
3 => KeyboardNavigationMode::None,
4 => KeyboardNavigationMode::Contained,
5 => KeyboardNavigationMode::Local,
_ => return None,
})
}
}