use winapi::um::shobjidl::IFileDialog;
use crate::win32::resources_helper as rh;
use crate::win32::base_helper::to_utf16;
use crate::{ControlHandle, NwgError};
use std::{fmt, ptr, mem, ffi::OsString};
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum FileDialogAction {
Open,
OpenDirectory,
Save,
}
pub struct FileDialog {
handle: *mut IFileDialog,
action: FileDialogAction
}
impl FileDialog {
pub fn builder() -> FileDialogBuilder {
FileDialogBuilder {
title: None,
action: FileDialogAction::Save,
multiselect: false,
default_folder: None,
filters: None
}
}
pub fn action(&self) -> FileDialogAction {
self.action
}
pub fn run<C: Into<ControlHandle>>(&self, parent: Option<C>) -> bool {
use winapi::shared::winerror::S_OK;
let parent_handle = match parent {
Some(p) => p.into().hwnd().expect("File dialog parent must be a window control"),
None => ptr::null_mut()
};
unsafe { (&mut *self.handle).Show(parent_handle) == S_OK }
}
pub fn get_selected_item(&self) -> Result<OsString, NwgError> {
if self.multiselect() {
return Err(NwgError::file_dialog("FileDialog have the multiselect flag"));
}
unsafe {
rh::filedialog_get_item(&mut *self.handle)
}
}
pub fn get_selected_items(&self) -> Result<Vec<OsString>, NwgError> {
if self.action == FileDialogAction::Save {
return Err(NwgError::file_dialog("Save dialog cannot have more than one item selected"));
}
unsafe {
rh::filedialog_get_items(mem::transmute(&mut *self.handle))
}
}
pub fn multiselect(&self) -> bool {
use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;
unsafe {
let flags = rh::file_dialog_options(&mut *self.handle).unwrap_or(0);
flags & FOS_ALLOWMULTISELECT == FOS_ALLOWMULTISELECT
}
}
pub fn set_multiselect(&self, multiselect: bool) -> Result<(), NwgError> {
use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;
if self.action == FileDialogAction::Save {
return Err(NwgError::file_dialog("Cannot set multiselect flag for a save file dialog"));
}
let result = unsafe{ rh::toggle_dialog_flags(&mut *self.handle, FOS_ALLOWMULTISELECT, multiselect) };
match result {
Ok(_) => Ok(()),
Err(e) => Err(e)
}
}
pub fn set_default_folder<'a>(&self, folder: &'a str) -> Result<(), NwgError> {
unsafe{
let handle = &mut *self.handle;
rh::file_dialog_set_default_folder(handle, &folder)
}
}
pub fn set_filters<'a>(&self, filters: &'a str) -> Result<(), NwgError> {
unsafe{
let handle = &mut *self.handle;
rh::file_dialog_set_filters(handle, &filters)
}
}
pub fn set_title<'a>(&self, title: &'a str) {
unsafe {
let title = to_utf16(title);
let handle = &mut *self.handle;
handle.SetTitle(title.as_ptr());
}
}
pub fn clear_client_data(&self) {
unsafe{
let handle = &mut *self.handle;
handle.ClearClientData();
}
}
}
impl fmt::Debug for FileDialog {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FileDialog {{ action: {:?} }}", self.action)
}
}
impl Default for FileDialog {
fn default() -> FileDialog {
FileDialog {
handle: ptr::null_mut(),
action: FileDialogAction::Open
}
}
}
impl PartialEq for FileDialog {
fn eq(&self, other: &Self) -> bool {
self.handle == other.handle && self.action == other.action
}
}
impl Eq for FileDialog {}
pub struct FileDialogBuilder {
pub title: Option<String>,
pub action: FileDialogAction,
pub multiselect: bool,
pub default_folder: Option<String>,
pub filters: Option<String>
}
impl FileDialogBuilder {
pub fn title<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
self.title = Some(t.into());
self
}
pub fn default_folder<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
self.default_folder = Some(t.into());
self
}
pub fn filters<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
self.filters = Some(t.into());
self
}
pub fn action(mut self, a: FileDialogAction) -> FileDialogBuilder {
self.action = a;
self
}
pub fn multiselect(mut self, m: bool) -> FileDialogBuilder {
self.multiselect = m;
self
}
pub fn build(self, out: &mut FileDialog) -> Result<(), NwgError> {
unsafe {
out.handle = rh::create_file_dialog(
self.action,
self.multiselect,
self.default_folder,
self.filters
)?;
}
out.action = self.action;
if let Some(title) = self.title {
out.set_title(&title);
}
Ok(())
}
}