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
use crate::dialogs::Dialog;
use crate::widgets::{Frame, Panel};
use crate::window::WxWidget;
use std::ffi::CString;
use std::marker::PhantomData;
use std::ptr;
use wxdragon_sys as ffi;
/// Represents the global wxXmlResource object.
#[derive(Clone)] // Cloning just copies the pointer to the singleton.
pub struct XmlResource {
ptr: *mut ffi::wxd_XmlResource_t,
// Ensures that XmlResource is !Send and !Sync if wxXmlResource is not thread-safe,
// which is typical for GUI singletons.
_phantom: PhantomData<*mut ()>,
}
impl XmlResource {
/// Get the global wxXmlResource instance
pub fn get() -> Self {
Self {
ptr: unsafe { ffi::wxd_XmlResource_Get() },
_phantom: PhantomData,
}
}
/// Initialize all standard handlers (idempotent)
pub fn init_all_handlers(&self) {
unsafe {
ffi::wxd_XmlResource_InitAllHandlers(self.ptr);
}
}
/// Initialize platform-aware StaticBitmap handler for XRC files
///
/// This should be called after `init_all_handlers()` and before loading XRC files.
/// It registers a custom handler that automatically creates the appropriate StaticBitmap
/// implementation based on the platform:
///
/// - **Windows**: Creates `wxGenericStaticBitmap` for proper scaling support (fixes scaling issues)
/// - **macOS/Linux**: Creates native `wxStaticBitmap` for optimal performance
///
/// This is automatically called by the `include_xrc!` macro, so users typically don't
/// need to call this directly. XRC files can continue to use `<object class="wxStaticBitmap">`
/// and the correct implementation will be created transparently.
///
/// # Note
/// Only available when the `xrc` feature is enabled. When XRC is disabled, this function
/// does nothing.
pub fn init_platform_aware_staticbitmap_handler(&self) {
unsafe {
ffi::wxd_XmlResource_InitPlatformAwareStaticBitmapHandler(self.ptr);
}
}
/// Load XRC from file
pub fn load_from_file(&self, filename: &str) -> Result<(), String> {
let c_filename = CString::new(filename).map_err(|_| "Invalid filename")?;
let success = unsafe { ffi::wxd_XmlResource_LoadFromFile(self.ptr, c_filename.as_ptr()) };
if success {
Ok(())
} else {
Err(format!("Failed to load XRC file: {filename}"))
}
}
/// Load XRC from string data
pub fn load_from_string(&self, xrc_data: &str) -> Result<(), String> {
let c_data = CString::new(xrc_data).map_err(|_| "Invalid XRC data")?;
let success = unsafe { ffi::wxd_XmlResource_LoadFromString(self.ptr, c_data.as_ptr()) };
if success {
Ok(())
} else {
Err("Failed to load XRC from string".to_string())
}
}
/// Load a dialog from XRC
pub fn load_dialog(&self, parent: Option<&dyn WxWidget>, name: &str) -> Option<Dialog> {
let c_name = CString::new(name).ok()?;
let parent_ptr = parent.map_or(ptr::null_mut(), |p| p.handle_ptr());
let dialog_ptr = unsafe { ffi::wxd_XmlResource_LoadDialog(self.ptr, parent_ptr, c_name.as_ptr()) };
if dialog_ptr.is_null() {
None
} else {
Some(unsafe { Dialog::from_xrc_ptr(dialog_ptr) })
}
}
/// Load a frame from XRC
pub fn load_frame(&self, parent: Option<&dyn WxWidget>, name: &str) -> Option<Frame> {
let c_name = CString::new(name).ok()?;
let parent_ptr = parent.map_or(ptr::null_mut(), |p| p.handle_ptr());
let frame_ptr = unsafe { ffi::wxd_XmlResource_LoadFrame(self.ptr, parent_ptr, c_name.as_ptr()) };
if frame_ptr.is_null() {
None
} else {
Some(unsafe { <Frame as FromXrcPtr>::from_xrc_ptr(frame_ptr as *mut ffi::wxd_Window_t) })
}
}
/// Load a panel from XRC
pub fn load_panel(&self, parent: Option<&dyn WxWidget>, name: &str) -> Option<Panel> {
let c_name = CString::new(name).ok()?;
let parent_ptr = parent.map_or(ptr::null_mut(), |p| p.handle_ptr());
let panel_ptr = unsafe { ffi::wxd_XmlResource_LoadPanel(self.ptr, parent_ptr, c_name.as_ptr()) };
if panel_ptr.is_null() {
None
} else {
Some(unsafe { <Panel as FromXrcPtr>::from_xrc_ptr(panel_ptr as *mut ffi::wxd_Window_t) })
}
}
/// Get XRC ID for a control name
pub fn get_xrc_id(name: &str) -> i32 {
let c_name = CString::new(name).unwrap_or_default();
unsafe { ffi::wxd_XmlResource_GetXRCID(c_name.as_ptr()) }
}
/// Returns the raw pointer.
/// # Safety
/// The caller must ensure the pointer is used correctly.
pub(crate) unsafe fn as_ptr(&self) -> *mut ffi::wxd_XmlResource_t {
self.ptr
}
}
/// Trait for creating widgets from XRC-managed pointers
pub trait FromXrcPtr {
type RawFfiType;
/// Create a widget wrapper from an XRC-managed pointer
/// The widget does not own the pointer - XRC manages its lifetime
///
/// # Safety
/// The caller must ensure the pointer is valid and points to the correct widget type.
unsafe fn from_xrc_ptr(ptr: Self::RawFfiType) -> Self;
}
/// Trait for widgets that support XRC loading
/// Widgets implement this trait to provide XRC support with their specific structure
pub trait XrcSupport: WxWidget + Sized {
/// Creates a widget wrapper for an XRC-managed object.
/// This widget will not be destroyed when dropped as it's managed by XRC.
/// Each widget implements this with their specific field structure.
///
/// # Safety
/// The caller must ensure the pointer is valid and points to the correct widget type.
unsafe fn from_xrc_ptr(ptr: *mut ffi::wxd_Window_t) -> Self;
}
/// Automatically implement FromXrcPtr for any widget that implements XrcSupport
impl<T: XrcSupport> FromXrcPtr for T {
type RawFfiType = *mut ffi::wxd_Window_t;
unsafe fn from_xrc_ptr(ptr: Self::RawFfiType) -> Self {
unsafe { T::from_xrc_ptr(ptr) }
}
}
/// Trait for XRC-specific window methods
pub trait WindowXrcMethods: WxWidget + Sized {
/// Find a child window by XRC name
fn find_child_by_xrc_name<T: FromXrcPtr<RawFfiType = *mut ffi::wxd_Window_t> + WxWidget>(&self, name: &str) -> Option<T> {
let c_name = CString::new(name).ok()?;
let child_ptr = unsafe { ffi::wxd_Window_FindWindowByXRCName(self.handle_ptr(), c_name.as_ptr()) };
if child_ptr.is_null() {
None
} else {
Some(unsafe { T::from_xrc_ptr(child_ptr) })
}
}
}
// Implement for all WxWidget types
impl<W: WxWidget> WindowXrcMethods for W {}
// FromXrcPtr implementations are handled automatically by the implement_widget_traits_with_target! macro.