use core::ptr::NonNull;
use std::ffi::c_void;
use crate::ffi::{
noesis_base_component_add_reference, noesis_base_component_release,
noesis_definition_collection_add, noesis_definition_collection_clear,
noesis_definition_collection_count, noesis_definition_collection_get,
noesis_definition_collection_insert, noesis_definition_collection_remove_at,
noesis_grid_column_definition_create, noesis_grid_column_definition_get_width,
noesis_grid_column_definition_set_width, noesis_grid_get_column_definitions,
noesis_grid_get_row_definitions, noesis_grid_row_definition_create,
noesis_grid_row_definition_get_height, noesis_grid_row_definition_set_height,
noesis_panel_children_add, noesis_panel_children_clear, noesis_panel_children_count,
noesis_panel_children_get, noesis_panel_children_get_at, noesis_panel_children_insert,
noesis_panel_children_remove_at,
};
use crate::view::FrameworkElement;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(i32)]
#[non_exhaustive]
pub enum GridUnitType {
Auto = 0,
Pixel = 1,
Star = 2,
}
impl GridUnitType {
fn from_raw(v: i32) -> Option<Self> {
match v {
0 => Some(Self::Auto),
1 => Some(Self::Pixel),
2 => Some(Self::Star),
_ => None,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct GridLength {
pub value: f32,
pub unit: GridUnitType,
}
impl GridLength {
#[must_use]
pub const fn pixels(value: f32) -> Self {
Self {
value,
unit: GridUnitType::Pixel,
}
}
#[must_use]
pub const fn auto() -> Self {
Self {
value: 0.0,
unit: GridUnitType::Auto,
}
}
#[must_use]
pub const fn star(weight: f32) -> Self {
Self {
value: weight,
unit: GridUnitType::Star,
}
}
}
pub trait GridDefinition {
fn definition_raw(&self) -> *mut c_void;
}
macro_rules! definition_handle {
($(#[$meta:meta])* $name:ident, $create:ident, $set:ident, $get:ident, $lendoc:literal) => {
$(#[$meta])*
pub struct $name {
ptr: NonNull<c_void>,
}
unsafe impl Send for $name {}
impl $name {
#[must_use]
pub fn new() -> Self {
let ptr = unsafe { $create() };
Self {
ptr: NonNull::new(ptr)
.unwrap_or_else(|| panic!(concat!(stringify!($create), " returned null"))),
}
}
#[doc = $lendoc]
#[must_use = "a false return means the length was not set"]
pub fn set_length(&mut self, length: GridLength) -> bool {
unsafe { $set(self.ptr.as_ptr(), length.value, length.unit as i32) }
}
#[must_use]
pub fn length(&self) -> Option<GridLength> {
let mut value = 0.0_f32;
let mut unit = -1_i32;
let ok = unsafe { $get(self.ptr.as_ptr(), &mut value, &mut unit) };
if !ok {
return None;
}
GridUnitType::from_raw(unit).map(|unit| GridLength { value, unit })
}
#[must_use]
pub fn raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl GridDefinition for $name {
fn definition_raw(&self) -> *mut c_void {
self.ptr.as_ptr()
}
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
impl Drop for $name {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
};
}
definition_handle!(
RowDefinition,
noesis_grid_row_definition_create,
noesis_grid_row_definition_set_height,
noesis_grid_row_definition_get_height,
"Set the row's `Height`."
);
definition_handle!(
ColumnDefinition,
noesis_grid_column_definition_create,
noesis_grid_column_definition_set_width,
noesis_grid_column_definition_get_width,
"Set the column's `Width`."
);
pub struct PanelChildren {
ptr: NonNull<c_void>,
}
unsafe impl Send for PanelChildren {}
impl PanelChildren {
pub fn add(&mut self, child: &FrameworkElement) -> Option<usize> {
let idx = unsafe { noesis_panel_children_add(self.ptr.as_ptr(), child.raw()) };
(idx >= 0).then_some(idx as usize)
}
#[must_use = "a false return means the child was not inserted"]
pub fn insert(&mut self, index: usize, child: &FrameworkElement) -> bool {
unsafe { noesis_panel_children_insert(self.ptr.as_ptr(), index as u32, child.raw()) }
}
#[must_use = "a false return means nothing was removed"]
pub fn remove_at(&mut self, index: usize) -> bool {
unsafe { noesis_panel_children_remove_at(self.ptr.as_ptr(), index as u32) }
}
#[must_use = "a false return means this is not a panel children collection"]
pub fn clear(&mut self) -> bool {
unsafe { noesis_panel_children_clear(self.ptr.as_ptr()) }
}
#[must_use]
pub fn count(&self) -> usize {
let n = unsafe { noesis_panel_children_count(self.ptr.as_ptr()) };
n.max(0) as usize
}
#[must_use]
pub fn get(&self, index: usize) -> Option<FrameworkElement> {
let borrowed = NonNull::new(self.get_raw(index))?;
let owned = unsafe { noesis_base_component_add_reference(borrowed.as_ptr()) };
NonNull::new(owned).map(|ptr| unsafe { FrameworkElement::from_owned(ptr) })
}
#[must_use]
pub fn get_raw(&self, index: usize) -> *mut c_void {
unsafe { noesis_panel_children_get_at(self.ptr.as_ptr(), index as u32) }
}
}
impl Drop for PanelChildren {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
pub struct DefinitionCollection {
ptr: NonNull<c_void>,
}
unsafe impl Send for DefinitionCollection {}
impl DefinitionCollection {
pub fn add<D: GridDefinition>(&mut self, definition: &D) -> Option<usize> {
let idx = unsafe {
noesis_definition_collection_add(self.ptr.as_ptr(), definition.definition_raw())
};
(idx >= 0).then_some(idx as usize)
}
#[must_use = "a false return means the definition was not inserted"]
pub fn insert<D: GridDefinition>(&mut self, index: usize, definition: &D) -> bool {
unsafe {
noesis_definition_collection_insert(
self.ptr.as_ptr(),
index as u32,
definition.definition_raw(),
)
}
}
#[must_use = "a false return means nothing was removed"]
pub fn remove_at(&mut self, index: usize) -> bool {
unsafe { noesis_definition_collection_remove_at(self.ptr.as_ptr(), index as u32) }
}
#[must_use = "a false return means this is not a definition collection"]
pub fn clear(&mut self) -> bool {
unsafe { noesis_definition_collection_clear(self.ptr.as_ptr()) }
}
#[must_use]
pub fn count(&self) -> usize {
let n = unsafe { noesis_definition_collection_count(self.ptr.as_ptr()) };
n.max(0) as usize
}
#[must_use]
pub fn get_raw(&self, index: usize) -> *mut c_void {
unsafe { noesis_definition_collection_get(self.ptr.as_ptr(), index as u32) }
}
}
impl Drop for DefinitionCollection {
fn drop(&mut self) {
unsafe { noesis_base_component_release(self.ptr.as_ptr()) }
}
}
impl FrameworkElement {
#[must_use = "a false return means the child was not added (not a Panel / not a UIElement)"]
pub fn add_child(&mut self, child: &FrameworkElement) -> bool {
panel_children(self).is_some_and(|mut children| children.add(child).is_some())
}
}
#[must_use]
pub fn panel_children(element: &FrameworkElement) -> Option<PanelChildren> {
let ptr = unsafe { noesis_panel_children_get(element.raw()) };
NonNull::new(ptr).map(|ptr| PanelChildren { ptr })
}
#[must_use]
pub fn row_definitions(element: &FrameworkElement) -> Option<DefinitionCollection> {
let ptr = unsafe { noesis_grid_get_row_definitions(element.raw()) };
NonNull::new(ptr).map(|ptr| DefinitionCollection { ptr })
}
#[must_use]
pub fn column_definitions(element: &FrameworkElement) -> Option<DefinitionCollection> {
let ptr = unsafe { noesis_grid_get_column_definitions(element.raw()) };
NonNull::new(ptr).map(|ptr| DefinitionCollection { ptr })
}