use core::ptr::NonNull;
use std::ffi::{CString, c_void};
use crate::converters::Converter;
use crate::ffi::{
noesis_base_component_release, noesis_binding_create, noesis_binding_destroy,
noesis_binding_set_converter, noesis_binding_set_converter_parameter,
noesis_binding_set_element_name, noesis_binding_set_fallback_value, noesis_binding_set_mode,
noesis_binding_set_relative_source_find_ancestor,
noesis_binding_set_relative_source_previous_data, noesis_binding_set_relative_source_self,
noesis_binding_set_relative_source_templated_parent, noesis_binding_set_source,
noesis_binding_set_string_format, noesis_binding_set_update_source_trigger, noesis_box_bool,
noesis_box_double, noesis_box_float, noesis_box_int32, noesis_box_string, noesis_clear_binding,
noesis_framework_element_add_resource, noesis_observable_collection_add,
noesis_observable_collection_clear, noesis_observable_collection_count,
noesis_observable_collection_create, noesis_observable_collection_get,
noesis_observable_collection_insert, noesis_observable_collection_move,
noesis_observable_collection_remove_at, noesis_observable_collection_set, noesis_set_binding,
};
use crate::view::FrameworkElement;
#[must_use]
pub fn box_string(value: &str) -> Boxed {
let c = CString::new(value).expect("boxed string contained interior NUL");
let ptr = unsafe { noesis_box_string(c.as_ptr()) };
Boxed {
ptr: NonNull::new(ptr).expect("noesis_box_string returned null"),
}
}
pub struct Boxed {
ptr: NonNull<c_void>,
}
unsafe impl Send for Boxed {}
impl Boxed {
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Drop for Boxed {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
pub struct ObservableCollection {
ptr: NonNull<c_void>,
}
unsafe impl Send for ObservableCollection {}
impl Default for ObservableCollection {
fn default() -> Self {
Self::new()
}
}
impl ObservableCollection {
#[must_use]
pub fn new() -> Self {
let ptr = unsafe { noesis_observable_collection_create() };
Self {
ptr: NonNull::new(ptr).expect("noesis_observable_collection_create returned null"),
}
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
#[must_use]
pub fn len(&self) -> usize {
let n = unsafe { noesis_observable_collection_count(self.ptr.as_ptr()) };
n.max(0) as usize
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn push_string(&mut self, value: &str) -> Option<usize> {
let boxed = box_string(value);
unsafe { self.push_component(boxed.raw()) }
}
pub fn push_bool(&mut self, value: bool) -> Option<usize> {
let boxed = box_bool(value);
unsafe { self.push_component(boxed.raw()) }
}
pub fn push_i32(&mut self, value: i32) -> Option<usize> {
let boxed = box_i32(value);
unsafe { self.push_component(boxed.raw()) }
}
pub fn push_f64(&mut self, value: f64) -> Option<usize> {
let boxed = box_f64(value);
unsafe { self.push_component(boxed.raw()) }
}
pub fn push_object(&mut self, instance: &crate::classes::ClassInstance) -> Option<usize> {
unsafe { self.push_component(instance.raw()) }
}
pub fn insert_object(
&mut self,
index: usize,
instance: &crate::classes::ClassInstance,
) -> bool {
unsafe { self.insert_component(index, instance.raw()) }
}
pub unsafe fn push_component(&mut self, item: *mut c_void) -> Option<usize> {
let idx = unsafe { noesis_observable_collection_add(self.ptr.as_ptr(), item) };
(idx >= 0).then_some(idx as usize)
}
pub unsafe fn insert_component(&mut self, index: usize, item: *mut c_void) -> bool {
unsafe { noesis_observable_collection_insert(self.ptr.as_ptr(), index as u32, item) }
}
pub unsafe fn set_component(&mut self, index: usize, item: *mut c_void) -> bool {
unsafe { noesis_observable_collection_set(self.ptr.as_ptr(), index as u32, item) }
}
pub fn remove_at(&mut self, index: usize) -> bool {
unsafe { noesis_observable_collection_remove_at(self.ptr.as_ptr(), index as u32) }
}
pub fn move_item(&mut self, old_index: usize, new_index: usize) -> bool {
unsafe {
noesis_observable_collection_move(self.ptr.as_ptr(), old_index as u32, new_index as u32)
}
}
pub fn clear(&mut self) {
unsafe { noesis_observable_collection_clear(self.ptr.as_ptr()) }
}
#[must_use]
pub fn get(&self, index: usize) -> Option<NonNull<c_void>> {
let p = unsafe { noesis_observable_collection_get(self.ptr.as_ptr(), index as u32) };
NonNull::new(p)
}
}
impl Drop for ObservableCollection {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
#[must_use]
pub fn box_bool(value: bool) -> Boxed {
let ptr = unsafe { noesis_box_bool(value) };
Boxed {
ptr: NonNull::new(ptr).expect("noesis_box_bool returned null"),
}
}
#[must_use]
pub fn box_i32(value: i32) -> Boxed {
let ptr = unsafe { noesis_box_int32(value) };
Boxed {
ptr: NonNull::new(ptr).expect("noesis_box_int32 returned null"),
}
}
#[must_use]
pub fn box_f64(value: f64) -> Boxed {
let ptr = unsafe { noesis_box_double(value) };
Boxed {
ptr: NonNull::new(ptr).expect("noesis_box_double returned null"),
}
}
#[must_use]
pub fn box_f32(value: f32) -> Boxed {
let ptr = unsafe { noesis_box_float(value) };
Boxed {
ptr: NonNull::new(ptr).expect("noesis_box_float returned null"),
}
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum BindingMode {
Default = 0,
TwoWay = 1,
OneWay = 2,
OneTime = 3,
OneWayToSource = 4,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum UpdateSourceTrigger {
Default = 0,
PropertyChanged = 1,
LostFocus = 2,
Explicit = 3,
}
pub struct Binding {
ptr: NonNull<c_void>,
}
unsafe impl Send for Binding {}
impl Binding {
#[must_use]
pub fn new(path: &str) -> Self {
let c = CString::new(path).expect("binding path contained interior NUL");
let ptr = unsafe { noesis_binding_create(c.as_ptr()) };
Self {
ptr: NonNull::new(ptr).expect("noesis_binding_create returned null"),
}
}
#[must_use]
pub fn whole() -> Self {
let ptr = unsafe { noesis_binding_create(core::ptr::null()) };
Self {
ptr: NonNull::new(ptr).expect("noesis_binding_create returned null"),
}
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
#[must_use]
pub fn mode(self, mode: BindingMode) -> Self {
unsafe { noesis_binding_set_mode(self.ptr.as_ptr(), mode as i32) };
self
}
#[must_use]
pub fn update_source_trigger(self, trigger: UpdateSourceTrigger) -> Self {
unsafe { noesis_binding_set_update_source_trigger(self.ptr.as_ptr(), trigger as i32) };
self
}
#[must_use]
pub fn converter(self, converter: &Converter) -> Self {
unsafe { noesis_binding_set_converter(self.ptr.as_ptr(), converter.raw()) };
self
}
#[must_use]
pub fn converter_parameter(self, parameter: &Boxed) -> Self {
unsafe { noesis_binding_set_converter_parameter(self.ptr.as_ptr(), parameter.raw()) };
self
}
#[must_use]
pub fn string_format(self, format: &str) -> Self {
let c = CString::new(format).expect("string format contained interior NUL");
unsafe { noesis_binding_set_string_format(self.ptr.as_ptr(), c.as_ptr()) };
self
}
#[must_use]
pub fn fallback_value(self, value: &Boxed) -> Self {
unsafe { noesis_binding_set_fallback_value(self.ptr.as_ptr(), value.raw()) };
self
}
#[must_use]
pub fn element_name(self, name: &str) -> Self {
let c = CString::new(name).expect("element name contained interior NUL");
unsafe { noesis_binding_set_element_name(self.ptr.as_ptr(), c.as_ptr()) };
self
}
#[must_use]
pub fn relative_source_self(self) -> Self {
unsafe { noesis_binding_set_relative_source_self(self.ptr.as_ptr()) };
self
}
#[must_use]
pub fn relative_source_find_ancestor(self, type_name: &str, level: u32) -> Self {
let _ = self.set_relative_source_find_ancestor(type_name, level);
self
}
pub fn try_relative_source_find_ancestor(&self, type_name: &str, level: u32) -> bool {
self.set_relative_source_find_ancestor(type_name, level)
}
fn set_relative_source_find_ancestor(&self, type_name: &str, level: u32) -> bool {
let Ok(c) = CString::new(type_name) else {
return false;
};
unsafe {
noesis_binding_set_relative_source_find_ancestor(self.ptr.as_ptr(), c.as_ptr(), level)
}
}
#[must_use]
pub fn relative_source_previous_data(self) -> Self {
unsafe { noesis_binding_set_relative_source_previous_data(self.ptr.as_ptr()) };
self
}
#[must_use]
pub fn relative_source_templated_parent(self) -> Self {
unsafe { noesis_binding_set_relative_source_templated_parent(self.ptr.as_ptr()) };
self
}
#[must_use]
pub unsafe fn source(self, source: *mut c_void) -> Self {
unsafe { noesis_binding_set_source(self.ptr.as_ptr(), source) };
self
}
}
impl Drop for Binding {
fn drop(&mut self) {
unsafe { noesis_binding_destroy(self.ptr.as_ptr()) }
}
}
#[must_use]
pub fn set_binding(element: &FrameworkElement, dp_name: &str, binding: &Binding) -> bool {
let c = CString::new(dp_name).expect("dp name contained interior NUL");
unsafe { noesis_set_binding(element.raw(), c.as_ptr(), binding.raw()) }
}
#[must_use]
pub fn clear_binding(element: &FrameworkElement, dp_name: &str) -> bool {
let c = CString::new(dp_name).expect("dp name contained interior NUL");
unsafe { noesis_clear_binding(element.raw(), c.as_ptr()) }
}
#[must_use]
pub unsafe fn add_resource(element: &FrameworkElement, key: &str, object: *mut c_void) -> bool {
let c = CString::new(key).expect("resource key contained interior NUL");
unsafe { noesis_framework_element_add_resource(element.raw(), c.as_ptr(), object) }
}