use crate::event::WxEvtHandler;
use crate::widgets::dataview::item::DataViewItem;
use crate::widgets::imagelist::ImageList;
use crate::window::{WindowHandle, WxWidget};
use crate::{Id, Point, Size};
use std::ffi::{CStr, CString};
use wxdragon_sys as ffi;
use super::DataViewModel;
use super::column::DataViewColumn;
use super::enums::{DataViewAlign, DataViewCellMode, DataViewColumnFlags};
use super::renderer::{DataViewIconTextRenderer, DataViewTextRenderer};
use super::variant::VariantType;
widget_style_enum! {
name: DataViewTreeCtrlStyle,
doc: "Style flags for DataViewTreeCtrl widget.",
variants: {
Default: 0, "Default style.",
DvMultiple: ffi::WXD_DV_MULTIPLE, "Allow multiple selections.",
DvRowLines: ffi::WXD_DV_ROW_LINES, "Show row lines.",
DvHorizRules: ffi::WXD_DV_HORIZ_RULES, "Show horizontal rules (same as DvRowLines).",
DvVariableLineHeight: ffi::WXD_DV_VARIABLE_LINE_HEIGHT, "Allow variable line height."
},
default_variant: Default
}
widget_builder! {
name: DataViewTreeCtrl,
parent_type: &'a dyn WxWidget,
style_type: DataViewTreeCtrlStyle,
fields: {
label: String = String::new()
},
build_impl: |slf| {
DataViewTreeCtrl::new_impl(
slf.parent.handle_ptr(),
slf.id,
&slf.label,
slf.pos,
slf.size,
slf.style.bits()
)
}
}
#[derive(Clone, Copy)]
pub struct DataViewTreeCtrl {
handle: WindowHandle,
}
impl DataViewTreeCtrl {
pub fn builder<'a>(parent: &'a dyn WxWidget) -> DataViewTreeCtrlBuilder<'a> {
DataViewTreeCtrlBuilder::new(parent)
}
fn new_impl(parent_ptr: *mut ffi::wxd_Window_t, id: Id, label: &str, pos: Point, size: Size, style: i64) -> Self {
let label_c_str = CString::new(label).unwrap_or_default();
let ptr = unsafe {
ffi::wxd_DataViewTreeCtrl_new(
parent_ptr,
id,
pos.into(),
size.into(),
style,
std::ptr::null_mut(),
label_c_str.as_ptr(),
)
};
if ptr.is_null() {
panic!("Failed to create DataViewTreeCtrl");
}
DataViewTreeCtrl {
handle: WindowHandle::new(ptr),
}
}
#[inline]
fn dvtc_ptr(&self) -> *mut ffi::wxd_Window_t {
self.handle.get_ptr().unwrap_or(std::ptr::null_mut())
}
pub fn window_handle(&self) -> WindowHandle {
self.handle
}
pub fn append_column(&self, column: &DataViewColumn) -> bool {
unsafe { ffi::wxd_DataViewCtrl_AppendColumn(self.dvtc_ptr(), column.as_raw()) }
}
pub fn prepend_column(&self, column: &DataViewColumn) -> bool {
unsafe { ffi::wxd_DataViewCtrl_PrependColumn(self.dvtc_ptr(), column.as_raw()) }
}
pub fn insert_column(&self, pos: usize, column: &DataViewColumn) -> bool {
unsafe { ffi::wxd_DataViewCtrl_InsertColumn(self.dvtc_ptr(), pos as i64, column.as_raw()) }
}
pub fn clear_columns(&self) -> bool {
unsafe { ffi::wxd_DataViewCtrl_ClearColumns(self.dvtc_ptr()) }
}
pub fn get_expander_column(&self) -> Option<DataViewColumn> {
unsafe {
let col_ptr = ffi::wxd_DataViewCtrl_GetExpanderColumn(self.dvtc_ptr());
if col_ptr.is_null() {
None
} else {
Some(DataViewColumn::from_ptr(col_ptr))
}
}
}
pub fn set_expander_column(&self, column: &DataViewColumn) {
unsafe { ffi::wxd_DataViewCtrl_SetExpanderColumn(self.dvtc_ptr(), column.as_raw()) }
}
pub fn get_column(&self, pos: usize) -> Option<DataViewColumn> {
unsafe {
let col_ptr = ffi::wxd_DataViewCtrl_GetColumn(self.dvtc_ptr(), pos as u32);
if col_ptr.is_null() {
None
} else {
Some(DataViewColumn::from_ptr(col_ptr))
}
}
}
pub fn append_text_column(
&self,
label: &str,
model_column: u32,
width: i32,
align: DataViewAlign,
flags: DataViewColumnFlags,
) -> bool {
let renderer = DataViewTextRenderer::new(VariantType::String, DataViewCellMode::Inert, align);
let column = DataViewColumn::new(label, &renderer, model_column as usize, width, align, flags);
self.append_column(&column)
}
pub fn append_icon_text_column(
&self,
label: &str,
model_column: i32,
width: i32,
align: DataViewAlign,
flags: DataViewColumnFlags,
) -> bool {
let renderer = DataViewIconTextRenderer::new(VariantType::IconText, DataViewCellMode::Inert, align);
let column = DataViewColumn::new(label, &renderer, model_column as usize, width, align, flags);
self.append_column(&column)
}
pub fn associate_model<M: DataViewModel>(&self, model: &M) -> bool {
let model_ptr = model.handle_ptr();
unsafe { ffi::wxd_DataViewCtrl_AssociateModel(self.dvtc_ptr(), model_ptr) }
}
pub fn append_item(&self, parent: &DataViewItem, text: &str, icon: i32) -> DataViewItem {
let text_c_str = CString::new(text).unwrap_or_default();
unsafe {
let raw_item = ffi::wxd_DataViewTreeCtrl_AppendItem(self.dvtc_ptr(), **parent, text_c_str.as_ptr(), icon);
DataViewItem::from(raw_item)
}
}
pub fn append_container(&self, parent: &DataViewItem, text: &str, icon: i32, expanded_icon: i32) -> DataViewItem {
let text_c_str = CString::new(text).unwrap_or_default();
unsafe {
let raw_item =
ffi::wxd_DataViewTreeCtrl_AppendContainer(self.dvtc_ptr(), **parent, text_c_str.as_ptr(), icon, expanded_icon);
DataViewItem::from(raw_item)
}
}
pub fn prepend_item(&self, parent: &DataViewItem, text: &str, icon: i32) -> DataViewItem {
let text_c_str = CString::new(text).unwrap_or_default();
unsafe {
let raw_item = ffi::wxd_DataViewTreeCtrl_PrependItem(self.dvtc_ptr(), **parent, text_c_str.as_ptr(), icon);
DataViewItem::from(raw_item)
}
}
pub fn prepend_container(&self, parent: &DataViewItem, text: &str, icon: i32, expanded_icon: i32) -> DataViewItem {
let text_c_str = CString::new(text).unwrap_or_default();
unsafe {
let raw_item =
ffi::wxd_DataViewTreeCtrl_PrependContainer(self.dvtc_ptr(), **parent, text_c_str.as_ptr(), icon, expanded_icon);
DataViewItem::from(raw_item)
}
}
pub fn insert_item(&self, parent: &DataViewItem, previous: &DataViewItem, text: &str, icon: i32) -> DataViewItem {
let text_c_str = CString::new(text).unwrap_or_default();
unsafe {
let raw_item = ffi::wxd_DataViewTreeCtrl_InsertItem(self.dvtc_ptr(), **parent, **previous, text_c_str.as_ptr(), icon);
DataViewItem::from(raw_item)
}
}
pub fn insert_container(
&self,
parent: &DataViewItem,
previous: &DataViewItem,
text: &str,
icon: i32,
expanded_icon: i32,
) -> DataViewItem {
let text_c_str = CString::new(text).unwrap_or_default();
unsafe {
let raw_item = ffi::wxd_DataViewTreeCtrl_InsertContainer(
self.dvtc_ptr(),
**parent,
**previous,
text_c_str.as_ptr(),
icon,
expanded_icon,
);
DataViewItem::from(raw_item)
}
}
pub fn delete_item(&self, item: &DataViewItem) {
unsafe { ffi::wxd_DataViewTreeCtrl_DeleteItem(self.dvtc_ptr(), **item) };
}
pub fn delete_children(&self, item: &DataViewItem) {
unsafe { ffi::wxd_DataViewTreeCtrl_DeleteChildren(self.dvtc_ptr(), **item) };
}
pub fn delete_all_items(&self) {
unsafe { ffi::wxd_DataViewTreeCtrl_DeleteAllItems(self.dvtc_ptr()) };
}
pub fn get_item_text(&self, item: &DataViewItem) -> String {
let ptr = self.dvtc_ptr();
let len = unsafe { ffi::wxd_DataViewTreeCtrl_GetItemText(ptr, **item, std::ptr::null_mut(), 0) };
if len <= 0 {
return String::new();
}
let mut b = vec![0; len as usize + 1]; unsafe { ffi::wxd_DataViewTreeCtrl_GetItemText(ptr, **item, b.as_mut_ptr(), b.len()) };
unsafe { CStr::from_ptr(b.as_ptr()).to_string_lossy().to_string() }
}
pub fn set_item_text(&self, item: &DataViewItem, text: &str) {
let text_c_str = CString::new(text).unwrap_or_default();
unsafe {
ffi::wxd_DataViewTreeCtrl_SetItemText(self.dvtc_ptr(), **item, text_c_str.as_ptr());
}
}
pub fn set_item_icon(&self, item: &DataViewItem, icon_idx: i32) {
unsafe {
ffi::wxd_DataViewTreeCtrl_SetItemIcon(self.dvtc_ptr(), **item, icon_idx);
}
}
pub fn set_item_expanded_icon(&self, item: &DataViewItem, icon_idx: i32) {
unsafe {
ffi::wxd_DataViewTreeCtrl_SetItemExpandedIcon(self.dvtc_ptr(), **item, icon_idx);
}
}
pub fn get_item_parent(&self, item: &DataViewItem) -> DataViewItem {
unsafe {
let raw_item = ffi::wxd_DataViewTreeCtrl_GetItemParent(self.dvtc_ptr(), **item);
DataViewItem::from(raw_item)
}
}
pub fn get_child_count(&self, parent: &DataViewItem) -> u32 {
unsafe { ffi::wxd_DataViewTreeCtrl_GetChildCount(self.dvtc_ptr(), **parent) }
}
pub fn get_nth_child(&self, parent: &DataViewItem, pos: u32) -> DataViewItem {
unsafe {
let raw_item = ffi::wxd_DataViewTreeCtrl_GetNthChild(self.dvtc_ptr(), **parent, pos);
DataViewItem::from(raw_item)
}
}
pub fn is_container(&self, item: &DataViewItem) -> bool {
unsafe { ffi::wxd_DataViewTreeCtrl_IsContainer(self.dvtc_ptr(), **item) }
}
pub fn expand(&self, item: &DataViewItem) {
unsafe { ffi::wxd_DataViewTreeCtrl_Expand(self.dvtc_ptr(), **item) };
}
pub fn collapse(&self, item: &DataViewItem) {
unsafe { ffi::wxd_DataViewTreeCtrl_Collapse(self.dvtc_ptr(), **item) };
}
pub fn is_expanded(&self, item: &DataViewItem) -> bool {
unsafe { ffi::wxd_DataViewTreeCtrl_IsExpanded(self.dvtc_ptr(), **item) }
}
pub fn set_image_list(&self, image_list: ImageList) {
unsafe {
ffi::wxd_DataViewTreeCtrl_SetImageList(self.dvtc_ptr(), image_list.as_ptr() as *mut ffi::wxd_ImageList_t);
std::mem::forget(image_list);
}
}
pub fn get_image_list(&self) -> Option<ImageList> {
unsafe {
let raw_ptr = ffi::wxd_DataViewTreeCtrl_GetImageList(self.dvtc_ptr()) as *mut ffi::wxd_ImageList_t;
if raw_ptr.is_null() {
None
} else {
Some(ImageList::from_ptr_unowned(raw_ptr)) }
}
}
pub fn get_selection(&self) -> Option<DataViewItem> {
let selections = self.get_selections();
selections.into_iter().next()
}
pub fn get_selections(&self) -> Vec<DataViewItem> {
let count = unsafe { ffi::wxd_DataViewCtrl_GetSelectedItemsCount(self.dvtc_ptr()) };
if count == 0 {
return Vec::new();
}
let mut items = Vec::with_capacity(count as usize);
let mut items_raw: Vec<*const ffi::wxd_DataViewItem_t> = vec![std::ptr::null(); count as usize];
let items_raw_ptr = items_raw.as_mut_ptr();
unsafe { ffi::wxd_DataViewCtrl_GetSelections(self.dvtc_ptr(), items_raw_ptr, count) };
for raw_ptr in items_raw {
if !raw_ptr.is_null() {
items.push(DataViewItem::from(raw_ptr));
}
}
items
}
}
impl WxWidget for DataViewTreeCtrl {
fn handle_ptr(&self) -> *mut ffi::wxd_Window_t {
self.handle.get_ptr().unwrap_or(std::ptr::null_mut())
}
fn is_valid(&self) -> bool {
self.handle.is_valid()
}
}
impl WxEvtHandler for DataViewTreeCtrl {
unsafe fn get_event_handler_ptr(&self) -> *mut ffi::wxd_EvtHandler_t {
self.handle.get_ptr().unwrap_or(std::ptr::null_mut()) as *mut ffi::wxd_EvtHandler_t
}
}
impl crate::event::WindowEvents for DataViewTreeCtrl {}
impl crate::widgets::dataview::DataViewEventHandler for DataViewTreeCtrl {}
impl crate::widgets::dataview::DataViewTreeEventHandler for DataViewTreeCtrl {}