use concinnity_cook::authoring::world::{entry_handle, entry_handles, set_entry_id};
use concinnity_core::components::FrameInput;
use concinnity_core::components::InputKey;
use concinnity_core::ecs::World;
use std::path::Path;
use crate::editor::file_dialog;
use crate::editor::hook::{
EditorHook, FormTarget, declared_id, entry_type, scroll_step, short_status,
};
use crate::editor::notify;
use crate::editor::panels::import_panel::{
self, ImportAction, ImportRow, ImportStatus, ImportView,
};
use crate::editor::panels::registry::PanelKey;
use crate::editor::widget;
impl EditorHook {
pub(in crate::editor::hook) fn import_rows(&self) -> Vec<ImportRow> {
let handles = entry_handles(&self.entries);
self.entries
.iter()
.enumerate()
.filter_map(|(i, e)| {
let ty = entry_type(e)?;
if !import_panel::IMPORT_TYPES.contains(&ty) {
return None;
}
let name = handles[i].as_deref().unwrap_or("?");
let source = e
.get("args")
.map(import_panel::source_of)
.unwrap_or_default();
Some(ImportRow {
entry: i,
caption: format!("{name} ({ty}) {source}"),
})
})
.collect()
}
pub(in crate::editor::hook) fn make_import_view<'a>(
&'a self,
rows: &'a [ImportRow],
mouse: [f32; 2],
) -> ImportView<'a> {
ImportView {
rows,
scroll: self.import.scroll,
focus: self.import.focus && self.panel_order.last() == Some(&PanelKey::Import),
status: self.import.status.as_ref(),
mouse,
}
}
pub(in crate::editor::hook) fn scroll_imports(&mut self, delta: f32) {
let rows_shown = import_panel::visible_rows(self.effective_size(PanelKey::Import)[1]);
let max = self.import_rows().len().saturating_sub(rows_shown);
self.import.scroll = scroll_step(self.import.scroll, delta, max);
}
pub(in crate::editor::hook) fn apply_import_action(
&mut self,
action: ImportAction,
world: &mut World,
) {
match action {
ImportAction::FocusPath => self.import.focus = true,
ImportAction::Browse => self.browse_import(world),
ImportAction::Add => self.add_import(world),
ImportAction::Open(i) => {
if let Some(row) = self.import_rows().get(i) {
self.open_import(row.entry, world);
}
}
ImportAction::Consume => self.import.focus = false,
}
}
pub(super) fn browse_import(&mut self, world: &mut World) {
let root = project_root();
if let Some(picked) = file_dialog::pick_import_file(&root) {
self.accept_browsed_path(world, &picked);
}
}
pub(in crate::editor::hook) fn accept_browsed_path(
&mut self,
world: &mut World,
picked: &Path,
) {
let text = file_dialog::project_path(picked, &project_root());
widget::seed_field(world, import_panel::PATH_INPUT, &text);
self.import.focus = true;
self.import.status = None;
}
pub(in crate::editor::hook) fn add_import(&mut self, world: &mut World) {
self.import.status = None;
let path = widget::field_text(world, import_panel::PATH_INPUT)
.trim()
.to_string();
if path.is_empty() {
return;
}
if !std::path::Path::new(&path).is_file() {
let msg = format!("{path}: no such file");
self.console_sink.error(&format!("import: {msg}"));
self.import.status = Some(ImportStatus::Error(short_status(&msg)));
self.notifier.error_with(
&format!("Import failed: {msg}"),
notify::Action::OpenConsole,
);
return;
}
let mut new_entries = match crate::authoring::entry_from_path(&path) {
Ok(entries) => entries,
Err(e) => {
self.console_sink.error(&format!("import: {e}"));
self.import.status = Some(ImportStatus::Error(short_status(&e.to_string())));
self.notifier
.error_with(&format!("Import failed: {e}"), notify::Action::OpenConsole);
return;
}
};
if let Some((name, source)) =
crate::authoring::try_retarget_environment_map(&mut self.entries, &new_entries)
{
let notice = format!("{name} now uses {source}");
self.import.status = Some(ImportStatus::Notice(short_status(¬ice)));
self.notifier.info(¬ice);
self.mark_changed();
widget::seed_field(world, import_panel::PATH_INPUT, "");
return;
}
let mut first_name = String::new();
for entry in &mut new_entries {
if let Some(base) = declared_id(entry).map(str::to_string) {
set_entry_id(entry, &self.unique_from(&base));
}
self.entries.push(entry.clone());
if first_name.is_empty() {
first_name =
entry_handle(&self.entries, self.entries.len() - 1).unwrap_or_default();
}
}
match new_entries.len() {
0 => {}
1 => self.notifier.success(&format!("Imported '{first_name}'")),
n => self.notifier.success(&format!("Imported {n} assets")),
}
self.mark_changed();
widget::seed_field(world, import_panel::PATH_INPUT, "");
}
pub(super) fn open_import(&mut self, idx: usize, world: &mut World) {
let Some(key) = self.entries.key_at(idx) else {
return;
};
let Some(ty) = self.entries.get(idx).and_then(entry_type).map(String::from) else {
return;
};
self.open[PanelKey::Assets] = true;
self.open_form(world, ty, FormTarget::Entry(key));
}
pub(in crate::editor::hook) fn import_keys(&mut self, world: &mut World, input: &FrameInput) {
if self.import.focus && input.pressed_fresh(InputKey::Enter) {
self.add_import(world);
}
}
}
fn project_root() -> std::path::PathBuf {
std::env::current_dir().unwrap_or_default()
}