fyrox_ui/file_browser/
field.rs1use crate::button::Button;
22use crate::file_browser::FileSelector;
23use crate::text_box::TextBox;
24use crate::{
25 button::{ButtonBuilder, ButtonMessage},
26 core::{
27 pool::Handle, reflect::prelude::*, uuid_provider, visitor::prelude::*, ComponentProvider,
28 },
29 define_widget_deref,
30 file_browser::{FileSelectorBuilder, FileSelectorMessage, FileSelectorMode},
31 grid::{Column, GridBuilder, Row},
32 message::{MessageData, MessageDirection, UiMessage},
33 text::TextMessage,
34 text_box::TextBoxBuilder,
35 widget::{Widget, WidgetBuilder, WidgetMessage},
36 window::{WindowAlignment, WindowBuilder, WindowMessage},
37 BuildContext, Control, UiNode, UserInterface, VerticalAlignment,
38};
39use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
40use std::path::{Path, PathBuf};
41
42#[derive(Debug, Clone, PartialEq)]
43pub enum FileSelectorFieldMessage {
44 Path(PathBuf),
45}
46
47impl MessageData for FileSelectorFieldMessage {}
48
49define_widget_deref!(FileSelectorField);
50
51uuid_provider!(FileSelectorField = "2dbda730-8a60-4f62-aee8-2ff0ccd15bf2");
52
53#[derive(Default, Clone, Visit, Reflect, Debug, ComponentProvider)]
54#[reflect(derived_type = "UiNode")]
55pub struct FileSelectorField {
56 widget: Widget,
57 path: PathBuf,
58 path_field: Handle<TextBox>,
59 select: Handle<Button>,
60 file_selector: Handle<FileSelector>,
61}
62
63impl ConstructorProvider<UiNode, UserInterface> for FileSelectorField {
64 fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
65 GraphNodeConstructor::new::<Self>()
66 .with_variant("File Selector Field", |ui| {
67 FileSelectorFieldBuilder::new(WidgetBuilder::new().with_name("File Selector Field"))
68 .build(&mut ui.build_ctx())
69 .to_base()
70 .into()
71 })
72 .with_group("File System")
73 }
74}
75
76impl Control for FileSelectorField {
77 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
78 self.widget.handle_routed_message(ui, message);
79
80 if let Some(TextMessage::Text(text)) = message.data() {
81 if message.destination() == self.path_field
82 && message.direction() == MessageDirection::FromWidget
83 && Path::new(text.as_str()) != self.path
84 {
85 ui.send(self.handle, FileSelectorFieldMessage::Path(text.into()));
86 }
87 } else if let Some(ButtonMessage::Click) = message.data() {
88 if message.destination() == self.select {
89 let file_selector = FileSelectorBuilder::new(
90 WindowBuilder::new(WidgetBuilder::new().with_width(300.0).with_height(400.0))
91 .open(false)
92 .can_minimize(false),
93 )
94 .with_path(self.path.clone())
95 .with_root(std::env::current_dir().unwrap_or_default())
96 .with_mode(FileSelectorMode::Open)
97 .build(&mut ui.build_ctx());
98
99 self.file_selector = file_selector;
100
101 ui.send(
102 file_selector,
103 WindowMessage::Open {
104 alignment: WindowAlignment::Center,
105 modal: true,
106 focus_content: true,
107 },
108 );
109 }
110 } else if let Some(FileSelectorFieldMessage::Path(new_path)) = message.data_for(self.handle)
111 {
112 if &self.path != new_path {
113 self.path.clone_from(new_path);
114 ui.send(
115 self.path_field,
116 TextMessage::Text(self.path.to_string_lossy().to_string()),
117 );
118
119 ui.send_message(message.reverse());
120 }
121 }
122 }
123
124 fn preview_message(&self, ui: &UserInterface, message: &mut UiMessage) {
125 if let Some(FileSelectorMessage::Commit(new_path)) = message.data() {
126 if message.destination() == self.file_selector {
127 ui.send(
128 self.handle,
129 FileSelectorFieldMessage::Path(new_path.clone()),
130 );
131 }
132 } else if let Some(WindowMessage::Close) = message.data() {
133 if message.destination() == self.file_selector {
134 ui.send(self.file_selector, WidgetMessage::Remove);
135 }
136 }
137 }
138}
139
140pub struct FileSelectorFieldBuilder {
141 widget_builder: WidgetBuilder,
142 path: PathBuf,
143}
144
145impl FileSelectorFieldBuilder {
146 pub fn new(widget_builder: WidgetBuilder) -> Self {
147 Self {
148 widget_builder,
149 path: Default::default(),
150 }
151 }
152
153 pub fn with_path(mut self, path: PathBuf) -> Self {
154 self.path = path;
155 self
156 }
157
158 pub fn build(self, ctx: &mut BuildContext) -> Handle<FileSelectorField> {
159 let select;
160 let path_field;
161 let field = FileSelectorField {
162 widget: self
163 .widget_builder
164 .with_preview_messages(true)
165 .with_child(
166 GridBuilder::new(
167 WidgetBuilder::new()
168 .with_child({
169 path_field = TextBoxBuilder::new(WidgetBuilder::new().on_column(0))
170 .with_text(self.path.to_string_lossy())
171 .with_vertical_text_alignment(VerticalAlignment::Center)
172 .build(ctx);
173 path_field
174 })
175 .with_child({
176 select = ButtonBuilder::new(
177 WidgetBuilder::new().on_column(1).with_width(25.0),
178 )
179 .with_text("...")
180 .build(ctx);
181 select
182 }),
183 )
184 .add_row(Row::stretch())
185 .add_column(Column::stretch())
186 .add_column(Column::auto())
187 .build(ctx),
188 )
189 .build(ctx),
190 path: self.path,
191 path_field,
192 select,
193 file_selector: Default::default(),
194 };
195
196 ctx.add(field)
197 }
198}