use crate::dialogs::Dialog;
use crate::geometry::{Point, Size};
use crate::utils::ArrayString;
use crate::window::WxWidget;
use std::ffi::{CStr, CString};
use wxdragon_sys as ffi;
widget_style_enum!(
name: FileDialogStyle,
doc: "Style flags for FileDialog.",
variants: {
Open: ffi::WXD_FD_OPEN, "Creates an open file dialog (cannot be combined with Save).",
Save: ffi::WXD_FD_SAVE, "Creates a save file dialog (cannot be combined with Open).",
OverwritePrompt: ffi::WXD_FD_OVERWRITE_PROMPT, "For save dialog only: prompt for a confirmation if a file with the same name already exists.",
FileMustExist: ffi::WXD_FD_FILE_MUST_EXIST, "For open dialog only: the user may only select files that actually exist.",
Multiple: ffi::WXD_FD_MULTIPLE, "For open dialog only: allows selecting multiple files.",
ChangeDir: ffi::WXD_FD_CHANGE_DIR, "Change the current working directory to the directory where the file(s) chosen by the user are.",
Preview: ffi::WXD_FD_PREVIEW, "Show the preview of the selected files (currently only supported by wxGTK)."
},
default_variant: Open
);
pub type FileDialogPtr = *mut ffi::wxd_FileDialog_t;
#[derive(Clone)] pub struct FileDialog {
dialog_base: Dialog,
}
impl FileDialog {
pub fn builder<'a>(parent: &'a dyn WxWidget) -> FileDialogBuilder<'a> {
FileDialogBuilder::new(parent)
}
pub(crate) unsafe fn from_ptr(ptr: *mut ffi::wxd_FileDialog_t) -> Self {
FileDialog {
dialog_base: unsafe { Dialog::from_ptr(ptr as *mut ffi::wxd_Dialog_t) },
}
}
fn as_ptr(&self) -> FileDialogPtr {
self.dialog_base.as_ptr() as FileDialogPtr
}
pub fn show_modal(&self) -> i32 {
self.dialog_base.show_modal()
}
pub fn get_path(&self) -> Option<String> {
let mut buffer = [0; 2048]; let len = unsafe { ffi::wxd_FileDialog_GetPath(self.as_ptr(), buffer.as_mut_ptr(), buffer.len()) };
if len < 0 {
return None;
}
if len < buffer.len() as i32 {
return Some(unsafe { CStr::from_ptr(buffer.as_ptr()).to_string_lossy().to_string() });
}
let mut buf = vec![0; len as usize + 1];
let len_copied = unsafe { ffi::wxd_FileDialog_GetPath(self.as_ptr(), buf.as_mut_ptr(), buf.len()) };
if len_copied == len {
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string() })
} else {
None
}
}
pub fn get_paths(&self) -> Vec<String> {
let mut arr_str = ArrayString::new();
unsafe { ffi::wxd_FileDialog_GetPaths(self.as_ptr(), arr_str.as_mut_ptr()) };
arr_str.into()
}
pub fn get_filename(&self) -> Option<String> {
let mut buffer = [0; 1024];
let len = unsafe { ffi::wxd_FileDialog_GetFilename(self.as_ptr(), buffer.as_mut_ptr(), buffer.len()) };
if len < 0 {
return None;
}
if len < buffer.len() as i32 {
return Some(unsafe { CStr::from_ptr(buffer.as_ptr()).to_string_lossy().to_string() });
}
let mut buf = vec![0; len as usize + 1];
let len2 = unsafe { ffi::wxd_FileDialog_GetFilename(self.as_ptr(), buf.as_mut_ptr(), buf.len()) };
if len2 == len {
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string() })
} else {
None
}
}
pub fn get_filenames(&self) -> Vec<String> {
let mut arr_str = ArrayString::new();
unsafe { ffi::wxd_FileDialog_GetFilenames(self.as_ptr(), arr_str.as_mut_ptr()) };
arr_str.into()
}
pub fn get_directory(&self) -> Option<String> {
let mut buffer = [0; 2048];
let len = unsafe { ffi::wxd_FileDialog_GetDirectory(self.as_ptr(), buffer.as_mut_ptr(), buffer.len()) };
if len < 0 {
return None;
}
if len < buffer.len() as i32 {
Some(unsafe { CStr::from_ptr(buffer.as_ptr()).to_string_lossy().to_string() })
} else {
let mut buf = vec![0; len as usize + 1];
let len2 = unsafe { ffi::wxd_FileDialog_GetDirectory(self.as_ptr(), buf.as_mut_ptr(), buf.len()) };
if len2 == len {
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string() })
} else {
None
}
}
}
pub fn get_filter_index(&self) -> i32 {
unsafe { ffi::wxd_FileDialog_GetFilterIndex(self.as_ptr()) }
}
pub fn get_message(&self) -> Option<String> {
let mut buffer = [0; 1024];
let len = unsafe { ffi::wxd_FileDialog_GetMessage(self.as_ptr(), buffer.as_mut_ptr(), buffer.len()) };
if len < 0 {
return None;
}
if len < buffer.len() as i32 {
return Some(unsafe { CStr::from_ptr(buffer.as_ptr()).to_string_lossy().into_owned() });
}
let mut buf = vec![0; len as usize + 1];
let len2 = unsafe { ffi::wxd_FileDialog_GetMessage(self.as_ptr(), buf.as_mut_ptr(), buf.len()) };
if len2 == len {
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned() })
} else {
None
}
}
pub fn get_wildcard(&self) -> Option<String> {
let mut buffer = [0; 1024];
let len = unsafe { ffi::wxd_FileDialog_GetWildcard(self.as_ptr(), buffer.as_mut_ptr(), buffer.len()) };
if len < 0 {
return None;
}
if len < buffer.len() as i32 {
return Some(unsafe { CStr::from_ptr(buffer.as_ptr()).to_string_lossy().into_owned() });
}
let mut buf = vec![0; len as usize + 1];
let len2 = unsafe { ffi::wxd_FileDialog_GetWildcard(self.as_ptr(), buf.as_mut_ptr(), buf.len()) };
if len2 == len {
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned() })
} else {
None
}
}
pub fn get_currently_selected_filter_index(&self) -> i32 {
unsafe { ffi::wxd_FileDialog_GetCurrentlySelectedFilterIndex(self.as_ptr()) }
}
pub fn set_directory(&self, directory: &str) {
let c_directory = CString::new(directory).expect("CString::new failed for directory");
unsafe {
ffi::wxd_FileDialog_SetDirectory(self.as_ptr(), c_directory.as_ptr());
}
}
pub fn set_filename(&self, filename: &str) {
let c_filename = CString::new(filename).expect("CString::new failed for filename");
unsafe {
ffi::wxd_FileDialog_SetFilename(self.as_ptr(), c_filename.as_ptr());
}
}
pub fn set_filter_index(&self, filter_index: i32) {
unsafe {
ffi::wxd_FileDialog_SetFilterIndex(self.as_ptr(), filter_index);
}
}
pub fn set_message(&self, message: &str) {
let c_message = CString::new(message).expect("CString::new failed for message");
unsafe {
ffi::wxd_FileDialog_SetMessage(self.as_ptr(), c_message.as_ptr());
}
}
pub fn set_path(&self, path: &str) {
let c_path = CString::new(path).expect("CString::new failed for path");
unsafe {
ffi::wxd_FileDialog_SetPath(self.as_ptr(), c_path.as_ptr());
}
}
pub fn set_wildcard(&self, wildcard: &str) {
let c_wildcard = CString::new(wildcard).expect("CString::new failed for wildcard");
unsafe {
ffi::wxd_FileDialog_SetWildcard(self.as_ptr(), c_wildcard.as_ptr());
}
}
}
impl WxWidget for FileDialog {
fn handle_ptr(&self) -> *mut ffi::wxd_Window_t {
self.dialog_base.handle_ptr()
}
}
impl Drop for FileDialog {
fn drop(&mut self) {
}
}
pub struct FileDialogBuilder<'a> {
parent: &'a dyn WxWidget,
message: String,
default_dir: String,
default_file: String,
wildcard: String,
style: FileDialogStyle,
pos: Point,
size: Size, }
impl<'a> FileDialogBuilder<'a> {
pub fn new(parent: &'a dyn WxWidget) -> Self {
FileDialogBuilder {
parent,
message: "Choose a file".to_string(), default_dir: String::new(),
default_file: String::new(),
wildcard: "*.*".to_string(), style: FileDialogStyle::Open,
pos: Point::DEFAULT_POSITION,
size: Size::DEFAULT_SIZE,
}
}
pub fn with_message(mut self, message: &str) -> Self {
self.message = message.to_string();
self
}
pub fn with_default_dir(mut self, dir: &str) -> Self {
self.default_dir = dir.to_string();
self
}
pub fn with_default_file(mut self, file: &str) -> Self {
self.default_file = file.to_string();
self
}
pub fn with_wildcard(mut self, wildcard: &str) -> Self {
self.wildcard = wildcard.to_string();
self
}
pub fn with_style(mut self, style: FileDialogStyle) -> Self {
self.style = style;
self
}
pub fn with_pos(mut self, pos: Point) -> Self {
self.pos = pos;
self
}
pub fn with_size(mut self, size: Size) -> Self {
self.size = size;
self
}
pub fn build(self) -> FileDialog {
let c_message = CString::new(self.message).expect("CString::new failed for message");
let c_default_dir = CString::new(self.default_dir).expect("CString::new failed for default_dir");
let c_default_file = CString::new(self.default_file).expect("CString::new failed for default_file");
let c_wildcard = CString::new(self.wildcard).expect("CString::new failed for wildcard");
let parent_ptr = self.parent.handle_ptr();
assert!(!parent_ptr.is_null(), "FileDialog requires a valid parent window pointer.");
let ptr = unsafe {
ffi::wxd_FileDialog_Create(
parent_ptr,
c_message.as_ptr(),
c_default_dir.as_ptr(),
c_default_file.as_ptr(),
c_wildcard.as_ptr(),
self.style.bits() as ffi::wxd_Style_t,
self.pos.x,
self.pos.y, self.size.width,
self.size.height, )
};
if ptr.is_null() {
panic!("Failed to create wxFileDialog");
}
unsafe { FileDialog::from_ptr(ptr) }
}
}