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
//! Safe wrapper for wxPanel.
use crate::event::{MenuEvents, WindowEvents, WxEvtHandler};
use crate::geometry::{Point, Size};
use crate::id::Id;
use crate::window::{WindowHandle, WxWidget};
// Window is used by new_from_composition for backwards compatibility
#[allow(unused_imports)]
use crate::window::Window;
use wxdragon_sys as ffi;
// --- Style enum using macro ---
widget_style_enum!(
name: PanelStyle,
doc: "Window style flags for Panel",
variants: {
TabTraversal: ffi::WXD_TAB_TRAVERSAL, "Allows the panel to participate in tab navigation. (Default)",
BorderNone: ffi::WXD_BORDER_NONE, "No border.",
BorderSimple: ffi::WXD_BORDER_SIMPLE, "A simple border.",
BorderRaised: ffi::WXD_BORDER_RAISED, "A raised border.",
BorderSunken: ffi::WXD_BORDER_SUNKEN, "A sunken border.",
BorderStatic: ffi::WXD_BORDER_STATIC, "A static border.",
BorderTheme: ffi::WXD_BORDER_THEME, "A theme border.",
BorderDefault: ffi::WXD_BORDER_DEFAULT, "A default border."
},
default_variant: TabTraversal
);
/// Represents a wxPanel widget.
/// Panels are windows within a frame (or other window) that can contain other widgets.
///
/// Panel uses `WindowHandle` internally for safe memory management.
/// When the underlying window is destroyed (by calling `destroy()` or when
/// its parent is destroyed), the handle becomes invalid and all operations
/// become safe no-ops.
///
/// # Example
/// ```ignore
/// let panel = Panel::builder(&frame).build();
///
/// // Panel is Copy - no clone needed for closures!
/// panel.bind_event(move |_| {
/// // Safe: if panel was destroyed, this is a no-op
/// panel.set_background_colour(Colour::white());
/// });
///
/// // After parent destruction, panel operations are safe no-ops
/// frame.destroy();
/// assert!(!panel.is_valid());
/// ```
#[derive(Clone, Copy)]
pub struct Panel {
/// Safe handle to the underlying wxPanel - automatically invalidated on destroy
handle: WindowHandle,
}
impl Panel {
/// Creates a new builder for a Panel.
pub fn builder(parent: &dyn WxWidget) -> PanelBuilder<'_> {
PanelBuilder::new(parent)
}
/// Creates a new Panel wrapper from a raw pointer.
/// # Safety
/// The pointer must be a valid `wxd_Panel_t` pointer.
/// Ownership is typically managed by the parent window in wxWidgets.
pub(crate) unsafe fn from_ptr(ptr: *mut ffi::wxd_Panel_t) -> Self {
assert!(!ptr.is_null());
Panel {
handle: WindowHandle::new(ptr as *mut ffi::wxd_Window_t),
}
}
/// Creates a new Panel from a raw window pointer.
/// This is for backwards compatibility with widgets that compose Panel.
/// The parent_ptr parameter is ignored (kept for API compatibility).
#[allow(dead_code)]
pub(crate) fn new_from_composition(_window: Window, _parent_ptr: *mut ffi::wxd_Window_t) -> Self {
// Use the window's pointer to create a new WindowHandle
Self {
handle: WindowHandle::new(_window.as_ptr()),
}
}
/// Returns the raw underlying panel pointer.
pub fn as_ptr(&self) -> *mut ffi::wxd_Panel_t {
self.handle
.get_ptr()
.map(|p| p as *mut ffi::wxd_Panel_t)
.unwrap_or(std::ptr::null_mut())
}
/// Helper to get raw panel pointer, returns null if widget has been destroyed
#[inline]
#[allow(dead_code)]
fn panel_ptr(&self) -> *mut ffi::wxd_Panel_t {
self.handle
.get_ptr()
.map(|p| p as *mut ffi::wxd_Panel_t)
.unwrap_or(std::ptr::null_mut())
}
/// Returns the underlying WindowHandle for this panel.
pub fn window_handle(&self) -> WindowHandle {
self.handle
}
}
// Manual WxWidget implementation for Panel (using WindowHandle)
impl WxWidget for Panel {
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()
}
}
// Implement WxEvtHandler for event binding
impl WxEvtHandler for Panel {
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
}
}
// Implement common event traits that all Window-based widgets support
impl WindowEvents for Panel {}
impl MenuEvents for Panel {}
// Use the widget_builder macro to generate the PanelBuilder implementation
widget_builder!(
name: Panel,
parent_type: &'a dyn WxWidget,
style_type: PanelStyle,
fields: {},
build_impl: |slf| {
let panel_ptr = unsafe {
ffi::wxd_Panel_Create(
slf.parent.handle_ptr(),
slf.id,
slf.pos.into(),
slf.size.into(),
slf.style.bits() as ffi::wxd_Style_t,
)
};
if panel_ptr.is_null() {
panic!("Failed to create Panel: FFI returned null pointer.");
}
unsafe { Panel::from_ptr(panel_ptr) }
}
);
// XRC Support - enables Panel to be created from XRC-managed pointers
#[cfg(feature = "xrc")]
impl crate::xrc::XrcSupport for Panel {
unsafe fn from_xrc_ptr(ptr: *mut ffi::wxd_Window_t) -> Self {
Panel {
handle: WindowHandle::new(ptr),
}
}
}
// Widget casting support for Panel
impl crate::window::FromWindowWithClassName for Panel {
fn class_name() -> &'static str {
"wxPanel"
}
unsafe fn from_ptr(ptr: *mut ffi::wxd_Window_t) -> Self {
Panel {
handle: WindowHandle::new(ptr),
}
}
}