wxdragon-sys 0.4.1

Raw FFI bindings to libwxdragon (which statically links wxWidgets).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
#include "../include/wxdragon.h"
// #include "../include/events/wxd_event_api.h" // No longer needed, wxd_Event_t defined in wxd_types.h (via wxdragon.h)
#include <wx/wx.h>
#include <unordered_map>
#include <memory> // For std::unique_ptr if we want safer memory management
#include <tuple>  // For std::pair used in map key
#include <wx/event.h>
#include <wx/app.h>
#include <wx/window.h> // For wxCloseEvent
#include <wx/tglbtn.h> // ADDED for wxEVT_TOGGLEBUTTON
#include <wx/treectrl.h> // ADDED: For wxEVT_TREE_* constants
#include <wx/slider.h> // ADDED: For wxEVT_SCROLL_CHANGED etc.
#include <wx/spinctrl.h> // ADDED: For wxEVT_SPINCTRL
#include <wx/spinbutt.h> // ADDED: For wxEVT_SPIN*
#include <wx/notebook.h> // ADDED: For wxEVT_NOTEBOOK_PAGE_CHANGED
#include <wx/splitter.h> // ADDED: For wxEVT_SPLITTER_*
#include <wx/listctrl.h> // ADDED: For wxEVT_LIST_*
#include <wx/clrpicker.h> // ADDED: For wxEVT_COLOURPICKER_CHANGED
#include <wx/dateevt.h> // ADDED: For wxEVT_DATE_CHANGED
#include <wx/treebook.h> // ADDED: For wxEVT_TREEBOOK_*
#include <wx/srchctrl.h> // ADDED: For wxEVT_SEARCHCTRL_SEARCH_BTN, wxEVT_SEARCHCTRL_CANCEL_BTN
#include <wx/hyperlink.h> // ADDED: For wxHyperlinkEvent
#include <wx/calctrl.h> // ADDED: For wxCalendarCtrl events
#include <wx/filepicker.h> // ADDED: For wxEVT_FILEPICKER_CHANGED and wxEVT_DIRPICKER_CHANGED
#include <wx/fontpicker.h> // ADDED: For wxEVT_FONTPICKER_CHANGED
#include <wx/notifmsg.h> // For wxNotificationMessage events
#include <wx/dnd.h> // ADDED: For drag and drop events (wxEVT_BEGIN_DRAG, wxEVT_DROP_TEXT, etc.)
#include <wx/timectrl.h> // ADDED: For wxTimePickerCtrl and wxEVT_TIME_CHANGED
#include <wx/mediactrl.h> // ADDED: For MediaCtrl events
#include <wx/dataview.h> // ADDED: For DataView events
#include <wx/grid.h>
#include "../src/wxd_utils.h" // For WXD_STR_TO_WX_STRING_UTF8_NULL_OK, etc.

// --- Internal C++ Structures/Classes (Not exposed in C API) ---

// Define a hash function for std::pair<int, int>
struct PairHash {
    template <class T1, class T2>
    std::size_t operator() (const std::pair<T1, T2>& p) const {
        auto hash1 = std::hash<T1>{}(p.first);
        auto hash2 = std::hash<T2>{}(p.second);
        // Simple combination hash - consider better alternatives if collisions become an issue
        return hash1 ^ (hash2 << 1); 
    }
};

// Structure to hold the Rust closure information
struct RustClosureInfo {
    void* closure_ptr = nullptr;
    // We might need the trampoline pointer here too if it varies,
    // but for now, assume a single global trampoline `rust_event_handler_trampoline`.
    wxd_ClosureCallback rust_trampoline = nullptr; // Store the trampoline func ptr
};

// Forward declaration
class WxdEventHandler;

// ClientData class to hold our handler pointer and ensure deletion
class WxdHandlerClientData : public wxClientData {
public:
    WxdEventHandler* handler; // Pointer to the handler associated with the window

    WxdHandlerClientData(WxdEventHandler* h) : handler(h) {}
    virtual ~WxdHandlerClientData(); // Defined after WxdEventHandler
};

// Custom Event Handler class to connect wx events to Rust closures
class WxdEventHandler : public wxEvtHandler {
public:
    // Map (eventType, widgetId) pair to the Rust closure info
    std::unordered_map<std::pair<wxEventType, wxd_Id>, RustClosureInfo, PairHash> closureMap; 
    wxd_EvtHandler_t* c_handle = nullptr; // Changed type to wxd_EvtHandler_t*
    wxEvtHandler* ownerHandler = nullptr; // Store the actual wxEvtHandler*

    WxdEventHandler(wxd_EvtHandler_t* handle, wxEvtHandler* owner) : c_handle(handle), ownerHandler(owner) {}

    // Destructor - Now needs to notify Rust to drop closures via drop_rust_closure_box
    ~WxdEventHandler(); // Declaration moved, definition below

    // The actual event handler called by wxWidgets
    void OnAnyEvent(wxEvent& event); 
};

// Define WxdHandlerClientData destructor (no change needed here, it still just deletes the handler)
WxdHandlerClientData::~WxdHandlerClientData() {
    delete handler;
}

// --- Declare the Rust helper functions ---
// These functions will be implemented in the Rust `wxdragon` crate.
extern "C" {
    // The trampoline function implemented in Rust
    // Its signature MUST match wxd_ClosureCallback in wxdragon.h
    // void rust_event_handler_trampoline(wxd_Event_t* event_ptr, void* user_data);
    
    // Function implemented in Rust to drop the Box<dyn FnMut(Event)>.
    void drop_rust_closure_box(void* ptr);
}

// WxdEventHandler Destructor Implementation
WxdEventHandler::~WxdEventHandler() {
    // wxLogDebug("WxdEventHandler destroying for handler %p. Notifying Rust to drop closures.", ownerHandler);
    for (auto const& [key, info] : closureMap) {
        if (info.closure_ptr) {
            // Tell Rust to drop the Box corresponding to this pointer
            drop_rust_closure_box(info.closure_ptr);
        }
    }
    // Clear the map (optional, as the handler is being destroyed)
    closureMap.clear();
}

// Modify OnAnyEvent to call the Rust trampoline
void WxdEventHandler::OnAnyEvent(wxEvent& event) {
    wxEventType eventType = event.GetEventType();
    wxd_Id id = event.GetId(); // Get the widget ID from the event

    // Create the key pair
    std::pair<wxEventType, wxd_Id> key = {eventType, id};

    auto it = closureMap.find(key); // Look up using the combined key

    if (it != closureMap.end()) {
        RustClosureInfo& info = it->second;
        if (info.closure_ptr && info.rust_trampoline) {
            // wxLogDebug("[DEBUG C++] Found closure for type=%d, id=%d. Calling trampoline.", eventType, id);
            // Call the specific Rust trampoline function stored in info
            info.rust_trampoline(reinterpret_cast<wxd_Event_t*>(&event), info.closure_ptr);

            // We assume the Rust closure handles event.Skip() if needed via wxd_Event_Skip.
            return; // Event handled (or skipped) by Rust closure
        } else {
            // Should not happen if Bind succeeded, but log if it does
            // wxLogDebug("[DEBUG C++] OnAnyEvent: Found key (%d, %d) but closure_ptr or rust_trampoline is null!", eventType, id);
        }
    } else {
    // If no Rust closure was found for this specific event type,
    // allow default processing.
    event.Skip();
    }
}

// --- C API Implementation --- 

// Gets the handler associated with the wxEvtHandler via client data,
// creating it if it doesn't exist.
WxdEventHandler* GetOrCreateEventHandler(wxEvtHandler* handler, wxd_EvtHandler_t* c_handle) {
    if (!handler) return nullptr;

    WxdHandlerClientData* clientData = static_cast<WxdHandlerClientData*>(handler->GetClientData());
    WxdEventHandler* customHandler = nullptr;

    if (!clientData) {
        // Create the handler
        customHandler = new WxdEventHandler(c_handle, handler);
        // Create the client data wrapper to manage the handler's lifetime
        clientData = new WxdHandlerClientData(customHandler);
        // Associate client data with the wxEvtHandler
        handler->SetClientData(clientData);
        // wxLogDebug("Created WxdEventHandler %p and WxdHandlerClientData %p for wxEvtHandler %p (c_handle %p)", customHandler, clientData, handler, c_handle);
    } else {
        customHandler = clientData->handler;
        // Ensure c_handle is up-to-date (shouldn't change, but good practice)
        if (customHandler) {
            customHandler->c_handle = c_handle; // Update C handle if needed
            customHandler->ownerHandler = handler; // Update owner pointer
        }
    }

    return customHandler;
}

// --- C++ Closure Wrapper (Functor) ---

// A simple functor class to wrap the Rust callback and data pointer.
// Its lifetime is managed by wxWidgets when bound using `wxEvtHandler::Bind`.
// Based on wxRust2 CxxClosureVoid.
class CxxClosureVoid {
public:
    // Type alias for the Rust trampoline function signature
    // It takes the Rust closure data (as void*) and the event pointer (as void*)
    // Note: Argument order might differ from previous attempts, match Rust definition.
    typedef void (*RustTrampolineFn)(void* closure_data, void* event_ptr);

    RustTrampolineFn fn_ptr;    // Pointer to the Rust trampoline function
    void*            param_ptr; // Pointer to the Rust closure Box
    bool             owned_by_wx; // NEW: Flag to track ownership transfer

    // Constructor: Store the Rust pointers, initially not owned by wx
    CxxClosureVoid(void* fn, void* param) : 
        fn_ptr(reinterpret_cast<RustTrampolineFn>(fn)), 
        param_ptr(param), 
        owned_by_wx(false) // Initialize flag
    {
         // wxLogDebug("CxxClosureVoid %p created fn=%p, param=%p, owned=%d", this, fn, param, owned_by_wx);
    }
    
    // Copy Constructor: Also copies the ownership flag state.
    CxxClosureVoid(const CxxClosureVoid& other) : 
        fn_ptr(other.fn_ptr), 
        param_ptr(other.param_ptr), 
        owned_by_wx(other.owned_by_wx) // CORRECT: Copy should inherit ownership state (initially false)
    {
        // wxLogDebug("CxxClosureVoid %p copy constructed from %p (owned=%d)", this, &other, owned_by_wx);
    }
    
    // Destructor: Only the wxWidgets-managed copy should drop the Rust Box.
    ~CxxClosureVoid() {
        // wxLogDebug("CxxClosureVoid %p destroyed. Checking ownership (owned=%d) for param=%p", this, owned_by_wx, param_ptr);
        
        // If owned_by_wx is TRUE, this is the *original* stack-allocated functor
        // whose ownership was transferred to the wxWidgets copy. DO NOT DROP here.
        if (owned_by_wx) {
            // wxLogDebug("CxxClosureVoid %p: Original functor (%p) destroyed, NOT dropping param=%p as owned by wx", this, param_ptr);
            return; // Don't drop if ownership was transferred
        }

        // If owned_by_wx is FALSE, this is either:
        // 1. The wxWidgets-managed copy being destroyed (param_ptr should be valid).
        // 2. The original functor being destroyed *because binding failed* (param_ptr should be valid).
        // In both cases where owned_by_wx is false, we *should* drop the box if the pointer is valid.
        if (param_ptr) {
            // wxLogDebug("CxxClosureVoid %p: Dropping Rust box param=%p as NOT owned by wx", this, param_ptr);
            drop_rust_closure_box(param_ptr);
            param_ptr = nullptr; // Avoid potential double drop if destructor called again somehow
        }
        // else: Warning if param_ptr is null when not owned? Might indicate logic error elsewhere.
    }

    // operator(): This is called by wxWidgets when the event fires.
    // It must accept the specific wxEvent subclass corresponding to the event type
    // it was bound with (e.g., wxCommandEvent&, wxCloseEvent&).
    // We define multiple operator() overloads or use templates if needed,
    // but the trampoline simplifies this: we just need one that takes wxEvent&.
    void operator()(wxEvent& event) {
        if (fn_ptr && param_ptr) {
            fn_ptr(param_ptr, reinterpret_cast<void*>(&event)); 
        } else {
             wxLogWarning("CxxClosureVoid operator() called but fn_ptr or param_ptr is null!");
             event.Skip();
        }
    }
};

// --- C API Implementation ---

extern "C" void wxd_EvtHandler_Bind(
    wxd_EvtHandler_t* handler,
    WXDEventTypeCEnum eventTypeC, 
    void* rust_trampoline_fn, 
    void* rust_closure_ptr   
) {
    wxEvtHandler* wx_handler = reinterpret_cast<wxEvtHandler*>(handler);
    if (!wx_handler) {
         wxLogWarning("wxd_EvtHandler_Bind called with null handler."); 
         if (rust_closure_ptr) { drop_rust_closure_box(rust_closure_ptr); }
         return;
    }

    if (!rust_trampoline_fn || !rust_closure_ptr) {
        wxLogWarning("wxd_EvtHandler_Bind called with null trampoline (%p) or closure (%p).", rust_trampoline_fn, rust_closure_ptr);
        if (rust_closure_ptr) { drop_rust_closure_box(rust_closure_ptr); } // Drop if trampoline is null but closure isn't
        return;
    }

    // Create the functor that wraps the Rust data
    CxxClosureVoid functor(rust_trampoline_fn, rust_closure_ptr);
    bool bound = false; // Flag to track if binding succeeded

    // Switch on the stable C enum value and map to the wxWidgets event tag
    switch (eventTypeC) {
        // --- Command Events ---
        case WXD_EVENT_TYPE_COMMAND_BUTTON_CLICKED:
             wx_handler->Bind(wxEVT_BUTTON, functor); 
             bound = true;
             break;
        case WXD_EVENT_TYPE_CHECKBOX:
            wx_handler->Bind(wxEVT_CHECKBOX, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_COMMAND_RADIOBUTTON_SELECTED:
             wx_handler->Bind(wxEVT_RADIOBUTTON, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_COMMAND_RADIOBOX_SELECTED:
             wx_handler->Bind(wxEVT_RADIOBOX, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_COMMAND_LISTBOX_SELECTED:
             wx_handler->Bind(wxEVT_LISTBOX, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_COMMAND_LISTBOX_DOUBLECLICKED:
            wx_handler->Bind(wxEVT_LISTBOX_DCLICK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_COMMAND_CHOICE_SELECTED:
             wx_handler->Bind(wxEVT_CHOICE, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_COMMAND_COMBOBOX_SELECTED:
             wx_handler->Bind(wxEVT_COMBOBOX, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_COMMAND_CHECKLISTBOX_SELECTED:
             wx_handler->Bind(wxEVT_CHECKLISTBOX, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_COMMAND_TOGGLEBUTTON_CLICKED:
             wx_handler->Bind(wxEVT_TOGGLEBUTTON, functor); 
             bound = true;
             break;
        case WXD_EVENT_TYPE_MENU:
             wx_handler->Bind(wxEVT_MENU, functor);
             bound = true;
             break;

        // --- Text Events ---
        case WXD_EVENT_TYPE_TEXT:
             wx_handler->Bind(wxEVT_TEXT, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_TEXT_ENTER:
             wx_handler->Bind(wxEVT_TEXT_ENTER, functor);
             bound = true;
             break;

        // --- Tree Events ---
        case WXD_EVENT_TYPE_TREE_BEGIN_LABEL_EDIT:
             wx_handler->Bind(wxEVT_TREE_BEGIN_LABEL_EDIT, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_TREE_END_LABEL_EDIT:
             wx_handler->Bind(wxEVT_TREE_END_LABEL_EDIT, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_TREE_SEL_CHANGED:
             wx_handler->Bind(wxEVT_TREE_SEL_CHANGED, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_TREE_ITEM_ACTIVATED:
             wx_handler->Bind(wxEVT_TREE_ITEM_ACTIVATED, functor);
             bound = true;
             break;

        // --- Slider/Spin Events ---
        case WXD_EVENT_TYPE_SLIDER:
             wx_handler->Bind(wxEVT_SLIDER, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_SPINCTRL:
             wx_handler->Bind(wxEVT_SPINCTRL, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_SPIN_UP:
             wx_handler->Bind(wxEVT_SPIN_UP, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_SPIN_DOWN:
             wx_handler->Bind(wxEVT_SPIN_DOWN, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_SPIN:
             wx_handler->Bind(wxEVT_SPIN, functor);
             bound = true;
             break;

        // --- Notebook Event ---
        case WXD_EVENT_TYPE_NOTEBOOK_PAGE_CHANGED:
             wx_handler->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, functor);
             bound = true;
             break;

        // --- Splitter Events ---
        case WXD_EVENT_TYPE_SPLITTER_SASH_POS_CHANGED:
             wx_handler->Bind(wxEVT_SPLITTER_SASH_POS_CHANGED, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_SPLITTER_SASH_POS_CHANGING:
             wx_handler->Bind(wxEVT_SPLITTER_SASH_POS_CHANGING, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_SPLITTER_DOUBLECLICKED:
             wx_handler->Bind(wxEVT_SPLITTER_DOUBLECLICKED, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_SPLITTER_UNSPLIT:
             wx_handler->Bind(wxEVT_SPLITTER_UNSPLIT, functor);
             bound = true;
             break;

        // --- ListCtrl Events ---
        case WXD_EVENT_TYPE_LIST_ITEM_SELECTED:
             wx_handler->Bind(wxEVT_LIST_ITEM_SELECTED, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_ITEM_ACTIVATED:
             wx_handler->Bind(wxEVT_LIST_ITEM_ACTIVATED, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_COL_CLICK:
             wx_handler->Bind(wxEVT_LIST_COL_CLICK, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_BEGIN_LABEL_EDIT:
             wx_handler->Bind(wxEVT_LIST_BEGIN_LABEL_EDIT, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_END_LABEL_EDIT:
             wx_handler->Bind(wxEVT_LIST_END_LABEL_EDIT, functor);
             bound = true;
             break;
        // ADDED: Additional ListCtrl events
        case WXD_EVENT_TYPE_LIST_BEGIN_DRAG:
             wx_handler->Bind(wxEVT_LIST_BEGIN_DRAG, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_BEGIN_RDRAG:
             wx_handler->Bind(wxEVT_LIST_BEGIN_RDRAG, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_DELETE_ITEM:
             wx_handler->Bind(wxEVT_LIST_DELETE_ITEM, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_DELETE_ALL_ITEMS:
             wx_handler->Bind(wxEVT_LIST_DELETE_ALL_ITEMS, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_ITEM_DESELECTED:
             wx_handler->Bind(wxEVT_LIST_ITEM_DESELECTED, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_ITEM_FOCUSED:
             wx_handler->Bind(wxEVT_LIST_ITEM_FOCUSED, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_ITEM_MIDDLE_CLICK:
             wx_handler->Bind(wxEVT_LIST_ITEM_MIDDLE_CLICK, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_ITEM_RIGHT_CLICK:
             wx_handler->Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_KEY_DOWN:
             wx_handler->Bind(wxEVT_LIST_KEY_DOWN, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_INSERT_ITEM:
             wx_handler->Bind(wxEVT_LIST_INSERT_ITEM, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_COL_RIGHT_CLICK:
             wx_handler->Bind(wxEVT_LIST_COL_RIGHT_CLICK, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LIST_COL_BEGIN_DRAG:
             wx_handler->Bind(wxEVT_LIST_COL_BEGIN_DRAG, functor);
             bound = true;
             break;

        // --- ColourPicker Event ---
        case WXD_EVENT_TYPE_COLOURPICKER_CHANGED: {
            int id = wxID_ANY;
            wxObject* cxx_data_copy = nullptr;
            wx_handler->Bind(wxEVT_COLOURPICKER_CHANGED, functor, id, wxID_ANY, cxx_data_copy);
            bound = true;
            break;
        }
        case WXD_EVENT_TYPE_DATE_CHANGED: {
            int id = wxID_ANY;
            wxObject* cxx_data_copy = nullptr;
            wx_handler->Bind(wxEVT_DATE_CHANGED, functor, id, wxID_ANY, cxx_data_copy);
            bound = true;
            break;
        }

        // --- Window Events ---
        case WXD_EVENT_TYPE_CLOSE_WINDOW:
            wx_handler->Bind(wxEVT_CLOSE_WINDOW, functor); 
            bound = true;
            break;
        case WXD_EVENT_TYPE_SIZE:
             wx_handler->Bind(wxEVT_SIZE, functor);
             bound = true;
             break;

        // --- Mouse Events ---
        case WXD_EVENT_TYPE_LEFT_DOWN:
             wx_handler->Bind(wxEVT_LEFT_DOWN, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_LEFT_UP:
             wx_handler->Bind(wxEVT_LEFT_UP, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_MOTION:
             wx_handler->Bind(wxEVT_MOTION, functor); 
             bound = true;
             break;
        case WXD_EVENT_TYPE_MOUSEWHEEL:
             wx_handler->Bind(wxEVT_MOUSEWHEEL, functor);
             bound = true;
             break;

        // --- Keyboard Events ---
        case WXD_EVENT_TYPE_KEY_DOWN:
             wx_handler->Bind(wxEVT_KEY_DOWN, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_KEY_UP:
             wx_handler->Bind(wxEVT_KEY_UP, functor);
             bound = true;
             break;
        case WXD_EVENT_TYPE_CHAR:
             wx_handler->Bind(wxEVT_CHAR, functor);
             bound = true;
             break;
             
        // ADDED: Treebook Events
        case WXD_EVENT_TYPE_TREEBOOK_PAGE_CHANGED:
            wx_handler->Bind(wxEVT_TREEBOOK_PAGE_CHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREEBOOK_PAGE_CHANGING:
            wx_handler->Bind(wxEVT_TREEBOOK_PAGE_CHANGING, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREEBOOK_NODE_EXPANDED:
            wx_handler->Bind(wxEVT_TREEBOOK_NODE_COLLAPSED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREEBOOK_NODE_COLLAPSED:
            wx_handler->Bind(wxEVT_TREEBOOK_NODE_COLLAPSED, functor);
            bound = true;
            break;
        // ADDED: SearchCtrl Events
        case WXD_EVENT_TYPE_COMMAND_SEARCHCTRL_SEARCH_BTN:
            wx_handler->Bind(wxEVT_SEARCHCTRL_SEARCH_BTN, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_COMMAND_SEARCHCTRL_CANCEL_BTN:
            wx_handler->Bind(wxEVT_SEARCHCTRL_CANCEL_BTN, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_COMMAND_HYPERLINK:
            wx_handler->Bind(wxEVT_HYPERLINK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SPINCTRLDOUBLE:
            wx_handler->Bind(wxEVT_SPINCTRLDOUBLE, functor);
            bound = true;
            break;

        // ADDED: Calendar Control Event
        case WXD_EVENT_TYPE_CALENDAR_SEL_CHANGED:
            wx_handler->Bind(wxEVT_CALENDAR_SEL_CHANGED, functor);
            bound = true;
            break;

        // ADDED: ScrollBar Events
        case WXD_EVENT_TYPE_SCROLL_TOP:
            wx_handler->Bind(wxEVT_SCROLL_TOP, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_BOTTOM:
            wx_handler->Bind(wxEVT_SCROLL_BOTTOM, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_LINEUP:
            wx_handler->Bind(wxEVT_SCROLL_LINEUP, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_LINEDOWN:
            wx_handler->Bind(wxEVT_SCROLL_LINEDOWN, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_PAGEUP:
            wx_handler->Bind(wxEVT_SCROLL_PAGEUP, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_PAGEDOWN:
            wx_handler->Bind(wxEVT_SCROLL_PAGEDOWN, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_THUMBTRACK:
            wx_handler->Bind(wxEVT_SCROLL_THUMBTRACK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_THUMBRELEASE:
            wx_handler->Bind(wxEVT_SCROLL_THUMBRELEASE, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SCROLL_CHANGED:
            wx_handler->Bind(wxEVT_SCROLL_CHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_FILEPICKER_CHANGED:
            wx_handler->Bind(wxEVT_FILEPICKER_CHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DIRPICKER_CHANGED:
            wx_handler->Bind(wxEVT_DIRPICKER_CHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_FONTPICKER_CHANGED:
            wx_handler->Bind(wxEVT_FONTPICKER_CHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_NOTIFICATION_MESSAGE_CLICK:
            wx_handler->Bind(wxEVT_NOTIFICATION_MESSAGE_CLICK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_NOTIFICATION_MESSAGE_DISMISSED:
            wx_handler->Bind(wxEVT_NOTIFICATION_MESSAGE_DISMISSED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_NOTIFICATION_MESSAGE_ACTION:
            wx_handler->Bind(wxEVT_NOTIFICATION_MESSAGE_ACTION, functor);
            bound = true;
            break;
        // MediaCtrl events
        #if wxUSE_MEDIACTRL
        case WXD_EVENT_TYPE_MEDIA_LOADED:
            wx_handler->Bind(wxEVT_MEDIA_LOADED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_MEDIA_STOP:
            wx_handler->Bind(wxEVT_MEDIA_STOP, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_MEDIA_FINISHED:
            wx_handler->Bind(wxEVT_MEDIA_FINISHED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_MEDIA_STATECHANGED:
            wx_handler->Bind(wxEVT_MEDIA_STATECHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_MEDIA_PLAY:
            wx_handler->Bind(wxEVT_MEDIA_PLAY, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_MEDIA_PAUSE:
            wx_handler->Bind(wxEVT_MEDIA_PAUSE, functor);
            bound = true;
            break;
        #endif // wxUSE_MEDIACTRL
        case WXD_EVENT_TYPE_IDLE:
            wx_handler->Bind(wxEVT_IDLE, functor);
            bound = true;
            break;
        // Drag and drop events
        case WXD_EVENT_TYPE_DROP_FILES:
            wx_handler->Bind(wxEVT_DROP_FILES, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_PAINT:
            wx_handler->Bind(wxEVT_PAINT, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TIME_CHANGED:
            wx_handler->Bind(wxEVT_TIME_CHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DESTROY:
            wx_handler->Bind(wxEVT_DESTROY, functor);
            bound = true;
            break;
        // DataView events
        case WXD_EVENT_TYPE_DATAVIEW_SELECTION_CHANGED:
            wx_handler->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_ACTIVATED:
            wx_handler->Bind(wxEVT_DATAVIEW_ITEM_ACTIVATED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EDITING_STARTED:
            wx_handler->Bind(wxEVT_DATAVIEW_ITEM_EDITING_STARTED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EDITING_DONE:
            wx_handler->Bind(wxEVT_DATAVIEW_ITEM_EDITING_DONE, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_COLLAPSING:
            wx_handler->Bind(wxEVT_DATAVIEW_ITEM_COLLAPSING, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_COLLAPSED:
            wx_handler->Bind(wxEVT_DATAVIEW_ITEM_COLLAPSED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EXPANDING:
            wx_handler->Bind(wxEVT_DATAVIEW_ITEM_EXPANDING, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EXPANDED:
            wx_handler->Bind(wxEVT_DATAVIEW_ITEM_EXPANDED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_HEADER_CLICK:
            wx_handler->Bind(wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK:
            wx_handler->Bind(wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_SORTED:
            wx_handler->Bind(wxEVT_DATAVIEW_COLUMN_SORTED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_REORDERED:
            wx_handler->Bind(wxEVT_DATAVIEW_COLUMN_REORDERED, functor);
            bound = true;
            break;

        // New TreeCtrl Event types
        case WXD_EVENT_TYPE_TREE_SEL_CHANGING:
            wx_handler->Bind(wxEVT_TREE_SEL_CHANGING, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_COLLAPSING:
            wx_handler->Bind(wxEVT_TREE_ITEM_COLLAPSING, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_COLLAPSED:
            wx_handler->Bind(wxEVT_TREE_ITEM_COLLAPSED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_EXPANDING:
            wx_handler->Bind(wxEVT_TREE_ITEM_EXPANDING, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_EXPANDED:
            wx_handler->Bind(wxEVT_TREE_ITEM_EXPANDED, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_RIGHT_CLICK:
            wx_handler->Bind(wxEVT_TREE_ITEM_RIGHT_CLICK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_MIDDLE_CLICK:
            wx_handler->Bind(wxEVT_TREE_ITEM_MIDDLE_CLICK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_KEY_DOWN:
            wx_handler->Bind(wxEVT_TREE_KEY_DOWN, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_DELETE_ITEM:
            wx_handler->Bind(wxEVT_TREE_DELETE_ITEM, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_MENU:
            wx_handler->Bind(wxEVT_TREE_ITEM_MENU, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_BEGIN_DRAG:
            wx_handler->Bind(wxEVT_TREE_BEGIN_DRAG, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_BEGIN_RDRAG:
            wx_handler->Bind(wxEVT_TREE_BEGIN_RDRAG, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_END_DRAG:
            wx_handler->Bind(wxEVT_TREE_END_DRAG, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_STATE_IMAGE_CLICK:
            wx_handler->Bind(wxEVT_TREE_STATE_IMAGE_CLICK, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TOOL_ENTER:
            wx_handler->Bind(wxEVT_TOOL_ENTER, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_TREE_ITEM_GETTOOLTIP:
            wx_handler->Bind(wxEVT_TREE_ITEM_GETTOOLTIP, functor);
            bound = true;
            break;
        // Window event types
        case WXD_EVENT_TYPE_MOVE:
            wx_handler->Bind(wxEVT_MOVE, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_ERASE:
            wx_handler->Bind(wxEVT_ERASE_BACKGROUND, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_SET_FOCUS:
            wx_handler->Bind(wxEVT_SET_FOCUS, functor);
            bound = true;
            break;
        case WXD_EVENT_TYPE_KILL_FOCUS:
            wx_handler->Bind(wxEVT_KILL_FOCUS, functor);
            bound = true;
            break;
        default:
            wxLogWarning("wxd_EvtHandler_Bind: Unsupported WXDEventTypeCEnum value %d for handler %p.", (int)eventTypeC, wx_handler);
            bound = false;
            break;
    }
    
    // Handle ownership transfer based on whether binding occurred
    if (bound) {
        // wxWidgets has taken ownership of the functor (a copy of it).
        // Mark the original functor on the stack so its destructor doesn't drop the Rust Box.
        functor.owned_by_wx = true; 
        // wxLogDebug("wxd_EvtHandler_Bind: Bound event type %d. Functor %p marked as owned by wx.", (int)eventTypeC, &functor);
    } else {
        // Binding failed (unknown event type?), functor going out of scope.
        // Its destructor will drop the Rust Box unless already marked owned (which it isn't here).
        wxLogDebug("wxd_EvtHandler_Bind: Did not bind event type %d. Functor %p destructor will drop Rust box.", (int)eventTypeC, &functor);
        // No need to explicitly call drop_rust_closure_box here, the functor destructor handles it.
    }
    // Original functor goes out of scope here.
}

// --- Event Accessors (Unchanged) ---

// Implementation for wxd_Event_GetId
wxd_Id wxd_Event_GetId(wxd_Event_t* event) {
    if (!event) return wxID_ANY;
    return ((wxEvent*)event)->GetId();
}

// Implementation for wxd_Event_GetEventObject
wxd_Window_t* wxd_Event_GetEventObject(wxd_Event_t* event) {
    if (!event) return nullptr;
    // GetEventObject returns wxObject*. We need to check if it's a window.
    wxObject* obj = ((wxEvent*)event)->GetEventObject();
    wxWindow* win = wxDynamicCast(obj, wxWindow);
    return reinterpret_cast<wxd_Window_t*>(win);
}

// ADDED: Correct signature for Skip
extern "C" void wxd_Event_Skip(wxd_Event_t* event, bool skip) {
    if (!event) return;
    ((wxEvent*)event)->Skip(skip);
}

// --- NEW: Event Data Accessors Implementation ---

// Accessors for specific event types
WXD_EXPORTED int wxd_CommandEvent_GetString(wxd_Event_t* event, char* buffer, int buffer_len) {
    wxCommandEvent* cmdEvent = wxDynamicCast((wxEvent*)event, wxCommandEvent);
    if (!cmdEvent) {
        if (buffer && buffer_len > 0) buffer[0] = '\0';
        return 0; // Return 0 if not a command event or event is null
    }
    wxString str = cmdEvent->GetString();
    size_t needed_len_no_null = wxd_cpp_utils::copy_wxstring_to_buffer(str, buffer, (size_t)buffer_len);
    return (int)(needed_len_no_null + 1); // Return required size including null terminator
}

WXD_EXPORTED bool wxd_CommandEvent_IsChecked(wxd_Event_t* event) {
    if (!event) return false;
    wxEvent* baseEvent = static_cast<wxEvent*>(static_cast<void*>(event)); // Cast via void*
    wxCommandEvent* cmdEvent = dynamic_cast<wxCommandEvent*>(baseEvent);
    if (!cmdEvent) return false; // Not a command event or derived

    return cmdEvent->IsChecked();
}

WXD_EXPORTED wxd_Point wxd_MouseEvent_GetPosition(wxd_Event_t* event) {
    wxd_Point defaultPos = { -1, -1 };
    if (!event) return defaultPos;
    wxEvent* baseEvent = static_cast<wxEvent*>(static_cast<void*>(event)); // Cast via void*
    wxMouseEvent* mouseEvent = dynamic_cast<wxMouseEvent*>(baseEvent);
    if (!mouseEvent) return defaultPos; // Not a mouse event or derived
    
    wxPoint wxPos = mouseEvent->GetPosition();
    wxd_Point pos = { wxPos.x, wxPos.y };
    return pos;
}

WXD_EXPORTED int wxd_KeyEvent_GetKeyCode(wxd_Event_t* event) {
    if (!event) return 0; 
    wxEvent* baseEvent = static_cast<wxEvent*>(static_cast<void*>(event)); // Cast via void*
    wxKeyEvent* keyEvent = dynamic_cast<wxKeyEvent*>(baseEvent);
    if (!keyEvent) return 0; // Not a key event or derived

    return keyEvent->GetKeyCode();
}

// ADDED: Implementation for wxd_CommandEvent_GetInt
WXD_EXPORTED int wxd_CommandEvent_GetInt(wxd_Event_t* event) {
    if (!event) return -1;
    wxEvent* baseEvent = static_cast<wxEvent*>(static_cast<void*>(event)); // Cast via void*
    wxCommandEvent* cmdEvent = dynamic_cast<wxCommandEvent*>(baseEvent);
    if (!cmdEvent) return -1; // Not a command event or derived

    return cmdEvent->GetInt();
}

// ADDED: Scroll Event Data Accessors
WXD_EXPORTED int wxd_ScrollEvent_GetPosition(wxd_Event_t* event) {
    if (!event) return -1; 
    wxScrollEvent* scrollEvent = wxDynamicCast((wxEvent*)event, wxScrollEvent);
    if (!scrollEvent) {
        wxScrollWinEvent* scrollWinEvent = wxDynamicCast((wxEvent*)event, wxScrollWinEvent);
        if (!scrollWinEvent) return -1;
        return scrollWinEvent->GetPosition();
    }
    return scrollEvent->GetPosition();
}

WXD_EXPORTED int wxd_ScrollEvent_GetOrientation(wxd_Event_t* event) {
    if (!event) return -1; 
    wxScrollEvent* scrollEvent = wxDynamicCast((wxEvent*)event, wxScrollEvent);
    if (!scrollEvent) {
        wxScrollWinEvent* scrollWinEvent = wxDynamicCast((wxEvent*)event, wxScrollWinEvent);
        if (!scrollWinEvent) return -1;
        return scrollWinEvent->GetOrientation();
    }
    return scrollEvent->GetOrientation();
}

// Maps our stable C enum value to wxWidgets' dynamic event types
static wxEventType get_wx_event_type_for_c_enum(WXDEventTypeCEnum c_enum_val) {
    switch (c_enum_val) {
        case WXD_EVENT_TYPE_COMMAND_BUTTON_CLICKED:
            return wxEVT_BUTTON;
        case WXD_EVENT_TYPE_CLOSE_WINDOW:
            return wxEVT_CLOSE_WINDOW;
        case WXD_EVENT_TYPE_CHECKBOX:
            return wxEVT_CHECKBOX;
        case WXD_EVENT_TYPE_TEXT:
            return wxEVT_TEXT;
        case WXD_EVENT_TYPE_TEXT_ENTER:
            return wxEVT_TEXT_ENTER;
        case WXD_EVENT_TYPE_SIZE:
            return wxEVT_SIZE;
        case WXD_EVENT_TYPE_MENU:
            return wxEVT_MENU;
        case WXD_EVENT_TYPE_LEFT_DOWN:
            return wxEVT_LEFT_DOWN;
        case WXD_EVENT_TYPE_LEFT_UP:
            return wxEVT_LEFT_UP;
        case WXD_EVENT_TYPE_MOTION:
            return wxEVT_MOTION;
        case WXD_EVENT_TYPE_MOUSEWHEEL:
            return wxEVT_MOUSEWHEEL;
        case WXD_EVENT_TYPE_KEY_DOWN:
            return wxEVT_KEY_DOWN;
        case WXD_EVENT_TYPE_KEY_UP:
            return wxEVT_KEY_UP;
        case WXD_EVENT_TYPE_CHAR:
            return wxEVT_CHAR;
        case WXD_EVENT_TYPE_COMMAND_RADIOBUTTON_SELECTED:
            return wxEVT_RADIOBUTTON;
        case WXD_EVENT_TYPE_COMMAND_RADIOBOX_SELECTED:
            return wxEVT_RADIOBOX;
        case WXD_EVENT_TYPE_COMMAND_LISTBOX_SELECTED:
            return wxEVT_LISTBOX;
        case WXD_EVENT_TYPE_COMMAND_LISTBOX_DOUBLECLICKED:
            return wxEVT_LISTBOX_DCLICK;
        case WXD_EVENT_TYPE_COMMAND_CHOICE_SELECTED:
            return wxEVT_CHOICE;
        case WXD_EVENT_TYPE_COMMAND_COMBOBOX_SELECTED:
            return wxEVT_COMBOBOX;
        case WXD_EVENT_TYPE_COMMAND_CHECKLISTBOX_SELECTED:
            return wxEVT_CHECKLISTBOX;
        case WXD_EVENT_TYPE_COMMAND_TOGGLEBUTTON_CLICKED:
            return wxEVT_TOGGLEBUTTON;
        case WXD_EVENT_TYPE_TREE_BEGIN_LABEL_EDIT:
            return wxEVT_TREE_BEGIN_LABEL_EDIT;
        case WXD_EVENT_TYPE_TREE_END_LABEL_EDIT:
            return wxEVT_TREE_END_LABEL_EDIT;
        case WXD_EVENT_TYPE_TREE_SEL_CHANGED:
            return wxEVT_TREE_SEL_CHANGED;
        case WXD_EVENT_TYPE_TREE_ITEM_ACTIVATED:
            return wxEVT_TREE_ITEM_ACTIVATED;
        case WXD_EVENT_TYPE_SLIDER:
            return wxEVT_SLIDER;
        case WXD_EVENT_TYPE_SPINCTRL:
            return wxEVT_SPINCTRL;
        case WXD_EVENT_TYPE_SPIN_UP:
            return wxEVT_SPIN_UP;
        case WXD_EVENT_TYPE_SPIN_DOWN:
            return wxEVT_SPIN_DOWN;
        case WXD_EVENT_TYPE_SPIN:
            return wxEVT_SPIN;
        case WXD_EVENT_TYPE_NOTEBOOK_PAGE_CHANGED:
            return wxEVT_NOTEBOOK_PAGE_CHANGED;
        case WXD_EVENT_TYPE_SPLITTER_SASH_POS_CHANGED:
            return wxEVT_SPLITTER_SASH_POS_CHANGED;
        case WXD_EVENT_TYPE_SPLITTER_SASH_POS_CHANGING:
            return wxEVT_SPLITTER_SASH_POS_CHANGING;
        case WXD_EVENT_TYPE_SPLITTER_DOUBLECLICKED:
            return wxEVT_SPLITTER_DOUBLECLICKED;
        case WXD_EVENT_TYPE_SPLITTER_UNSPLIT:
            return wxEVT_SPLITTER_UNSPLIT;
        case WXD_EVENT_TYPE_LIST_ITEM_SELECTED:
            return wxEVT_LIST_ITEM_SELECTED;
        case WXD_EVENT_TYPE_LIST_ITEM_ACTIVATED:
            return wxEVT_LIST_ITEM_ACTIVATED;
        case WXD_EVENT_TYPE_LIST_COL_CLICK:
            return wxEVT_LIST_COL_CLICK;
        case WXD_EVENT_TYPE_LIST_BEGIN_LABEL_EDIT:
            return wxEVT_LIST_BEGIN_LABEL_EDIT;
        case WXD_EVENT_TYPE_LIST_END_LABEL_EDIT:
            return wxEVT_LIST_END_LABEL_EDIT;
        case WXD_EVENT_TYPE_LIST_BEGIN_DRAG:
            return wxEVT_LIST_BEGIN_DRAG;
        case WXD_EVENT_TYPE_LIST_BEGIN_RDRAG:
            return wxEVT_LIST_BEGIN_RDRAG;
        case WXD_EVENT_TYPE_LIST_DELETE_ITEM:
            return wxEVT_LIST_DELETE_ITEM;
        case WXD_EVENT_TYPE_LIST_DELETE_ALL_ITEMS:
            return wxEVT_LIST_DELETE_ALL_ITEMS;
        case WXD_EVENT_TYPE_LIST_ITEM_DESELECTED:
            return wxEVT_LIST_ITEM_DESELECTED;
        case WXD_EVENT_TYPE_LIST_ITEM_FOCUSED:
            return wxEVT_LIST_ITEM_FOCUSED;
        case WXD_EVENT_TYPE_LIST_ITEM_MIDDLE_CLICK:
            return wxEVT_LIST_ITEM_MIDDLE_CLICK;
        case WXD_EVENT_TYPE_LIST_ITEM_RIGHT_CLICK:
            return wxEVT_LIST_ITEM_RIGHT_CLICK;
        case WXD_EVENT_TYPE_LIST_KEY_DOWN:
            return wxEVT_LIST_KEY_DOWN;
        case WXD_EVENT_TYPE_LIST_INSERT_ITEM:
            return wxEVT_LIST_INSERT_ITEM;
        case WXD_EVENT_TYPE_LIST_COL_RIGHT_CLICK:
            return wxEVT_LIST_COL_RIGHT_CLICK;
        case WXD_EVENT_TYPE_LIST_COL_BEGIN_DRAG:
            return wxEVT_LIST_COL_BEGIN_DRAG;
        case WXD_EVENT_TYPE_COLOURPICKER_CHANGED:
            return wxEVT_COLOURPICKER_CHANGED;
        case WXD_EVENT_TYPE_DATE_CHANGED:
            return wxEVT_DATE_CHANGED;
        case WXD_EVENT_TYPE_TREEBOOK_PAGE_CHANGED:
            return wxEVT_TREEBOOK_PAGE_CHANGED;
        case WXD_EVENT_TYPE_TREEBOOK_PAGE_CHANGING:
            return wxEVT_TREEBOOK_PAGE_CHANGING;
        case WXD_EVENT_TYPE_TREEBOOK_NODE_EXPANDED:
            return wxEVT_TREEBOOK_NODE_COLLAPSED;
        case WXD_EVENT_TYPE_TREEBOOK_NODE_COLLAPSED:
            return wxEVT_TREEBOOK_NODE_COLLAPSED;
        case WXD_EVENT_TYPE_COMMAND_SEARCHCTRL_SEARCH_BTN:
            return wxEVT_SEARCHCTRL_SEARCH_BTN;
        case WXD_EVENT_TYPE_COMMAND_SEARCHCTRL_CANCEL_BTN:
            return wxEVT_SEARCHCTRL_CANCEL_BTN;
        case WXD_EVENT_TYPE_COMMAND_HYPERLINK:
            return wxEVT_HYPERLINK;
        case WXD_EVENT_TYPE_SPINCTRLDOUBLE:
            return wxEVT_SPINCTRLDOUBLE;
        case WXD_EVENT_TYPE_CALENDAR_SEL_CHANGED:
            return wxEVT_CALENDAR_SEL_CHANGED;
        case WXD_EVENT_TYPE_SCROLL_TOP:
            return wxEVT_SCROLL_TOP;
        case WXD_EVENT_TYPE_SCROLL_BOTTOM:
            return wxEVT_SCROLL_BOTTOM;
        case WXD_EVENT_TYPE_SCROLL_LINEUP:
            return wxEVT_SCROLL_LINEUP;
        case WXD_EVENT_TYPE_SCROLL_LINEDOWN:
            return wxEVT_SCROLL_LINEDOWN;
        case WXD_EVENT_TYPE_SCROLL_PAGEUP:
            return wxEVT_SCROLL_PAGEUP;
        case WXD_EVENT_TYPE_SCROLL_PAGEDOWN:
            return wxEVT_SCROLL_PAGEDOWN;
        case WXD_EVENT_TYPE_SCROLL_THUMBTRACK:
            return wxEVT_SCROLL_THUMBTRACK;
        case WXD_EVENT_TYPE_SCROLL_THUMBRELEASE:
            return wxEVT_SCROLL_THUMBRELEASE;
        case WXD_EVENT_TYPE_SCROLL_CHANGED:
            return wxEVT_SCROLL_CHANGED;
        case WXD_EVENT_TYPE_FILEPICKER_CHANGED:
            return wxEVT_FILEPICKER_CHANGED;
        case WXD_EVENT_TYPE_DIRPICKER_CHANGED:
            return wxEVT_DIRPICKER_CHANGED;
        case WXD_EVENT_TYPE_FONTPICKER_CHANGED:
            return wxEVT_FONTPICKER_CHANGED;
        case WXD_EVENT_TYPE_NOTIFICATION_MESSAGE_CLICK:
            return wxEVT_NOTIFICATION_MESSAGE_CLICK;
        case WXD_EVENT_TYPE_NOTIFICATION_MESSAGE_DISMISSED:
            return wxEVT_NOTIFICATION_MESSAGE_DISMISSED;
        case WXD_EVENT_TYPE_NOTIFICATION_MESSAGE_ACTION:
            return wxEVT_NOTIFICATION_MESSAGE_ACTION;
        case WXD_EVENT_TYPE_MEDIA_LOADED:
            return wxEVT_MEDIA_LOADED;
        case WXD_EVENT_TYPE_MEDIA_STOP:
            return wxEVT_MEDIA_STOP;
        case WXD_EVENT_TYPE_MEDIA_FINISHED:
            return wxEVT_MEDIA_FINISHED;
        case WXD_EVENT_TYPE_MEDIA_STATECHANGED:
            return wxEVT_MEDIA_STATECHANGED;
        case WXD_EVENT_TYPE_MEDIA_PLAY:
            return wxEVT_MEDIA_PLAY;
        case WXD_EVENT_TYPE_MEDIA_PAUSE:
            return wxEVT_MEDIA_PAUSE;
        case WXD_EVENT_TYPE_IDLE:
            return wxEVT_IDLE;
        case WXD_EVENT_TYPE_DROP_FILES:
            return wxEVT_DROP_FILES;
        case WXD_EVENT_TYPE_PAINT:
            return wxEVT_PAINT;
        case WXD_EVENT_TYPE_TIME_CHANGED:
            return wxEVT_TIME_CHANGED;
        case WXD_EVENT_TYPE_DESTROY:
            return wxEVT_DESTROY;
        case WXD_EVENT_TYPE_DATAVIEW_SELECTION_CHANGED:
            return wxEVT_DATAVIEW_SELECTION_CHANGED;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_ACTIVATED:
            return wxEVT_DATAVIEW_ITEM_ACTIVATED;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EDITING_STARTED:
            return wxEVT_DATAVIEW_ITEM_EDITING_STARTED;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EDITING_DONE:
            return wxEVT_DATAVIEW_ITEM_EDITING_DONE;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_COLLAPSING:
            return wxEVT_DATAVIEW_ITEM_COLLAPSING;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_COLLAPSED:
            return wxEVT_DATAVIEW_ITEM_COLLAPSED;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EXPANDING:
            return wxEVT_DATAVIEW_ITEM_EXPANDING;
        case WXD_EVENT_TYPE_DATAVIEW_ITEM_EXPANDED:
            return wxEVT_DATAVIEW_ITEM_EXPANDED;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_HEADER_CLICK:
            return wxEVT_DATAVIEW_COLUMN_HEADER_CLICK;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK:
            return wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_SORTED:
            return wxEVT_DATAVIEW_COLUMN_SORTED;
        case WXD_EVENT_TYPE_DATAVIEW_COLUMN_REORDERED:
            return wxEVT_DATAVIEW_COLUMN_REORDERED;
        case WXD_EVENT_TYPE_TREE_SEL_CHANGING:
            return wxEVT_TREE_SEL_CHANGING;
        case WXD_EVENT_TYPE_TREE_ITEM_COLLAPSING:
            return wxEVT_TREE_ITEM_COLLAPSING;
        case WXD_EVENT_TYPE_TREE_ITEM_COLLAPSED:
            return wxEVT_TREE_ITEM_COLLAPSED;
        case WXD_EVENT_TYPE_TREE_ITEM_EXPANDING:
            return wxEVT_TREE_ITEM_EXPANDING;
        case WXD_EVENT_TYPE_TREE_ITEM_EXPANDED:
            return wxEVT_TREE_ITEM_EXPANDED;
        case WXD_EVENT_TYPE_TREE_ITEM_RIGHT_CLICK:
            return wxEVT_TREE_ITEM_RIGHT_CLICK;
        case WXD_EVENT_TYPE_TREE_ITEM_MIDDLE_CLICK:
            return wxEVT_TREE_ITEM_MIDDLE_CLICK;
        case WXD_EVENT_TYPE_TREE_KEY_DOWN:
            return wxEVT_TREE_KEY_DOWN;
        case WXD_EVENT_TYPE_TREE_DELETE_ITEM:
            return wxEVT_TREE_DELETE_ITEM;
        case WXD_EVENT_TYPE_TREE_ITEM_MENU:
            return wxEVT_TREE_ITEM_MENU;
        case WXD_EVENT_TYPE_TREE_BEGIN_DRAG:
            return wxEVT_TREE_BEGIN_DRAG;
        case WXD_EVENT_TYPE_TREE_BEGIN_RDRAG:
            return wxEVT_TREE_BEGIN_RDRAG;
        case WXD_EVENT_TYPE_TREE_END_DRAG:
            return wxEVT_TREE_END_DRAG;
        case WXD_EVENT_TYPE_TREE_STATE_IMAGE_CLICK:
            return wxEVT_TREE_STATE_IMAGE_CLICK;
        case WXD_EVENT_TYPE_TOOL_ENTER:
            return wxEVT_TOOL_ENTER;
        case WXD_EVENT_TYPE_TREE_ITEM_GETTOOLTIP:
            return wxEVT_TREE_ITEM_GETTOOLTIP;
        // Window event types
        case WXD_EVENT_TYPE_MOVE:
            return wxEVT_MOVE;
        case WXD_EVENT_TYPE_ERASE:
            return wxEVT_ERASE_BACKGROUND;
        case WXD_EVENT_TYPE_SET_FOCUS:
            return wxEVT_SET_FOCUS;
        case WXD_EVENT_TYPE_KILL_FOCUS:
            return wxEVT_KILL_FOCUS;
        default:
            wxLogWarning("Unknown WXDEventTypeCEnum value: %d", static_cast<int>(c_enum_val));
            return wxEVT_NULL;
    }
}

// Function to convert a generic wxEvent* to a wxd_Event_t* (which is also wxEvent*),
// but potentially casting to a more specific wx derived event type if known and safe.
// This is primarily for potential future use or debugging; for now, it's mostly identity.
wxd_Event_t* convert_wx_event_to_wxd_event(wxEvent* event) {
    if (!event) return nullptr;

    wxEventType type = event->GetEventType();

    // Current guideline: The C-API `wxd_Event_t` is an opaque `wxEvent*`.
    // Specific event data access (e.g., `wxd_CommandEvent_GetString`) will perform
    // the necessary cast from `wxd_Event_t*` (which is a wxEvent*) to the correct `wx...Event*`.
    // So, this function can generally just return the event pointer as is.
    // The main purpose of checking types here is for potential sanity checks or future needs
    // if we wanted this function to do more aggressive casting, but it's not strictly needed
    // for the current accessor pattern.

    if (type == wxEVT_NULL) return nullptr; // Should not happen for valid events

    // Most events, including wxCommandEvent and its many derivatives (wxButton, wxTextCtrl, wxChoice,
    // wxDateEvent, wxCalendarEvent, wxTreeEvent, wxNotebookEvent, wxSpinEvent, wxColourPickerEvent etc.)
    // will be covered by IsCommandEvent() or are other common event types.
    // We can simply return the event as wxd_Event_t* (which is an opaque wxEvent*).
    // The specific accessor functions (e.g., wxd_CommandEvent_GetString, wxd_MouseEvent_GetPosition)
    // are responsible for casting to the correct wx...Event type from wxd_Event_t*.

    // No complex casting logic needed here for now. Return the opaque pointer.
    return reinterpret_cast<wxd_Event_t*>(event);
}

// DataView event accessor implementations
WXD_EXPORTED bool wxd_DataViewEvent_GetColumn(wxd_Event_t* event, int32_t* column) {
    if (!event || !column) return false;
    
    wxDataViewEvent* dvEvent = wxDynamicCast((wxEvent*)event, wxDataViewEvent);
    if (!dvEvent) return false;
    
    *column = dvEvent->GetColumn();
    return true;
}

WXD_EXPORTED bool wxd_DataViewEvent_GetRow(wxd_Event_t* event, int64_t* row) {
    if (!event || !row) return false;
    
    wxDataViewEvent* dvEvent = wxDynamicCast((wxEvent*)event, wxDataViewEvent);
    if (!dvEvent) return false;
    
    // wxDataViewEvent doesn't have a GetRow method in all wxWidgets versions
    // Instead, we'll return -1 to indicate row is not available
    *row = -1;
    return false; // Return false to indicate this information is not available
}

WXD_EXPORTED bool wxd_DataViewEvent_GetValue(wxd_Event_t* event, wxd_Variant_t* value) {
    if (!event || !value) return false;
    
    wxDataViewEvent* dvEvent = wxDynamicCast((wxEvent*)event, wxDataViewEvent);
    if (!dvEvent) return false;
    
    // Get the wxVariant from the event
    const wxVariant& wxVar = dvEvent->GetValue();
    
    // Convert wxVariant to wxd_Variant_t
    if (wxVar.IsNull()) {
        value->type = WXD_VARIANT_TYPE_INVALID;
        return true;
    }
    
    if (wxVar.GetType() == "bool") {
        value->type = WXD_VARIANT_TYPE_BOOL;
        value->data.bool_val = wxVar.GetBool();
    }
    else if (wxVar.GetType() == "long") {
        value->type = WXD_VARIANT_TYPE_INT32;
        value->data.int32_val = wxVar.GetLong();
    }
    else if (wxVar.GetType() == "longlong") {
        value->type = WXD_VARIANT_TYPE_INT64;
        value->data.int64_val = wxVar.GetLongLong().GetValue();
    }
    else if (wxVar.GetType() == "double") {
        value->type = WXD_VARIANT_TYPE_DOUBLE;
        value->data.double_val = wxVar.GetDouble();
    }
    else if (wxVar.GetType() == "string") {
        value->type = WXD_VARIANT_TYPE_STRING;
        const wxString& str = wxVar.GetString();
        // Use strdup directly instead of wxd_cpp_utils::cpp_strdup
        // Note: Caller is responsible for freeing this memory with wxd_Variant_Free
        value->data.string_val = strdup(str.utf8_str());
    }
    else if (wxVar.GetType() == "datetime") {
        value->type = WXD_VARIANT_TYPE_DATETIME;
        const wxDateTime& dt = wxVar.GetDateTime();
        wxd_DateTime_t& dt_out = value->data.datetime_val;
        dt_out.day = dt.GetDay();
        dt_out.month = dt.GetMonth() + 1; // wxDateTime months are 0-based
        dt_out.year = dt.GetYear();
        dt_out.hour = dt.GetHour();
        dt_out.minute = dt.GetMinute();
        dt_out.second = dt.GetSecond();
    }
    else {
        // Unsupported type
        value->type = WXD_VARIANT_TYPE_INVALID;
        return false;
    }
    
    return true;
}

WXD_EXPORTED bool wxd_DataViewEvent_SetValue(wxd_Event_t* event, const wxd_Variant_t* value) {
    if (!event || !value) return false;
    
    wxDataViewEvent* dvEvent = wxDynamicCast((wxEvent*)event, wxDataViewEvent);
    if (!dvEvent) return false;
    
    wxVariant wxVar;
    
    // Convert wxd_Variant_t to wxVariant
    switch (value->type) {
        case WXD_VARIANT_TYPE_BOOL:
            wxVar = wxVariant(value->data.bool_val);
            break;
        case WXD_VARIANT_TYPE_INT32:
            wxVar = wxVariant((long)value->data.int32_val);
            break;
        case WXD_VARIANT_TYPE_INT64:
            wxVar = wxVariant(wxLongLong(value->data.int64_val));
            break;
        case WXD_VARIANT_TYPE_DOUBLE:
            wxVar = wxVariant(value->data.double_val);
            break;
        case WXD_VARIANT_TYPE_STRING:
            if (value->data.string_val) {
                wxVar = wxVariant(wxString::FromUTF8(value->data.string_val));
            } else {
                wxVar = wxVariant(wxString());
            }
            break;
        case WXD_VARIANT_TYPE_DATETIME: {
            const wxd_DateTime_t& dt = value->data.datetime_val;
            wxDateTime wxDt;
            wxDt.Set(
                dt.day,
                static_cast<wxDateTime::Month>(dt.month - 1), // wxDateTime months are 0-based
                dt.year,
                dt.hour,
                dt.minute,
                dt.second
            );
            wxVar = wxVariant(wxDt);
            break;
        }
        default:
            // Unsupported type
            return false;
    }
    
    dvEvent->SetValue(wxVar);
    return true;
}

WXD_EXPORTED bool wxd_DataViewEvent_IsEditCancelled(wxd_Event_t* event) {
    if (!event) return false;
    
    wxDataViewEvent* dvEvent = wxDynamicCast((wxEvent*)event, wxDataViewEvent);
    if (!dvEvent) return false;
    
    return dvEvent->IsEditCancelled();
}

// --- Tree Event Data Accessors ---

// Helper to convert wxTreeItemId to wxd_TreeItemId_t*
// wxTreeItemId internally is just a void* (m_pItem)
static wxd_TreeItemId_t* to_wxd_tree_item_id(const wxTreeItemId& wx_id) {
    if (!wx_id.IsOk()) {
        return nullptr;
    }
    // Directly cast the internal void* to the opaque wxd_TreeItemId_t*
    // Rust will treat this as an opaque pointer.
    return (wxd_TreeItemId_t*)wx_id.m_pItem;
}

wxd_TreeItemId_t* wxd_TreeEvent_GetItem(wxd_Event_t* self) {
    if (!self) return nullptr;
    wxTreeEvent* event = dynamic_cast<wxTreeEvent*>((wxEvent*)self);
    if (!event) return nullptr;
    wxTreeItemId item = event->GetItem();
    if (!item.IsOk()) return nullptr;
    return (wxd_TreeItemId_t*)new wxTreeItemId(item);
}

// Remove WXD_API and use correct wxd_Event_t type
wxd_TreeItemId_t* wxd_TreeEvent_GetOldItem(wxd_Event_t* self) {
    if (!self) return nullptr;
    wxTreeEvent* event = dynamic_cast<wxTreeEvent*>((wxEvent*)self);
    if (!event) return nullptr;
    wxTreeItemId item = event->GetOldItem();
    if (!item.IsOk()) return nullptr;
    return (wxd_TreeItemId_t*)new wxTreeItemId(item);
}

// And restore original signature and logic for GetLabel
const char* wxd_TreeEvent_GetLabel(wxd_Event_t* self) {
    if (!self) return "";
    wxTreeEvent* event = dynamic_cast<wxTreeEvent*>((wxEvent*)self);
    if (!event) return "";
    // return WXD_WX_STRING_TO_CHAR_PTR_UTF8(event->GetLabel()); // Macro causing issues
    return event->GetLabel().ToUTF8().data(); // Inline the macro's logic
}

// Restore IsEditCancelled
int wxd_TreeEvent_IsEditCancelled(wxd_Event_t* self) {
    if (!self) return 1; // Default to cancelled if event is bad (true as int)
    wxTreeEvent* event = dynamic_cast<wxTreeEvent*>((wxEvent*)self);
    if (!event) return 1; // Default to cancelled if cast fails
    return event->IsEditCancelled() ? 1 : 0;
}

// Function to free wxd_TreeItemId_t (called from Rust via TreeItemId::drop)
// ... existing code ...

wxd_DateTime_t* wxd_CalendarEvent_GetDate(wxd_Event_t* event_ptr) {
    if (!event_ptr) return nullptr;
    wxEvent* wx_event = static_cast<wxEvent*>(event_ptr->event);
    if (wx_event->IsCommandEvent()) { // wxCalendarEvent derives from wxDateEvent from wxCommandEvent
        wxCalendarEvent* cal_event = dynamic_cast<wxCalendarEvent*>(wx_event);
        if (cal_event) {
             const wxDateTime& dt = cal_event->GetDate();
             if (dt.IsValid()) {
                // Create a new wxd_DateTime_t on the heap. Rust side (DateTime::from_raw)
                // will take ownership and be responsible for freeing it.
                return new wxd_DateTime_t{
                    (short)dt.GetDay(),
                    (unsigned short)(dt.GetMonth() + 1), // wxDateTime::Month is 0-indexed
                    dt.GetYear(),
                    (short)dt.GetHour(),
                    (short)dt.GetMinute(),
                    (short)dt.GetSecond()
                };
             }
        }
    }
    return nullptr;
}

// Function to get the underlying wxEvent* (for casting or direct use in C++ if absolutely necessary)
// ... existing code ...