#![allow(dead_code)]
+use crate::ui::ffi::{UiObject, UiListArgs, UiCallback, UiList};
+use crate::ui::{ffi, toolkit};
+use std::ffi::{c_char, c_int, c_void};
+use std::ffi::CString;
+use std::marker::PhantomData;
+use crate::ui::widget::{widget_typed_fn};
+
+pub enum ListValue<'a> {
+ None,
+ Str(&'a str),
+ String(String)
+}
+
+pub struct ListBuilder<'a, T, E> {
+ args: *mut UiListArgs,
+ obj: &'a mut toolkit::UiObject<T>,
+ create: ListBuilderCreate,
+ has_getvalue_func: bool,
+ _marker: PhantomData<E>
+}
+
+pub type ListBuilderCreate = fn(*const UiObject, *const UiListArgs);
+
+impl<T> toolkit::UiObject<T> {
+ widget_typed_fn!(listview, listview_builder, ListBuilder);
+ pub fn listview_builder<'a, E>(&'a mut self) -> ListBuilder<'a, T, E> {
+ unsafe {
+ let args = ui_list_args_new();
+ ListBuilder { args: args, obj: self, create: list_create, has_getvalue_func: false, _marker: PhantomData }
+ }
+ }
+}
+
+fn list_create(obj: *const UiObject, args: *const UiListArgs) {
+ unsafe {
+ ui_listview_create(obj, args);
+ }
+}
+
+impl<'a, T, E> Drop for ListBuilder<'a, T, E> {
+ fn drop(&mut self) {
+ unsafe {
+ ui_list_args_free(self.args);
+ }
+ }
+}
+
+
+impl<'a, T, E> ListBuilder<'a, T, E> {
+ pub fn create(&mut self) {
+ if !self.has_getvalue_func {
+ unsafe {
+ ui_list_args_set_getvalue_func2(self.args, null_getvalue_wrapper);
+ }
+ }
+ (self.create)(self.obj.ptr, self.args);
+ }
+
+ pub fn fill(&mut self, fill: bool) -> &mut Self {
+ unsafe {
+ ui_list_args_set_fill(self.args, if fill { 1 } else { 0 });
+ }
+ self
+ }
+
+ pub fn hexpand(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_list_args_set_hexpand(self.args, if value { 1 } else { 0 });
+ }
+ self
+ }
+
+ pub fn vexpand(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_list_args_set_vexpand(self.args, if value { 1 } else { 0 });
+ }
+ self
+ }
+
+ pub fn hfill(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_list_args_set_hfill(self.args, if value { 1 } else { 0 });
+ }
+ self
+ }
+
+ pub fn vfill(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_list_args_set_vfill(self.args, if value { 1 } else { 0 });
+ }
+ self
+ }
+
+ pub fn override_defaults(&mut self, value: bool) -> &mut Self {
+ unsafe {
+ ui_list_args_set_override_defaults(self.args, if value { 1 } else { 0 });
+ }
+ self
+ }
+
+ pub fn margin(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_list_args_set_margin(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_left(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_list_args_set_margin_left(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_right(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_list_args_set_margin_right(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_top(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_list_args_set_margin_top(self.args, value);
+ }
+ self
+ }
+
+ pub fn margin_bottom(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_list_args_set_margin_bottom(self.args, value);
+ }
+ self
+ }
+
+ pub fn colspan(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_list_args_set_colspan(self.args, value);
+ }
+ self
+ }
+
+ pub fn rowspan(&mut self, value: i32) -> &mut Self {
+ unsafe {
+ ui_list_args_set_rowspan(self.args, value);
+ }
+ self
+ }
+
+ pub fn name(&mut self, value: &str) -> &mut Self {
+ let cstr = CString::new(value).unwrap();
+ unsafe {
+ ui_list_args_set_name(self.args, cstr.as_ptr());
+ }
+ self
+ }
+
+ pub fn style_class(&mut self, value: &str) -> &mut Self {
+ let cstr = CString::new(value).unwrap();
+ unsafe {
+ ui_list_args_set_style_class(self.args, cstr.as_ptr());
+ }
+ self
+ }
+
+ pub fn visibility_states(&mut self, states: &[i32]) -> &mut Self {
+ unsafe {
+ ui_list_args_set_visibility_states(self.args, states.as_ptr(), states.len() as c_int);
+ }
+ self
+ }
+
+ pub fn value<C>(&mut self, value: &toolkit::UiList<C>) -> &mut Self {
+ unsafe {
+ ui_list_args_set_value(self.args, value.ptr);
+ }
+ self
+ }
+
+ pub fn getvalue<F>(&mut self, f: F) -> &mut Self
+ where F: Fn(&E, i32, i32) -> ListValue<'a> + 'static {
+ unsafe {
+ let wrapper = Box::new(GetValueWrapper { callback: Box::new(f) });
+ let ptr = self.obj.reg_box(wrapper);
+ ui_list_args_set_getvalue_func2(self.args, getvalue_wrapper::<T>);
+ ui_list_args_set_getvalue_data(self.args, ptr as *mut c_void);
+ }
+ self.has_getvalue_func = true;
+ self
+ }
+
+ pub fn states(&mut self, states: &[i32]) -> &mut Self {
+ unsafe {
+ ui_list_args_set_states(self.args, states.as_ptr(), states.len() as c_int);
+ }
+ self
+ }
+}
+
+type GetValueFunc = extern "C" fn(list: *const ffi::UiList, elm_ptr: *const c_void, row: i32, col: i32, wrapper: *const c_void, free: *mut bool) -> *mut c_void;
+
+pub struct GetValueWrapper<'a, T> {
+ pub callback: Box<dyn Fn(&T, i32, i32) -> ListValue<'a>>,
+}
+
+
+fn str_dup(str: &str) -> *mut c_void {
+ let cstr = CString::new(str).unwrap();
+ let bytes = cstr.as_bytes_with_nul();
+
+ unsafe {
+ let ptr = malloc(bytes.len()) as *mut c_char;
+ if ptr.is_null() {
+ return std::ptr::null_mut();
+ }
+
+ std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len());
+ ptr as *mut c_void
+ }
+}
+
+pub extern "C" fn getvalue_wrapper<T>(_list: *const ffi::UiList, elm_ptr: *const c_void, row: i32, col: i32, wrapper_ptr: *const c_void, free: *mut bool) -> *mut c_void {
+ let wrapper = unsafe { &*(wrapper_ptr as *const GetValueWrapper<T> ) };
+ let elm = unsafe { &*(elm_ptr as *const T) };
+
+ unsafe {
+ *free = true;
+ }
+
+ let result = (wrapper.callback)(elm, col, row);
+ match result {
+ ListValue::None => std::ptr::null_mut(),
+ ListValue::Str(s) => str_dup(s),
+ ListValue::String(s) => str_dup(s.as_str())
+ }
+}
+
+pub extern "C" fn null_getvalue_wrapper(_list: *const ffi::UiList, _elm_ptr: *const c_void, _row: i32, _col: i32, _wrapper: *const c_void, _free: *mut bool) -> *mut c_void {
+ std::ptr::null_mut()
+}
+
+
+extern "C" {
+ fn malloc(size: usize) -> *mut c_void;
+
+ fn ui_listview_create(obj: *const UiObject, args: *const UiListArgs);
+
+ fn ui_list_args_new() -> *mut UiListArgs;
+ fn ui_list_args_set_fill(args: *mut UiListArgs, fill: c_int);
+ fn ui_list_args_set_hexpand(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_vexpand(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_hfill(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_vfill(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_override_defaults(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_margin(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_margin_left(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_margin_right(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_margin_top(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_margin_bottom(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_colspan(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_rowspan(args: *mut UiListArgs, value: c_int);
+ fn ui_list_args_set_name(args: *mut UiListArgs, name: *const c_char);
+ fn ui_list_args_set_style_class(args: *mut UiListArgs, classname: *const c_char);
+ fn ui_list_args_set_onchange(args: *mut UiListArgs, callback: UiCallback);
+ fn ui_list_args_set_onchangedata(args: *mut UiListArgs, data: *mut c_void);
+ fn ui_list_args_set_varname(args: *mut UiListArgs, varname: *const c_char);
+ fn ui_list_args_set_value(args: *mut UiListArgs, ivalue: *mut UiList);
+ fn ui_list_args_set_getvalue_func2(args: *mut UiListArgs, func: GetValueFunc);
+ fn ui_list_args_set_getvalue_data(args: *mut UiListArgs, data: *mut c_void);
+ fn ui_list_args_set_enablestate(args: *mut UiListArgs, state: c_int);
+ fn ui_list_args_set_states(args: *mut UiListArgs, states: *const c_int, numstates: c_int);
+ fn ui_list_args_set_visibility_states(args: *mut UiListArgs, states: *const c_int, numstates: c_int);
+ fn ui_list_args_free(args: *mut UiListArgs);
+
+}
\ No newline at end of file