use crate::{
fyrox::{
asset::{
manager::ResourceManager,
untyped::{ResourceKind, UntypedResource},
},
core::{log::Log, make_pretty_type_name, pool::Handle, SafeLock, Uuid},
engine::Engine,
gui::{
button::{ButtonBuilder, ButtonMessage},
grid::{Column, GridBuilder, Row},
list_view::{ListViewBuilder, ListViewMessage},
message::UiMessage,
stack_panel::StackPanelBuilder,
text::TextMessage,
text_box::TextBoxBuilder,
utils::make_dropdown_list_option,
widget::{WidgetBuilder, WidgetMessage},
window::{WindowBuilder, WindowMessage, WindowTitle},
BuildContext, HorizontalAlignment, Orientation, Thickness, UserInterface,
},
},
message::MessageSender,
Message,
};
use fyrox::gui::button::Button;
use fyrox::gui::list_view::ListView;
use fyrox::gui::text_box::TextBox;
use fyrox::gui::window::{Window, WindowAlignment};
use std::path::{Path, PathBuf};
pub struct ResourceCreator {
pub window: Handle<Window>,
resource_constructors_list: Handle<ListView>,
ok: Handle<Button>,
cancel: Handle<Button>,
name: Handle<TextBox>,
selected: Option<usize>,
supported_resource_data_uuids: Vec<Uuid>,
name_str: String,
}
impl ResourceCreator {
pub fn new(ctx: &mut BuildContext, resource_manager: &ResourceManager) -> Self {
let rm_state = resource_manager.state();
let mut constructors = rm_state.constructors_container.map.safe_lock();
let mut items = Vec::new();
let mut supported_resource_data_uuids = Vec::new();
for (uuid, constructor) in constructors.iter_mut() {
let instance = (constructor.callback)();
if instance.can_be_saved() {
supported_resource_data_uuids.push(*uuid);
items.push(make_dropdown_list_option(
ctx,
make_pretty_type_name(&constructor.type_name),
))
}
}
let name_str = String::from("unnamed_resource");
let name;
let ok;
let cancel;
let resource_constructors_list;
let window = WindowBuilder::new(WidgetBuilder::new().with_width(300.0).with_height(400.0))
.with_title(WindowTitle::text("Resource Creator"))
.open(false)
.with_content(
GridBuilder::new(
WidgetBuilder::new()
.with_child({
name = TextBoxBuilder::new(
WidgetBuilder::new()
.with_tab_index(Some(0))
.on_row(0)
.with_height(22.0)
.with_margin(Thickness::uniform(1.0)),
)
.with_text(&name_str)
.build(ctx);
name
})
.with_child({
resource_constructors_list = ListViewBuilder::new(
WidgetBuilder::new().with_tab_index(Some(1)).on_row(1),
)
.with_items(items)
.build(ctx);
resource_constructors_list
})
.with_child(
StackPanelBuilder::new(
WidgetBuilder::new()
.with_horizontal_alignment(HorizontalAlignment::Right)
.on_row(2)
.with_child({
ok = ButtonBuilder::new(
WidgetBuilder::new()
.with_tab_index(Some(2))
.with_enabled(false)
.with_width(100.0)
.with_height(22.0),
)
.with_text("OK")
.build(ctx);
ok
})
.with_child({
cancel = ButtonBuilder::new(
WidgetBuilder::new()
.with_tab_index(Some(3))
.with_width(100.0)
.with_height(22.0),
)
.with_text("Cancel")
.build(ctx);
cancel
}),
)
.with_orientation(Orientation::Horizontal)
.build(ctx),
),
)
.add_row(Row::auto())
.add_row(Row::stretch())
.add_row(Row::auto())
.add_column(Column::stretch())
.build(ctx),
)
.build(ctx);
Self {
window,
resource_constructors_list,
ok,
cancel,
name,
selected: None,
name_str,
supported_resource_data_uuids,
}
}
pub fn open(&self, ui: &UserInterface) {
ui.send(
self.window,
WindowMessage::Open {
alignment: WindowAlignment::Center,
modal: true,
focus_content: true,
},
);
}
#[must_use]
pub fn handle_ui_message(
&mut self,
message: &UiMessage,
engine: &mut Engine,
sender: MessageSender,
base_path: &Path,
) -> bool {
let mut asset_added = false;
if let Some(ListViewMessage::Selection(selection)) =
message.data_from(self.resource_constructors_list)
{
self.selected = selection.first().cloned();
engine
.user_interfaces
.first()
.send(self.ok, WidgetMessage::Enabled(true));
let resource_manager_state = engine.resource_manager.state();
if let Some(data_type_uuid) = self
.supported_resource_data_uuids
.get(self.selected.unwrap_or_default())
{
let loaders = resource_manager_state.loaders.safe_lock();
if let Some(loader) = loaders
.iter()
.find(|loader| &loader.data_type_uuid() == data_type_uuid)
{
if let Some(first) = loader.extensions().first() {
let mut path = PathBuf::from(&self.name_str);
path.set_extension(first);
self.name_str = path.to_string_lossy().to_string();
engine
.user_interfaces
.first()
.send(self.name, TextMessage::Text(self.name_str.clone()));
}
};
}
} else if let Some(ButtonMessage::Click) = message.data() {
if message.destination() == self.ok {
let resource_manager_state = engine.resource_manager.state();
let mut constructors = resource_manager_state
.constructors_container
.map
.safe_lock();
if let Some(mut instance) = self
.supported_resource_data_uuids
.get(self.selected.unwrap_or_default())
.and_then(|uuid| constructors.get_mut(uuid))
.map(|c| c.create_instance())
{
let path = base_path.join(&self.name_str);
match instance.save(&path) {
Ok(_) => {
let resource = UntypedResource::new_ok_untyped(
Uuid::new_v4(),
ResourceKind::External,
instance,
);
drop(constructors);
drop(resource_manager_state);
Log::verify(engine.resource_manager.register(resource, path));
sender.send(Message::ForceSync);
asset_added = true;
}
Err(e) => Log::err(format!("Unable to create a resource. Reason: {e:?}")),
}
}
}
if message.destination() == self.ok || message.destination() == self.cancel {
engine
.user_interfaces
.first()
.send(self.window, WindowMessage::Close);
}
} else if let Some(TextMessage::Text(text)) = message.data_from(self.name) {
self.name_str.clone_from(text);
}
asset_added
}
}