use azul_css::{
corety::OptionString,
impl_option, impl_option_inner,
props::basic::color::{ColorU, OptionColorU},
AzString, OptionStringVec, StringVec,
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use tfd::{DefaultColorValue, MessageBoxIcon};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
#[allow(clippy::pub_underscore_fields)] pub struct MsgBox {
pub _reserved: u8,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
#[allow(clippy::pub_underscore_fields)] pub struct FileDialog {
pub _reserved: u8,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
#[allow(clippy::pub_underscore_fields)] pub struct ColorPickerDialog {
pub _reserved: u8,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
pub enum OkCancel {
Ok,
Cancel,
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
impl From<tfd::OkCancel> for OkCancel {
#[inline]
fn from(e: tfd::OkCancel) -> Self {
match e {
tfd::OkCancel::Ok => Self::Ok,
tfd::OkCancel::Cancel => Self::Cancel,
}
}
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
impl From<OkCancel> for tfd::OkCancel {
#[inline]
fn from(e: OkCancel) -> Self {
match e {
OkCancel::Ok => Self::Ok,
OkCancel::Cancel => Self::Cancel,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub enum YesNo {
Yes,
No,
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
impl From<YesNo> for tfd::YesNo {
#[inline]
fn from(e: YesNo) -> Self {
match e {
YesNo::Yes => Self::Yes,
YesNo::No => Self::No,
}
}
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
impl From<tfd::YesNo> for YesNo {
#[inline]
fn from(e: tfd::YesNo) -> Self {
match e {
tfd::YesNo::Yes => Self::Yes,
tfd::YesNo::No => Self::No,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub enum MsgBoxIcon {
Info,
Warning,
Error,
Question,
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
impl From<MsgBoxIcon> for MessageBoxIcon {
#[inline]
fn from(e: MsgBoxIcon) -> Self {
match e {
MsgBoxIcon::Info => Self::Info,
MsgBoxIcon::Warning => Self::Warning,
MsgBoxIcon::Error => Self::Error,
MsgBoxIcon::Question => Self::Question,
}
}
}
impl Default for MsgBox {
fn default() -> Self {
Self::new()
}
}
impl MsgBox {
#[must_use] pub const fn new() -> Self {
Self { _reserved: 0 }
}
#[allow(clippy::needless_pass_by_value)]
pub fn ok(title: AzString, message: AzString, icon: MsgBoxIcon) {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let mut msg = message.as_str().to_string();
msg = msg.replace('\"', "");
msg = msg.replace('\'', "");
tfd::MessageBox::new(title.as_str(), &msg)
.with_icon(icon.into())
.run_modal();
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = (title, message, icon);
}
}
#[allow(clippy::needless_pass_by_value)]
#[must_use] pub fn ok_cancel(
title: AzString,
message: AzString,
icon: MsgBoxIcon,
default: OkCancel,
) -> OkCancel {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
tfd::MessageBox::new(title.as_str(), message.as_str())
.with_icon(icon.into())
.run_modal_ok_cancel(default.into())
.into()
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = (title, message, icon);
default
}
}
#[allow(clippy::needless_pass_by_value)]
#[must_use] pub fn yes_no(
title: AzString,
message: AzString,
icon: MsgBoxIcon,
default: YesNo,
) -> YesNo {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
tfd::MessageBox::new(title.as_str(), message.as_str())
.with_icon(icon.into())
.run_modal_yes_no(default.into())
.into()
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = (title, message, icon);
default
}
}
pub fn info(content: AzString) {
Self::ok(AzString::from("Info"), content, MsgBoxIcon::Info);
}
}
impl Default for ColorPickerDialog {
fn default() -> Self {
Self::new()
}
}
impl ColorPickerDialog {
#[must_use] pub const fn new() -> Self {
Self { _reserved: 0 }
}
#[allow(clippy::needless_pass_by_value)]
#[must_use] pub fn open(title: AzString, default_value: OptionColorU) -> OptionColorU {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let rgb = default_value
.into_option()
.map_or([0, 0, 0], |c| [c.r, c.g, c.b]);
let default_color = DefaultColorValue::RGB(rgb);
let result = tfd::ColorChooser::new(title.as_str())
.with_default_color(default_color)
.run_modal();
match result {
Some(r) => OptionColorU::Some(ColorU {
r: r.1[0],
g: r.1[1],
b: r.1[2],
a: ColorU::ALPHA_OPAQUE,
}),
None => OptionColorU::None,
}
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = title;
default_value
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
#[repr(C)]
pub struct FileTypeList {
pub document_types: StringVec,
pub document_descriptor: AzString,
}
impl_option!(
FileTypeList,
OptionFileTypeList,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd]
);
#[cfg(not(any(target_os = "android", target_os = "ios")))]
#[allow(clippy::needless_pass_by_value)]
fn apply_filter(mut dialog: tfd::FileDialog, filter: FileTypeList) -> tfd::FileDialog {
let v = filter.document_types.clone().into_library_owned_vec();
let patterns: Vec<&str> = v.iter().map(AzString::as_str).collect();
dialog = dialog.with_filter(&patterns, filter.document_descriptor.as_str());
dialog
}
impl Default for FileDialog {
fn default() -> Self {
Self::new()
}
}
impl FileDialog {
#[must_use] pub const fn new() -> Self {
Self { _reserved: 0 }
}
#[allow(clippy::needless_pass_by_value)]
pub fn open_file(
title: AzString,
default_path: OptionString,
filter_list: OptionFileTypeList,
) -> OptionString {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let mut dialog = tfd::FileDialog::new(title.as_str());
if let Some(path) = default_path.as_option() {
dialog = dialog.with_path(path.as_str());
}
if let Some(filter) = filter_list.into_option() {
dialog = apply_filter(dialog, filter);
}
dialog.open_file().map(AzString::from).into()
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = (title, default_path, filter_list);
OptionString::None
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn open_directory(title: AzString, default_path: OptionString) -> OptionString {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let mut dialog = tfd::FileDialog::new(title.as_str());
if let Some(path) = default_path.as_option() {
dialog = dialog.with_path(path.as_str());
}
dialog.select_folder().map(AzString::from).into()
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = (title, default_path);
OptionString::None
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn open_multiple_files(
title: AzString,
default_path: OptionString,
filter_list: OptionFileTypeList,
) -> OptionStringVec {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let mut dialog =
tfd::FileDialog::new(title.as_str()).with_multiple_selection(true);
if let Some(path) = default_path.as_option() {
dialog = dialog.with_path(path.as_str());
}
if let Some(filter) = filter_list.into_option() {
dialog = apply_filter(dialog, filter);
}
dialog.open_files().map(StringVec::from).into()
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = (title, default_path, filter_list);
OptionStringVec::None
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn save_file(title: AzString, default_path: OptionString) -> OptionString {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let mut dialog = tfd::FileDialog::new(title.as_str());
if let Some(path) = default_path.as_option() {
dialog = dialog.with_path(path.as_str());
}
dialog.save_file().map(AzString::from).into()
}
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let _ = (title, default_path);
OptionString::None
}
}
}
pub fn msg_box(content: &str) {
MsgBox::info(AzString::from(content));
}