hydrate_editor/
action_queue.rs

1use crate::app::UiState;
2use crate::modal_action::ModalAction;
3use crate::ui::modals::ConfirmQuitWithoutSaving;
4use crate::ui::modals::ConfirmRevertChanges;
5use crossbeam_channel::{Receiver, Sender};
6use egui::KeyboardShortcut;
7use hydrate_base::hashing::HashMap;
8use hydrate_model::edit_context::EditContext;
9use hydrate_model::pipeline::{AssetEngine, HydrateProjectConfiguration, ImportJobToQueue};
10use hydrate_model::{
11    AssetId, AssetLocation, AssetName, DataSetError, DataSetErrorWithBacktrace, DataSetResult,
12    EditorModel, EndContextBehavior, NullOverride, OverrideBehavior, PropertyPath, Schema,
13    SchemaFingerprint, SchemaRecord, Value,
14};
15use std::path::PathBuf;
16use std::sync::Arc;
17use uuid::Uuid;
18
19pub enum UIAction {
20    TryBeginModalAction(Box<dyn ModalAction>),
21    EditContext(
22        &'static str,
23        Box<dyn FnOnce(&mut EditContext) -> DataSetResult<EndContextBehavior>>,
24    ),
25    Undo,
26    Redo,
27    SaveAll,
28    RevertAll,
29    RevertAllNoConfirm,
30    Quit,
31    QuitNoConfirm,
32    PersistAssets(Vec<AssetId>),
33    BuildAll,
34    ReimportAndRebuild(Vec<AssetId>),
35    ForceRebuild(Vec<AssetId>),
36    ShowAssetInAssetGallery(AssetId),
37    MoveAssets(Vec<AssetId>, AssetLocation),
38    MoveOrRename(Vec<AssetId>, Option<AssetName>, AssetLocation),
39    NewAsset(AssetName, AssetLocation, SchemaRecord, Option<AssetId>),
40    DuplicateAssets(Vec<AssetId>),
41    DeleteAssets(Vec<AssetId>),
42    SetProperty(
43        Vec<AssetId>,
44        PropertyPath,
45        Option<Value>,
46        EndContextBehavior,
47    ),
48    ClearPropertiesForRecord(Vec<AssetId>, PropertyPath, SchemaFingerprint),
49    CommitPendingUndoContext,
50    ApplyPropertyOverrideToPrototype(Vec<AssetId>, PropertyPath),
51    ApplyPropertyOverrideToPrototypeForRecord(Vec<AssetId>, PropertyPath, SchemaFingerprint),
52    ApplyResolvedPropertyToAllSelected(AssetId, Vec<AssetId>, PropertyPath),
53    ApplyResolvedPropertyToAllSelectedForRecord(
54        AssetId,
55        Vec<AssetId>,
56        PropertyPath,
57        SchemaFingerprint,
58    ),
59    SetNullOverride(Vec<AssetId>, PropertyPath, NullOverride),
60    AddDynamicArrayEntry(AssetId, PropertyPath),
61    AddMapEntry(AssetId, PropertyPath),
62    RemoveDynamicArrayEntry(AssetId, PropertyPath, Uuid),
63    RemoveMapEntry(AssetId, PropertyPath, Uuid),
64    MoveDynamicArrayEntryUp(AssetId, PropertyPath, Uuid),
65    MoveDynamicArrayEntryDown(AssetId, PropertyPath, Uuid),
66    // This moves values, not entries, that's why it's named differently
67    MoveStaticArrayOverrideUp(Vec<AssetId>, PropertyPath, usize),
68    MoveStaticArrayOverrideDown(Vec<AssetId>, PropertyPath, usize),
69    OverrideWithDefault(Vec<AssetId>, PropertyPath),
70    SetOverrideBehavior(Vec<AssetId>, PropertyPath, OverrideBehavior),
71    ToggleSelectAllAssetGallery,
72}
73
74impl UIAction {
75    // title
76    // tooltip
77    // default keyboard shortcut
78    // draw button
79    // draw menu item
80}
81
82pub struct UIActionQueueSenderInner {
83    action_queue_tx: Sender<UIAction>,
84}
85
86#[derive(Clone)]
87pub struct UIActionQueueSender {
88    inner: Arc<UIActionQueueSenderInner>,
89}
90
91impl UIActionQueueSender {
92    pub fn queue_action(
93        &self,
94        action: UIAction,
95    ) {
96        self.inner.action_queue_tx.send(action).unwrap();
97    }
98
99    // shorthand for a common action
100    pub fn try_set_modal_action<T: ModalAction + 'static>(
101        &self,
102        action: T,
103    ) {
104        self.queue_action(UIAction::TryBeginModalAction(Box::new(action)))
105    }
106
107    // pub fn queue_edit<
108    //     F: 'static + FnOnce(&mut EditContext) -> DataSetResult<EndContextBehavior>,
109    // >(
110    //     &self,
111    //     undo_context_name: &'static str,
112    //     assets: Vec<AssetId>,
113    //     f: F,
114    // ) {
115    //     self.queue_action(UIAction::EditContext(
116    //         undo_context_name,
117    //         assets,
118    //         Box::new(f),
119    //     ))
120    // }
121}
122
123pub struct UIActionQueueReceiver {
124    sender: UIActionQueueSender,
125    action_queue_tx: Sender<UIAction>,
126    action_queue_rx: Receiver<UIAction>,
127    anything_has_focus_last_frame: bool,
128}
129
130impl Default for UIActionQueueReceiver {
131    fn default() -> Self {
132        let (action_queue_tx, action_queue_rx) = crossbeam_channel::unbounded();
133
134        let sender_inner = UIActionQueueSenderInner {
135            action_queue_tx: action_queue_tx.clone(),
136        };
137
138        let sender = UIActionQueueSender {
139            inner: Arc::new(sender_inner),
140        };
141
142        UIActionQueueReceiver {
143            sender,
144            action_queue_tx,
145            action_queue_rx,
146            anything_has_focus_last_frame: false,
147        }
148    }
149}
150
151impl UIActionQueueReceiver {
152    pub fn sender(&self) -> UIActionQueueSender {
153        self.sender.clone()
154    }
155
156    pub fn queue_action(
157        &self,
158        action: UIAction,
159    ) {
160        self.action_queue_tx.send(action).unwrap();
161    }
162
163    pub fn process(
164        &mut self,
165        project_config: &HydrateProjectConfiguration,
166        editor_model: &mut EditorModel,
167        asset_engine: &mut AssetEngine,
168        ui_state: &mut UiState,
169        modal_action: &mut Option<Box<dyn ModalAction>>,
170        ctx: &egui::Context,
171    ) {
172        {
173            // If we are editing a text field, it is the focus and we should not try to listen for hotkeys
174            let anything_has_focus = ctx.memory(|mem| mem.focus().is_some());
175            if !anything_has_focus && !self.anything_has_focus_last_frame {
176                ctx.input_mut(|input| {
177                    //for command in UICommand::iter() {
178                    //     if let Some(kb_shortcut) = command.kb_shortcut() {
179                    //         if input.consume_shortcut(&kb_shortcut) {
180                    //             return Some(command);
181                    //         }
182                    //     }
183                    //}
184                    //None
185
186                    if input.consume_shortcut(&KeyboardShortcut {
187                        key: egui::Key::A,
188                        modifiers: egui::Modifiers::COMMAND,
189                    }) {
190                        // Select All
191                        self.action_queue_tx
192                            .send(UIAction::ToggleSelectAllAssetGallery)
193                            .unwrap();
194                    }
195
196                    if input.consume_shortcut(&KeyboardShortcut {
197                        key: egui::Key::B,
198                        modifiers: egui::Modifiers::COMMAND | egui::Modifiers::SHIFT,
199                    }) {
200                        self.action_queue_tx.send(UIAction::BuildAll).unwrap();
201                    }
202
203                    if input.consume_shortcut(&KeyboardShortcut {
204                        key: egui::Key::S,
205                        modifiers: egui::Modifiers::COMMAND,
206                    }) {
207                        self.action_queue_tx.send(UIAction::SaveAll).unwrap();
208                    }
209
210                    if input.consume_shortcut(&KeyboardShortcut {
211                        key: egui::Key::Z,
212                        modifiers: egui::Modifiers::COMMAND,
213                    }) {
214                        self.action_queue_tx.send(UIAction::Undo).unwrap();
215                    }
216
217                    if input.consume_shortcut(&KeyboardShortcut {
218                        key: egui::Key::Z,
219                        modifiers: egui::Modifiers::COMMAND | egui::Modifiers::SHIFT,
220                    }) {
221                        self.action_queue_tx.send(UIAction::Redo).unwrap();
222                    }
223                });
224            }
225
226            self.anything_has_focus_last_frame = anything_has_focus;
227        }
228
229        let mut import_job_to_queue = ImportJobToQueue::default();
230        while let Ok(action) = self.action_queue_rx.try_recv() {
231            match action {
232                UIAction::ToggleSelectAllAssetGallery => {
233                    ui_state.asset_gallery_ui_state.toggle_select_all();
234                }
235                UIAction::SaveAll => editor_model.save_root_edit_context(),
236                UIAction::RevertAll => {
237                    if editor_model.any_edit_context_has_unsaved_changes() {
238                        *modal_action = Some(Box::new(ConfirmRevertChanges {}))
239                    }
240                }
241                UIAction::RevertAllNoConfirm => {
242                    editor_model.revert_root_edit_context(project_config, &mut import_job_to_queue)
243                }
244                UIAction::Undo => editor_model.undo().unwrap(),
245                UIAction::Redo => editor_model.redo().unwrap(),
246                UIAction::Quit => {
247                    // Only verify with a modal if there are unsaved changes
248                    if editor_model.any_edit_context_has_unsaved_changes() {
249                        *modal_action = Some(Box::new(ConfirmQuitWithoutSaving {}))
250                    } else {
251                        self.action_queue_tx.send(UIAction::QuitNoConfirm).unwrap();
252                    }
253                }
254                UIAction::QuitNoConfirm => {
255                    ui_state.user_confirmed_should_quit = true;
256                    ctx.send_viewport_cmd(egui::ViewportCommand::Close)
257                }
258                UIAction::TryBeginModalAction(modal) => {
259                    if modal_action.is_none() {
260                        *modal_action = Some(modal);
261                    }
262                }
263                UIAction::EditContext(undo_context_name, f) => editor_model
264                    .root_edit_context_mut()
265                    .with_undo_context(&undo_context_name, |x| f(x).unwrap()),
266
267                UIAction::PersistAssets(asset_ids) => {
268                    for asset_id in asset_ids {
269                        editor_model.persist_generated_asset(asset_id);
270                    }
271                }
272                UIAction::BuildAll => {
273                    asset_engine.queue_build_all();
274                }
275                UIAction::MoveOrRename(asset_ids, new_name, new_location) => {
276                    editor_model.root_edit_context_mut().with_undo_context(
277                        "MoveOrRename",
278                        |edit_context| {
279                            for &asset_id in &asset_ids {
280                                if let Some(new_name) = &new_name {
281                                    edit_context
282                                        .set_asset_name(asset_id, new_name.clone())
283                                        .unwrap();
284                                }
285
286                                edit_context
287                                    .set_asset_location(asset_id, new_location)
288                                    .unwrap();
289                            }
290
291                            EndContextBehavior::Finish
292                        },
293                    );
294                }
295                UIAction::ReimportAndRebuild(asset_ids) => {
296                    // - Only update assets that were requested
297                    // - Process source files once
298                    // - Match the same import settings as were originally in place, or fail if
299                    //   this is not possible.
300
301                    let mut import_job_to_queue = ImportJobToQueue::default();
302                    for &asset_id in &asset_ids {
303                        let root_edit_context = editor_model.root_edit_context();
304                        let import_info = root_edit_context.import_info(asset_id);
305                        if let Some(import_info) = import_info {
306                            //import_info.importer_id()
307                            //
308                            let source_file_path: PathBuf = import_info
309                                .source_file()
310                                .canonicalized_absolute_path(root_edit_context, &PathBuf::default())
311                                .unwrap()
312                                .path()
313                                .into();
314
315                            // let requested_importables = HashMap::default();
316                            // let source_file = ImportJobSourceFile {
317                            //     importer_id: import_info.importer_id(),
318                            //     import_type: ImportType::ImportAlways,
319                            //     requested_importables,
320                            //     source_file_path,
321                            // };
322
323                            let mut asset_id_assignments = HashMap::default();
324                            asset_id_assignments
325                                .insert(import_info.importable_name().clone(), asset_id);
326
327                            println!("reimport {:?}", source_file_path);
328                            hydrate_model::pipeline::recursively_gather_import_operations_and_create_assets(
329                                project_config,
330                                &source_file_path,
331                                asset_engine.importer_registry().importer(import_info.importer_id()).unwrap(),
332                                root_edit_context,
333                                asset_engine.importer_registry(),
334                                &root_edit_context.asset_location(asset_id).unwrap(),
335                                Some(&asset_id_assignments),
336                                &mut import_job_to_queue,
337                            ).unwrap();
338
339                            //hydrate_pipeline::recursively_gather_import_operations_and_create_assets()
340                        }
341                    }
342
343                    if !import_job_to_queue.is_empty() {
344                        asset_engine.queue_import_operation(import_job_to_queue);
345
346                        // Can't do incremental build, manifest won't have *anything* but what was built
347                        // for asset_id in asset_ids {
348                        //     asset_engine.queue_build_asset(asset_id);
349                        // }
350                    }
351
352                    asset_engine.queue_build_all();
353                }
354                UIAction::ForceRebuild(_asset_ids) => {
355                    // Can't do incremental build, manifest won't have *anything* but what was built
356                    // for asset_id in asset_ids {
357                    //     asset_engine.queue_build_asset(asset_id);
358                    // }
359
360                    asset_engine.queue_build_all();
361                }
362                UIAction::ShowAssetInAssetGallery(asset_id) => {
363                    ui_state
364                        .asset_gallery_ui_state
365                        .set_selection(Some(asset_id));
366
367                    if let Some(location) =
368                        editor_model.root_edit_context().asset_location(asset_id)
369                    {
370                        ui_state.asset_tree_ui_state.selected_tree_node = Some(location);
371                    }
372                }
373                UIAction::MoveAssets(moving_assets, new_location) => {
374                    editor_model.root_edit_context_mut().with_undo_context(
375                        "move asset",
376                        |edit_context| {
377                            for &moving_asset in &moving_assets {
378                                let result =
379                                    edit_context.set_asset_location(moving_asset, new_location);
380                                match result {
381                                    Ok(_) => {
382                                        // do nothing
383                                    }
384                                    Err(DataSetErrorWithBacktrace {
385                                        error: DataSetError::NewLocationIsChildOfCurrentAsset,
386                                        ..
387                                    }) => {
388                                        // do nothing
389                                    }
390                                    _ => {
391                                        unimplemented!()
392                                    }
393                                }
394                            }
395
396                            EndContextBehavior::Finish
397                        },
398                    );
399                }
400                UIAction::NewAsset(asset_name, asset_location, schema_record, prototype) => {
401                    editor_model.root_edit_context_mut().with_undo_context(
402                        "new asset",
403                        |edit_context| {
404                            let new_asset_id = if let Some(prototype) = prototype {
405                                edit_context
406                                    .new_asset_from_prototype(
407                                        &asset_name,
408                                        &asset_location,
409                                        prototype,
410                                    )
411                                    .unwrap()
412                            } else {
413                                edit_context.new_asset(&asset_name, &asset_location, &schema_record)
414                            };
415
416                            self.sender
417                                .queue_action(UIAction::ShowAssetInAssetGallery(new_asset_id));
418                            EndContextBehavior::Finish
419                        },
420                    );
421                }
422                UIAction::DuplicateAssets(asset_ids) => {
423                    editor_model.root_edit_context_mut().with_undo_context(
424                        "delete asset",
425                        |edit_context| {
426                            for asset_id in asset_ids {
427                                let new_asset_id = edit_context.duplicate_asset(asset_id).unwrap();
428                                if edit_context.import_info(asset_id).is_some() {
429                                    asset_engine
430                                        .duplicate_import_data(asset_id, new_asset_id)
431                                        .unwrap();
432                                }
433                            }
434                            EndContextBehavior::Finish
435                        },
436                    );
437                }
438                UIAction::DeleteAssets(asset_ids) => {
439                    editor_model.root_edit_context_mut().with_undo_context(
440                        "delete asset",
441                        |edit_context| {
442                            for asset_id in asset_ids {
443                                edit_context.delete_asset(asset_id).unwrap();
444                            }
445                            EndContextBehavior::Finish
446                        },
447                    );
448                }
449                UIAction::SetProperty(asset_ids, property_path, value, end_context_behavior) => {
450                    editor_model.root_edit_context_mut().with_undo_context(
451                        "set property",
452                        |edit_context| {
453                            for asset_id in asset_ids {
454                                edit_context
455                                    .set_property_override(
456                                        asset_id,
457                                        property_path.path(),
458                                        value.clone(),
459                                    )
460                                    .unwrap();
461                            }
462                            end_context_behavior
463                        },
464                    );
465                }
466                UIAction::ClearPropertiesForRecord(
467                    asset_ids,
468                    property_path,
469                    record_schema_fingerprint,
470                ) => {
471                    editor_model.root_edit_context_mut().with_undo_context(
472                        "ClearPropertiesForRecord",
473                        |edit_context| {
474                            let record_schema = edit_context
475                                .schema_set()
476                                .find_named_type_by_fingerprint(record_schema_fingerprint)
477                                .unwrap()
478                                .as_record()
479                                .unwrap()
480                                .clone();
481
482                            for field in record_schema.fields() {
483                                let field_path = property_path.push(field.name());
484                                for &asset_id in &asset_ids {
485                                    edit_context
486                                        .set_property_override(asset_id, field_path.path(), None)
487                                        .unwrap();
488                                }
489                            }
490
491                            EndContextBehavior::Finish
492                        },
493                    );
494                }
495                UIAction::CommitPendingUndoContext => {
496                    editor_model
497                        .root_edit_context_mut()
498                        .commit_pending_undo_context();
499                }
500                UIAction::ApplyPropertyOverrideToPrototype(asset_ids, property_path) => {
501                    editor_model.root_edit_context_mut().with_undo_context(
502                        "apply override",
503                        |edit_context| {
504                            for asset_id in asset_ids {
505                                edit_context
506                                    .apply_property_override_to_prototype(
507                                        asset_id,
508                                        property_path.path(),
509                                    )
510                                    .unwrap();
511                            }
512                            EndContextBehavior::Finish
513                        },
514                    );
515                }
516
517                UIAction::ApplyPropertyOverrideToPrototypeForRecord(
518                    asset_ids,
519                    property_path,
520                    record_schema_fingerprint,
521                ) => {
522                    editor_model.root_edit_context_mut().with_undo_context(
523                        "ApplyPropertyOverrideToPrototypeForRecord",
524                        |edit_context| {
525                            let record_schema = edit_context
526                                .schema_set()
527                                .find_named_type_by_fingerprint(record_schema_fingerprint)
528                                .unwrap()
529                                .as_record()
530                                .unwrap()
531                                .clone();
532
533                            for field in record_schema.fields() {
534                                let field_path = property_path.push(field.name());
535                                for &asset_id in &asset_ids {
536                                    edit_context
537                                        .apply_property_override_to_prototype(
538                                            asset_id,
539                                            field_path.path(),
540                                        )
541                                        .unwrap();
542                                }
543                            }
544
545                            EndContextBehavior::Finish
546                        },
547                    );
548                }
549
550                UIAction::ApplyResolvedPropertyToAllSelected(
551                    src_asset_id,
552                    selected_asset_ids,
553                    property_path,
554                ) => {
555                    editor_model.root_edit_context_mut().with_undo_context(
556                        "apply override",
557                        |edit_context| {
558                            let value = edit_context
559                                .resolve_property(src_asset_id, property_path.path())
560                                .unwrap()
561                                .clone();
562
563                            for &asset_id in &selected_asset_ids {
564                                edit_context
565                                    .set_property_override(
566                                        asset_id,
567                                        property_path.path(),
568                                        Some(value.clone()),
569                                    )
570                                    .unwrap();
571                            }
572                            EndContextBehavior::Finish
573                        },
574                    );
575                }
576                UIAction::ApplyResolvedPropertyToAllSelectedForRecord(
577                    src_asset_id,
578                    selected_asset_ids,
579                    property_path,
580                    record_schema_fingerprint,
581                ) => {
582                    editor_model.root_edit_context_mut().with_undo_context(
583                        "apply override",
584                        |edit_context| {
585                            let record_schema = edit_context
586                                .schema_set()
587                                .find_named_type_by_fingerprint(record_schema_fingerprint)
588                                .unwrap()
589                                .as_record()
590                                .unwrap()
591                                .clone();
592
593                            for field in record_schema.fields() {
594                                let field_path = property_path.push(field.name());
595                                let value = edit_context
596                                    .resolve_property(src_asset_id, field_path.path())
597                                    .unwrap()
598                                    .clone();
599
600                                for &asset_id in &selected_asset_ids {
601                                    edit_context
602                                        .set_property_override(
603                                            asset_id,
604                                            field_path.path(),
605                                            Some(value.clone()),
606                                        )
607                                        .unwrap();
608                                }
609                            }
610
611                            EndContextBehavior::Finish
612                        },
613                    );
614                }
615
616                UIAction::SetNullOverride(asset_ids, property_path, null_override) => {
617                    editor_model.root_edit_context_mut().with_undo_context(
618                        "set null override",
619                        |edit_context| {
620                            for &asset_id in &asset_ids {
621                                edit_context
622                                    .set_null_override(
623                                        asset_id,
624                                        property_path.path(),
625                                        null_override,
626                                    )
627                                    .unwrap();
628                            }
629                            EndContextBehavior::Finish
630                        },
631                    );
632                }
633                UIAction::AddDynamicArrayEntry(asset_id, property_path) => {
634                    editor_model.root_edit_context_mut().with_undo_context(
635                        "set null override",
636                        |edit_context| {
637                            edit_context
638                                .add_dynamic_array_entry(asset_id, property_path.path())
639                                .unwrap();
640                            EndContextBehavior::Finish
641                        },
642                    );
643                }
644                UIAction::AddMapEntry(asset_id, property_path) => {
645                    editor_model.root_edit_context_mut().with_undo_context(
646                        "set null override",
647                        |edit_context| {
648                            edit_context
649                                .add_map_entry(asset_id, property_path.path())
650                                .unwrap();
651                            EndContextBehavior::Finish
652                        },
653                    );
654                }
655                UIAction::RemoveDynamicArrayEntry(asset_id, property_path, entry_uuid) => {
656                    editor_model.root_edit_context_mut().with_undo_context(
657                        "RemoveDynamicArrayOverride",
658                        |edit_context| {
659                            edit_context
660                                .remove_dynamic_array_entry(
661                                    asset_id,
662                                    property_path.path(),
663                                    entry_uuid,
664                                )
665                                .unwrap();
666
667                            EndContextBehavior::Finish
668                        },
669                    );
670                }
671                UIAction::RemoveMapEntry(asset_id, property_path, entry_uuid) => {
672                    editor_model.root_edit_context_mut().with_undo_context(
673                        "RemoveDynamicArrayOverride",
674                        |edit_context| {
675                            edit_context
676                                .remove_map_entry(asset_id, property_path.path(), entry_uuid)
677                                .unwrap();
678
679                            EndContextBehavior::Finish
680                        },
681                    );
682                }
683                UIAction::MoveDynamicArrayEntryUp(asset_id, property_path, entry_uuid) => {
684                    editor_model.root_edit_context_mut().with_undo_context(
685                        "MoveDynamicArrayOverrideUp",
686                        |edit_context| {
687                            let overrides: Vec<_> = edit_context
688                                .get_dynamic_array_entries(asset_id, property_path.path())
689                                .unwrap()
690                                .copied()
691                                .collect();
692                            let current_index =
693                                overrides.iter().position(|x| *x == entry_uuid).unwrap();
694                            if current_index > 0 {
695                                // Remove
696                                edit_context
697                                    .remove_dynamic_array_entry(
698                                        asset_id,
699                                        property_path.path(),
700                                        entry_uuid,
701                                    )
702                                    .unwrap();
703                                // Insert one index higher
704                                edit_context
705                                    .insert_dynamic_array_entry(
706                                        asset_id,
707                                        property_path.path(),
708                                        current_index - 1,
709                                        entry_uuid,
710                                    )
711                                    .unwrap();
712                            }
713
714                            EndContextBehavior::Finish
715                        },
716                    );
717                }
718                UIAction::MoveDynamicArrayEntryDown(asset_id, property_path, entry_uuid) => {
719                    editor_model.root_edit_context_mut().with_undo_context(
720                        "MoveDynamicArrayOverrideDown",
721                        |edit_context| {
722                            let overrides: Vec<_> = edit_context
723                                .get_dynamic_array_entries(asset_id, property_path.path())
724                                .unwrap()
725                                .collect();
726                            let current_index =
727                                overrides.iter().position(|x| **x == entry_uuid).unwrap();
728                            if current_index < overrides.len() - 1 {
729                                // Remove
730                                edit_context
731                                    .remove_dynamic_array_entry(
732                                        asset_id,
733                                        property_path.path(),
734                                        entry_uuid,
735                                    )
736                                    .unwrap();
737                                // Re-insert at next index
738                                edit_context
739                                    .insert_dynamic_array_entry(
740                                        asset_id,
741                                        property_path.path(),
742                                        current_index + 1,
743                                        entry_uuid,
744                                    )
745                                    .unwrap();
746                            }
747
748                            EndContextBehavior::Finish
749                        },
750                    );
751                }
752                // UIAction::ClearStaticArrayOverride(asset_id, property_path, entry_index) => {
753                //
754                // }
755                UIAction::MoveStaticArrayOverrideUp(asset_ids, property_path, entry_index) => {
756                    editor_model.root_edit_context_mut().with_undo_context(
757                        "MoveStaticArrayOverrideUp",
758                        |edit_context| {
759                            for &asset_id in &asset_ids {
760                                let schema_set = edit_context.schema_set().clone();
761                                let index_a = entry_index;
762                                let property_path_a = property_path.push(&index_a.to_string());
763                                let bundle_a = edit_context
764                                    .read_properties_bundle(
765                                        &schema_set,
766                                        asset_id,
767                                        property_path_a.path(),
768                                    )
769                                    .unwrap();
770
771                                let index_b = entry_index - 1;
772                                let property_path_b = property_path.push(&index_b.to_string());
773                                let bundle_b = edit_context
774                                    .read_properties_bundle(
775                                        &schema_set,
776                                        asset_id,
777                                        property_path_b.path(),
778                                    )
779                                    .unwrap();
780
781                                edit_context
782                                    .write_properties_bundle(
783                                        &schema_set,
784                                        asset_id,
785                                        property_path_a.path(),
786                                        &bundle_b,
787                                    )
788                                    .unwrap();
789                                edit_context
790                                    .write_properties_bundle(
791                                        &schema_set,
792                                        asset_id,
793                                        property_path_b.path(),
794                                        &bundle_a,
795                                    )
796                                    .unwrap();
797                            }
798
799                            EndContextBehavior::Finish
800                        },
801                    );
802                }
803                UIAction::MoveStaticArrayOverrideDown(asset_ids, property_path, entry_index) => {
804                    editor_model.root_edit_context_mut().with_undo_context(
805                        "MoveStaticArrayOverrideDown",
806                        |edit_context| {
807                            for &asset_id in &asset_ids {
808                                let schema_set = edit_context.schema_set().clone();
809                                let index_a = entry_index;
810                                let property_path_a = property_path.push(&index_a.to_string());
811                                let bundle_a = edit_context
812                                    .read_properties_bundle(
813                                        &schema_set,
814                                        asset_id,
815                                        property_path_a.path(),
816                                    )
817                                    .unwrap();
818
819                                let index_b = entry_index + 1;
820                                let property_path_b = property_path.push(&index_b.to_string());
821                                let bundle_b = edit_context
822                                    .read_properties_bundle(
823                                        &schema_set,
824                                        asset_id,
825                                        property_path_b.path(),
826                                    )
827                                    .unwrap();
828
829                                edit_context
830                                    .write_properties_bundle(
831                                        &schema_set,
832                                        asset_id,
833                                        property_path_a.path(),
834                                        &bundle_b,
835                                    )
836                                    .unwrap();
837                                edit_context
838                                    .write_properties_bundle(
839                                        &schema_set,
840                                        asset_id,
841                                        property_path_b.path(),
842                                        &bundle_a,
843                                    )
844                                    .unwrap();
845                            }
846                            EndContextBehavior::Finish
847                        },
848                    );
849                }
850                UIAction::OverrideWithDefault(asset_ids, property_path) => {
851                    editor_model.root_edit_context_mut().with_undo_context(
852                        "OverrideWithDefault",
853                        |edit_context| {
854                            //let schema = edit_context.asset_schema(asset_id).unwrap().clone();
855
856                            for asset_id in asset_ids {
857                                let schema = edit_context
858                                    .asset_schema(asset_id)
859                                    .unwrap()
860                                    .find_property_schema(
861                                        property_path.path(),
862                                        edit_context.schema_set().schemas(),
863                                    )
864                                    .unwrap();
865                                println!(
866                                    "find schema {:?} for property {:?}",
867                                    schema,
868                                    property_path.path()
869                                );
870                                override_with_default_values_recursively(
871                                    asset_id,
872                                    &property_path,
873                                    schema,
874                                    edit_context,
875                                );
876                            }
877
878                            //let schema_set = edit_context.schema_set().clone();
879                            // let schema = edit_context.asset_schema(asset_id).unwrap().clone();
880                            // for field in schema.fields() {
881                            //     let field_name = property_path.push(field.name());
882                            //     let field_schema = schema.field_schema(field).unwrap();
883                            //     match schema {
884                            //
885                            //     }
886                            // }
887
888                            // Value::default_for_schema(&property_schema, schema_set);
889                            // edit_context.set_property_override(asset_id, path, schema_set.)
890
891                            EndContextBehavior::Finish
892                        },
893                    );
894                }
895                UIAction::SetOverrideBehavior(asset_ids, property_path, override_behavior) => {
896                    editor_model.root_edit_context_mut().with_undo_context(
897                        "SetOverrideBehavior",
898                        |edit_context| {
899                            for &asset_id in &asset_ids {
900                                edit_context
901                                    .set_override_behavior(
902                                        asset_id,
903                                        property_path.path(),
904                                        override_behavior,
905                                    )
906                                    .unwrap();
907                            }
908                            EndContextBehavior::Finish
909                        },
910                    );
911                }
912            }
913        }
914
915        if !import_job_to_queue.is_empty() {
916            asset_engine.queue_import_operation(import_job_to_queue);
917        }
918    }
919}
920
921fn override_with_default_values_recursively(
922    asset_id: AssetId,
923    property_path: &PropertyPath,
924    schema: Schema,
925    edit_context: &mut EditContext,
926) {
927    println!("{} {:?} set to default", property_path.path(), schema);
928    match schema {
929        Schema::Boolean
930        | Schema::I32
931        | Schema::I64
932        | Schema::U32
933        | Schema::U64
934        | Schema::F32
935        | Schema::F64
936        | Schema::Bytes
937        | Schema::String
938        | Schema::AssetRef(_)
939        | Schema::Enum(_) => {
940            println!("set path {:?} {:?}", property_path.path(), schema);
941            edit_context
942                .set_property_override(
943                    asset_id,
944                    property_path.path(),
945                    Some(Value::default_for_schema(&schema, edit_context.schema_set()).clone()),
946                )
947                .unwrap();
948        }
949        Schema::Nullable(_) => {
950            edit_context
951                .set_null_override(asset_id, property_path.path(), NullOverride::SetNull)
952                .unwrap();
953        }
954        Schema::StaticArray(schema) => {
955            for i in 0..schema.length() {
956                let element_path = property_path.push(&i.to_string());
957                override_with_default_values_recursively(
958                    asset_id,
959                    &element_path,
960                    schema.item_type().clone(),
961                    edit_context,
962                );
963            }
964        }
965        Schema::DynamicArray(_) => {
966            edit_context
967                .set_override_behavior(asset_id, property_path.path(), OverrideBehavior::Replace)
968                .unwrap();
969        }
970        Schema::Map(_) => {
971            edit_context
972                .set_override_behavior(asset_id, property_path.path(), OverrideBehavior::Replace)
973                .unwrap();
974        }
975        Schema::Record(record_schema) => {
976            let record_schema = edit_context
977                .schema_set()
978                .find_named_type_by_fingerprint(record_schema)
979                .unwrap()
980                .as_record()
981                .unwrap()
982                .clone();
983            println!(
984                "iterate fields of {:?} {:?}",
985                record_schema,
986                record_schema.fields()
987            );
988            for field in record_schema.fields() {
989                let field_path = property_path.push(field.name());
990                let field_schema = record_schema.field_schema(field.name()).unwrap();
991                override_with_default_values_recursively(
992                    asset_id,
993                    &field_path,
994                    field_schema.clone(),
995                    edit_context,
996                );
997            }
998        }
999    }
1000}