use crate::bitmap::Bitmap; use crate::geometry::{Point, Size};
use crate::id::ID_ANY;
use crate::id::Id;
use crate::menus::MenuBar; use crate::widgets::statusbar::StatusBar; use crate::widgets::toolbar::{ToolBar, ToolBarStyle}; use crate::window::{WindowHandle, WxWidget};
#[allow(unused_imports)]
use crate::window::Window;
use std::default::Default;
use std::ffi::CString;
use std::marker::PhantomData;
use std::os::raw::c_int; use std::ptr;
use wxdragon_sys as ffi;
widget_style_enum!(
name: FrameStyle,
doc: "Window style flags for Frame.",
variants: {
Default: ffi::WXD_DEFAULT_FRAME_STYLE, "Includes `wxCAPTION`, `wxRESIZE_BORDER`, `wxSYSTEM_MENU`, `wxMINIMIZE_BOX`, `wxMAXIMIZE_BOX`, `wxCLOSE_BOX`. This is the default style.",
Caption: ffi::WXD_CAPTION, "Displays a title bar.",
ResizeBorder: ffi::WXD_RESIZE_BORDER, "Displays a resizeable border.",
SystemMenu: ffi::WXD_SYSTEM_MENU, "Displays a system menu.",
CloseBox: ffi::WXD_CLOSE_BOX, "Displays a close box.",
MaximizeBox: ffi::WXD_MAXIMIZE_BOX, "Displays a maximize box.",
MinimizeBox: ffi::WXD_MINIMIZE_BOX, "Displays a minimize box.",
StayOnTop: ffi::WXD_STAY_ON_TOP, "Stays on top of other windows.",
ToolWindow: ffi::WXD_FRAME_TOOL_WINDOW, "Tool window style (typically a thin border and title bar).",
NoTaskbar: ffi::WXD_FRAME_NO_TASKBAR, "No taskbar button (Windows only).",
FloatOnParent: ffi::WXD_FRAME_FLOAT_ON_PARENT, "Equivalent to StayOnTop for frames.",
ClipChildren: ffi::WXD_CLIP_CHILDREN, "Clip children to the frame."
},
default_variant: Default
);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UserAttentionFlag {
Info,
Error,
}
impl UserAttentionFlag {
fn as_raw(self) -> i32 {
match self {
UserAttentionFlag::Info => ffi::WXD_USER_ATTENTION_INFO as i32,
UserAttentionFlag::Error => ffi::WXD_USER_ATTENTION_ERROR as i32,
}
}
}
#[derive(Clone, Copy)]
pub struct Frame {
handle: WindowHandle,
#[allow(dead_code)]
parent_ptr: *mut ffi::wxd_Window_t,
_marker: PhantomData<()>,
}
pub struct FrameBuilder {
parent_ptr: *mut ffi::wxd_Window_t, id: Id,
title: String,
pos: Point,
size: Size,
style: FrameStyle,
}
impl Default for FrameBuilder {
fn default() -> Self {
Self {
parent_ptr: ptr::null_mut(),
id: ID_ANY as i32, title: "wxDragon Frame".to_string(), pos: Point::DEFAULT_POSITION, size: Size { width: 500, height: 400 }, style: FrameStyle::Default,
}
}
}
impl FrameBuilder {
pub fn with_parent(mut self, parent: &impl WxWidget) -> Self {
self.parent_ptr = parent.handle_ptr();
self
}
pub fn with_id(mut self, id: Id) -> Self {
self.id = id;
self
}
pub fn with_title(mut self, title: &str) -> Self {
self.title = title.to_string();
self
}
pub fn with_position(mut self, pos: Point) -> Self {
self.pos = pos;
self
}
pub fn with_size(mut self, size: Size) -> Self {
self.size = size;
self
}
pub fn with_style(mut self, style: FrameStyle) -> Self {
self.style = style;
self
}
pub fn build(self) -> Frame {
let c_title = CString::new(self.title).expect("CString::new failed for title");
let ptr = unsafe {
ffi::wxd_Frame_Create(
self.parent_ptr,
self.id,
c_title.as_ptr(),
self.pos.into(),
self.size.into(),
self.style.bits() as ffi::wxd_Style_t,
)
};
if ptr.is_null() {
panic!("Failed to create wxFrame: wxWidgets returned a null pointer.");
} else {
Frame {
handle: WindowHandle::new(ptr as *mut ffi::wxd_Window_t),
parent_ptr: self.parent_ptr,
_marker: PhantomData,
}
}
}
}
impl Frame {
pub fn builder() -> FrameBuilder {
FrameBuilder::default()
}
#[allow(dead_code)]
pub(crate) fn new_from_composition(_window: Window, _parent_ptr: *mut ffi::wxd_Window_t) -> Self {
Self {
handle: WindowHandle::new(_window.as_ptr()),
parent_ptr: _parent_ptr,
_marker: PhantomData,
}
}
#[inline]
fn frame_ptr(&self) -> *mut ffi::wxd_Frame_t {
self.handle
.get_ptr()
.map(|p| p as *mut ffi::wxd_Frame_t)
.unwrap_or(std::ptr::null_mut())
}
pub fn window_handle(&self) -> WindowHandle {
self.handle
}
pub fn set_title(&self, title: &str) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
let title_c = CString::new(title).expect("CString::new failed");
unsafe { ffi::wxd_Frame_SetTitle(ptr, title_c.as_ptr()) };
}
pub fn centre(&self) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_Centre(ptr, ffi::WXD_ALIGN_CENTRE as i32) };
}
pub fn center_on_screen(&self) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_CenterOnScreen(ptr) }
}
pub fn show(&self, show: bool) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_Show(ptr, show) };
}
pub fn set_menu_bar(&self, menu_bar: MenuBar) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
let menu_bar_ptr = unsafe { menu_bar.as_ptr() };
unsafe { ffi::wxd_Frame_SetMenuBar(ptr, menu_bar_ptr) };
}
pub fn get_menu_bar(&self) -> Option<MenuBar> {
let ptr = self.frame_ptr();
if ptr.is_null() {
return None;
}
let menu_bar_ptr = unsafe { ffi::wxd_Frame_GetMenuBar(ptr) };
if menu_bar_ptr.is_null() {
None
} else {
Some(unsafe { MenuBar::from_ptr(menu_bar_ptr) })
}
}
pub fn close(&self, force: bool) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_Close(ptr, force) };
}
pub fn set_existing_status_bar(&self, status_bar: Option<&StatusBar>) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
let sb_ptr = status_bar.map_or(ptr::null_mut(), |sb| sb.as_ptr() as *mut _);
unsafe { ffi::wxd_Frame_SetStatusBar(ptr, sb_ptr) };
}
pub fn create_tool_bar(&self, style: Option<ToolBarStyle>, id: Id) -> Option<ToolBar> {
let ptr = self.frame_ptr();
if ptr.is_null() {
return None;
}
let style_bits = style.map(|s| s.bits()).unwrap_or(ToolBarStyle::default().bits());
let tb_ptr = unsafe { ffi::wxd_Frame_CreateToolBar(ptr, style_bits as ffi::wxd_Style_t, id) };
if tb_ptr.is_null() {
None
} else {
Some(unsafe { ToolBar::from_ptr(tb_ptr) })
}
}
pub fn create_status_bar(&self, number: i32, style: i64, id: Id, name: &str) -> StatusBar {
let ptr = self.frame_ptr();
if ptr.is_null() {
return unsafe { StatusBar::from_ptr(ptr::null_mut()) };
}
unsafe {
let name_c = CString::new(name).unwrap_or_default();
let statbar_ptr =
ffi::wxd_Frame_CreateStatusBar(ptr, number as c_int, style as ffi::wxd_Style_t, id, name_c.as_ptr());
StatusBar::from_ptr(statbar_ptr)
}
}
pub fn set_status_text(&self, text: &str, number: i32) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
let c_text = CString::new(text).expect("CString::new for status text failed");
unsafe { ffi::wxd_Frame_SetStatusText(ptr, c_text.as_ptr(), number) }
}
pub fn get_title(&self) -> String {
let ptr = self.frame_ptr();
if ptr.is_null() {
return String::new();
}
let c_title_ptr = unsafe { ffi::wxd_Frame_GetTitle(ptr) };
if c_title_ptr.is_null() {
return String::new(); }
unsafe {
CString::from_raw(c_title_ptr)
.into_string()
.unwrap_or_else(|_| String::from("Error converting title"))
}
}
pub fn iconize(&self, iconize: bool) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_Iconize(ptr, iconize) }
}
pub fn is_iconized(&self) -> bool {
let ptr = self.frame_ptr();
if ptr.is_null() {
return false;
}
unsafe { ffi::wxd_Frame_IsIconized(ptr) }
}
pub fn maximize(&self, maximize: bool) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_Maximize(ptr, maximize) }
}
pub fn is_maximized(&self) -> bool {
let ptr = self.frame_ptr();
if ptr.is_null() {
return false;
}
unsafe { ffi::wxd_Frame_IsMaximized(ptr) }
}
pub fn set_icon(&self, bitmap: &Bitmap) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_SetIconFromBitmap(ptr, bitmap.as_const_ptr()) };
}
pub fn request_user_attention(&self, flags: UserAttentionFlag) {
let ptr = self.frame_ptr();
if ptr.is_null() {
return;
}
unsafe { ffi::wxd_Frame_RequestUserAttention(ptr, flags.as_raw()) }
}
}
impl Frame {
pub(crate) fn bind_window_event<F>(&self, event_type: crate::event::EventType, handler: F)
where
F: FnMut(crate::event::Event) + 'static,
{
<Self as crate::event::WxEvtHandler>::bind_internal(self, event_type, handler);
}
pub fn on_menu<F>(&self, handler: F)
where
F: FnMut(crate::event::Event) + 'static,
{
self.bind_window_event(crate::event::EventType::MENU, handler);
}
pub fn track_menu_lifecycle<F>(&self, callback: F)
where
F: Fn(&str, bool) + 'static, {
use crate::event::MenuEvents;
let callback_ref = std::rc::Rc::new(callback);
let callback_open = {
let cb = callback_ref.clone();
move |_: crate::event::MenuEventData| cb("menu_open", true)
};
let callback_close = {
let cb = callback_ref.clone();
move |_: crate::event::MenuEventData| cb("menu_close", false)
};
self.on_menu_opened(callback_open);
self.on_menu_closed(callback_close);
}
}
impl WxWidget for Frame {
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 crate::event::WxEvtHandler for Frame {
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 Frame {}
impl crate::event::MenuEvents for Frame {}
#[cfg(feature = "xrc")]
impl crate::xrc::XrcSupport for Frame {
unsafe fn from_xrc_ptr(ptr: *mut wxdragon_sys::wxd_Window_t) -> Self {
Frame {
handle: WindowHandle::new(ptr),
parent_ptr: std::ptr::null_mut(),
_marker: PhantomData,
}
}
}
impl crate::window::FromWindowWithClassName for Frame {
fn class_name() -> &'static str {
"wxFrame"
}
unsafe fn from_ptr(ptr: *mut ffi::wxd_Window_t) -> Self {
Frame {
handle: WindowHandle::new(ptr),
parent_ptr: std::ptr::null_mut(),
_marker: PhantomData,
}
}
}