#include <wx/wxprec.h>
#include <wx/wx.h>
#include "../include/wxdragon.h"
#include "wx/dataview.h"
#include <vector>
extern "C" void wxd_Drop_Rust_DataViewTreeModelCallbacks(wxd_DataViewTreeModel_Callbacks* ptr);
class Wxd_Callbacks_DataViewTreeModel : public wxDataViewModel
{
public:
Wxd_Callbacks_DataViewTreeModel(const wxd_DataViewTreeModel_Callbacks* cb)
{
m_cb = cb;
}
virtual ~Wxd_Callbacks_DataViewTreeModel()
{
if (m_cb) {
wxd_Drop_Rust_DataViewTreeModelCallbacks(const_cast<wxd_DataViewTreeModel_Callbacks*>(m_cb));
}
}
unsigned int GetChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const override
{
if (!m_cb || !m_cb->get_children)
return 0;
void** items = nullptr;
int count = 0;
m_cb->get_children(m_cb->userdata, (void*)parent.GetID(), &items, &count);
if (items && count > 0)
{
for (int i = 0; i < count; ++i)
{
array.push_back(wxDataViewItem(items[i]));
}
if (m_cb->free_children)
m_cb->free_children(items, count);
return array.size();
}
return 0;
}
wxDataViewItem GetParent(const wxDataViewItem &item) const override
{
if (!m_cb || !m_cb->get_parent)
return wxDataViewItem(nullptr);
void* p = m_cb->get_parent(m_cb->userdata, (void*)item.GetID());
return wxDataViewItem(p);
}
bool IsContainer(const wxDataViewItem &item) const override
{
if (!m_cb || !m_cb->is_container)
return false;
return m_cb->is_container(m_cb->userdata, (void*)item.GetID());
}
void GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const override
{
if (!m_cb || !m_cb->get_value)
return;
wxd_Variant_t rust_variant_data = {};
m_cb->get_value(m_cb->userdata, (void*)item.GetID(), col, &rust_variant_data);
switch (rust_variant_data.type) {
case WXD_VARIANT_TYPE_STRING:
if (rust_variant_data.data.string_val) {
variant = wxVariant(wxString::FromUTF8(rust_variant_data.data.string_val));
wxd_Variant_Free_Rust_String(rust_variant_data.data.string_val);
rust_variant_data.data.string_val = nullptr;
}
break;
case WXD_VARIANT_TYPE_BOOL:
variant = wxVariant(rust_variant_data.data.bool_val != 0);
break;
case WXD_VARIANT_TYPE_INT32:
variant = wxVariant(static_cast<long>(rust_variant_data.data.int32_val));
break;
case WXD_VARIANT_TYPE_INT64:
variant = wxVariant(wxLongLong(rust_variant_data.data.int64_val));
break;
case WXD_VARIANT_TYPE_DOUBLE:
variant = wxVariant(rust_variant_data.data.double_val);
break;
case WXD_VARIANT_TYPE_DATETIME: {
wxDateTime dt;
dt.Set(
rust_variant_data.data.datetime_val.day,
static_cast<wxDateTime::Month>(rust_variant_data.data.datetime_val.month),
rust_variant_data.data.datetime_val.year,
rust_variant_data.data.datetime_val.hour,
rust_variant_data.data.datetime_val.minute,
rust_variant_data.data.datetime_val.second
);
variant = dt;
break;
}
case WXD_VARIANT_TYPE_BITMAP_RUST_BORROWED:
if (rust_variant_data.data.bitmap_val) {
wxBitmap* bmp = reinterpret_cast<wxBitmap*>(rust_variant_data.data.bitmap_val);
if (bmp && bmp->IsOk()) {
try {
wxBitmap copy(*bmp);
variant << copy;
} catch (...) {
wxBitmap fb(16,16); variant << fb;
}
}
}
break;
case WXD_VARIANT_TYPE_BITMAP:
if (rust_variant_data.data.bitmap_val) {
wxBitmap* bmp = reinterpret_cast<wxBitmap*>(rust_variant_data.data.bitmap_val);
if (bmp && bmp->IsOk()) {
try {
wxBitmap copy(*bmp);
variant << copy;
} catch (...) { }
}
wxd_Bitmap_Destroy(reinterpret_cast<wxd_Bitmap_t*>(rust_variant_data.data.bitmap_val));
rust_variant_data.data.bitmap_val = nullptr;
}
break;
default:
break;
}
}
bool SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned int col) override
{
if (!m_cb || !m_cb->set_value)
return false;
wxd_Variant_t rust_variant = {};
wxString type_name = variant.GetType();
if (type_name == "bool") {
rust_variant.type = WXD_VARIANT_TYPE_BOOL;
rust_variant.data.bool_val = variant.GetBool();
} else if (type_name == "long") {
rust_variant.type = WXD_VARIANT_TYPE_INT32;
rust_variant.data.int32_val = static_cast<int32_t>(variant.GetLong());
} else if (type_name == "longlong") {
rust_variant.type = WXD_VARIANT_TYPE_INT64;
rust_variant.data.int64_val = static_cast<int64_t>(variant.GetLongLong().GetValue());
} else if (type_name == "double") {
rust_variant.type = WXD_VARIANT_TYPE_DOUBLE;
rust_variant.data.double_val = variant.GetDouble();
} else if (type_name == "string") {
rust_variant.type = WXD_VARIANT_TYPE_STRING;
std::string utf8 = variant.GetString().ToUTF8().data();
char* str = static_cast<char*>(calloc(utf8.length() + 1, sizeof(char)));
if (str) {
strcpy(str, utf8.c_str());
rust_variant.data.string_val = str;
} else {
rust_variant.data.string_val = nullptr;
}
} else {
rust_variant.type = WXD_VARIANT_TYPE_INVALID;
}
bool result = m_cb->set_value(m_cb->userdata, (void*)item.GetID(), col, &rust_variant);
if (rust_variant.type == WXD_VARIANT_TYPE_STRING && rust_variant.data.string_val) {
free(rust_variant.data.string_val);
}
return result;
}
bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override
{
if (!m_cb || !m_cb->is_enabled)
return true;
return m_cb->is_enabled(m_cb->userdata, (void*)item.GetID(), col);
}
int Compare(const wxDataViewItem &item1, const wxDataViewItem &item2, unsigned int column, bool ascending) const override
{
if (!m_cb || !m_cb->compare)
return wxDataViewModel::Compare(item1, item2, column, ascending);
return m_cb->compare(m_cb->userdata, (void*)item1.GetID(), (void*)item2.GetID(), column, ascending);
}
private:
const wxd_DataViewTreeModel_Callbacks* m_cb;
};
extern "C" wxd_DataViewModel_t* wxd_DataViewTreeModel_CreateWithCallbacks(const wxd_DataViewTreeModel_Callbacks* cb)
{
if (!cb) return nullptr;
Wxd_Callbacks_DataViewTreeModel* model = new Wxd_Callbacks_DataViewTreeModel(cb);
return reinterpret_cast<wxd_DataViewModel_t*>(model);
}
extern "C" void wxd_DataViewTreeModel_Release(wxd_DataViewModel_t* model)
{
if (!model) return;
Wxd_Callbacks_DataViewTreeModel* m = reinterpret_cast<Wxd_Callbacks_DataViewTreeModel*>((wxDataViewModel*)model);
if (m) {
delete m;
}
}