fui_controls 0.18.0

Standard controls for FUI UI Framework
Documentation
use crate::controls::*;
use fui_core::*;
use fui_macros::ui;
use std::cell::RefCell;
use std::rc::Rc;
use typed_builder::TypedBuilder;
use typemap::TypeMap;

#[derive(Copy, Clone)]
pub enum PathKind {
    OpenFile,
    SaveFile,
    Folder,
}

#[derive(TypedBuilder)]
pub struct PathEdit {
    #[builder(default = Property::new("".to_string()))]
    pub label: Property<String>,

    #[builder(default = Property::new("".to_string()))]
    pub path: Property<String>,

    #[builder(default = PathKind::OpenFile)]
    pub kind: PathKind,

    #[builder(default = Vec::new())]
    pub filters: Vec<FileFilter>,
}

impl PathEdit {
    pub fn to_view(
        self,
        _style: Option<Box<dyn Style<Self>>>,
        mut context: ViewContext,
    ) -> Rc<RefCell<dyn ControlObject>> {
        let mut choose_callback = Callback::empty();

        let control = ui! {
            Horizontal {
                Text { text: self.label.clone() },
                TextBox { Grow: Length::Fill(1.0f32), text: self.path.clone() },
                Button { Text { text: "..." }, clicked: choose_callback.clone() },
            }
        };

        if !context.attached_values.contains::<Margin>() {
            context
                .attached_values
                .insert::<Margin>(Thickness::all(8.0f32));
        }

        control
            .borrow_mut()
            .get_context_mut()
            .set_attached_values(context.attached_values);

        let control_weak = Rc::downgrade(&control);

        choose_callback.set_async({
            move |_| {
                let control_weak = control_weak.clone();
                let path_prop = self.path.clone();
                let label_prop = self.label.clone();
                let filters = self.filters.clone();
                async move {
                    if let Some(file_dialog_service) = control_weak
                        .upgrade()
                        .map(|c| c.borrow().get_context().get_services().clone())
                        .flatten()
                        .map(|s| s.get_file_dialog_service())
                    {
                        let dialog_data = FileDialogData::new()
                            .with_title(&label_prop.get())
                            .with_initial_path(path_prop.get())
                            .with_filters(filters);
                        let path = match self.kind {
                            PathKind::OpenFile => file_dialog_service.pick_file(dialog_data).await,

                            PathKind::SaveFile => {
                                file_dialog_service.pick_save_file(dialog_data).await
                            }

                            PathKind::Folder => file_dialog_service.pick_folder(dialog_data).await,
                        };

                        if let Some(path) = path {
                            path_prop.set(path.to_str().map(|s| s.to_string()).unwrap_or_default());
                        }
                    }
                }
            }
        });

        control
    }
}