// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using System.IO; using FlaxEditor.CustomEditors; using FlaxEditor.GUI; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Dialogs; using FlaxEditor.GUI.Tree; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Content.Import { /// /// Dialog used to edit import files settings. /// /// public class ImportFilesDialog : Dialog { private TreeNode _rootNode; private CustomEditorPresenter _settingsEditor; /// /// Gets the entries count. /// public int EntriesCount { get { var result = 0; for (int i = 0; i < _rootNode.ChildrenCount; i++) { if (_rootNode.Children[i].Tag is ImportFileEntry) result++; } return result; } } /// /// Initializes a new instance of the class. /// /// The entries to edit settings. public ImportFilesDialog(List entries) : base("Import files settings") { if (entries == null || entries.Count < 1) throw new ArgumentNullException(); const float TotalWidth = 920; const float EditorHeight = 450; Width = TotalWidth; // Header and help description var headerLabel = new Label { Text = "Import settings", AnchorPreset = AnchorPresets.HorizontalStretchTop, Offsets = new Margin(0, 0, 0, 40), Parent = this, Font = new FontReference(Style.Current.FontTitle) }; var infoLabel = new Label { Text = "Specify options for importing files. Every file can have different settings. Select entries on the left panel to modify them.\nPro Tip: hold CTRL key and select entries to edit multiple at once or use CTRL+A to select them all.", HorizontalAlignment = TextAlignment.Near, Margin = new Margin(7), AnchorPreset = AnchorPresets.HorizontalStretchTop, Offsets = new Margin(10, -20, 45, 70), Parent = this }; // Buttons const float ButtonsWidth = 60; const float ButtonsHeight = 24; const float ButtonsMargin = 8; var importButton = new Button { Text = "Import", AnchorPreset = AnchorPresets.BottomRight, Offsets = new Margin(-ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight), Parent = this }; importButton.Clicked += OnImport; var cancelButton = new Button { Text = "Cancel", AnchorPreset = AnchorPresets.BottomRight, Offsets = new Margin(-ButtonsWidth - ButtonsMargin - ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight), Parent = this }; cancelButton.Clicked += OnCancel; // Split panel for entries list and settings editor var splitPanel = new SplitPanel(Orientation.Horizontal, ScrollBars.Both, ScrollBars.Vertical) { AnchorPreset = AnchorPresets.StretchAll, Offsets = new Margin(2, 2, infoLabel.Bottom + 2, ButtonsHeight + ButtonsMargin + ButtonsMargin), Parent = this }; // Settings editor _settingsEditor = new CustomEditorPresenter(null); _settingsEditor.Panel.Parent = splitPanel.Panel2; // Setup tree var tree = new Tree(true) { Parent = splitPanel.Panel1 }; tree.RightClick += OnTreeRightClick; _rootNode = new TreeNode(false); for (int i = 0; i < entries.Count; i++) { var entry = entries[i]; // TODO: add icons for textures/models/etc from FileEntry to tree node?? var node = new ItemNode(entry) { Parent = _rootNode }; } _rootNode.Expand(); _rootNode.ChildrenIndent = 0; _rootNode.Parent = tree; tree.Margin = new Margin(0.0f, 0.0f, -14.0f, 2.0f); // Hide root node tree.SelectedChanged += OnSelectedChanged; // Select the first item tree.Select(_rootNode.Children[0] as TreeNode); _dialogSize = new Vector2(TotalWidth, EditorHeight + splitPanel.Offsets.Height); } private void OnTreeRightClick(TreeNode node, Vector2 location) { var menu = new ContextMenu(); menu.AddButton("Rename", OnRenameClicked); menu.AddButton("Don't import", OnDontImportClicked); menu.AddButton("Show in Explorer", OnShowInExplorerClicked); menu.Tag = node; menu.Show(node, location); } private void OnRenameClicked(ContextMenuButton button) { var node = (ItemNode)button.ParentContextMenu.Tag; node.StartRenaming(); } private void OnDontImportClicked(ContextMenuButton button) { if (EntriesCount == 1) { OnCancel(); return; } var node = (ItemNode)button.ParentContextMenu.Tag; if (_settingsEditor.Selection.Count == 1 && _settingsEditor.Selection[0] == node.Entry.Settings) _settingsEditor.Deselect(); node.Dispose(); } private void OnShowInExplorerClicked(ContextMenuButton button) { var node = (ItemNode)button.ParentContextMenu.Tag; FileSystem.ShowFileExplorer(Path.GetDirectoryName(node.Entry.SourceUrl)); } private class ItemNode : TreeNode { public ImportFileEntry Entry => (ImportFileEntry)Tag; public ItemNode(ImportFileEntry entry) : base(false) { Text = Path.GetFileName(entry.SourceUrl); Tag = entry; LinkTooltip(entry.SourceUrl); } /// protected override bool OnMouseDoubleClickHeader(ref Vector2 location, MouseButton button) { StartRenaming(); return true; } /// /// Shows the rename popup for the item. /// public void StartRenaming() { // Start renaming the folder var entry = (ImportFileEntry)Tag; var shortName = Path.GetFileNameWithoutExtension(entry.ResultUrl); var dialog = RenamePopup.Show(this, HeaderRect, shortName, false); dialog.Tag = Tag; dialog.Renamed += OnRenamed; } private void OnRenamed(RenamePopup popup) { var entry = (ImportFileEntry)Tag; entry.ModifyResultFilename(popup.Text); Text = string.Format("{0} ({1})", Path.GetFileName(entry.SourceUrl), popup.Text); } } private void OnImport() { var entries = new List(_rootNode.ChildrenCount); for (int i = 0; i < _rootNode.ChildrenCount; i++) { if (_rootNode.Children[i].Tag is ImportFileEntry fileEntry) entries.Add(fileEntry); } Editor.Instance.ContentImporting.LetThemBeImportedxD(entries); Close(DialogResult.OK); } private void OnCancel() { Close(DialogResult.Cancel); } private void OnSelectedChanged(List before, List after) { var selection = new List(after.Count); for (int i = 0; i < after.Count; i++) { if (after[i].Tag is ImportFileEntry fileEntry && fileEntry.HasSettings) selection.Add(fileEntry.Settings); } _settingsEditor.Select(selection); } /// protected override void SetupWindowSettings(ref CreateWindowSettings settings) { base.SetupWindowSettings(ref settings); settings.MinimumSize = new Vector2(300, 400); settings.HasSizingFrame = true; } /// public override bool OnKeyDown(KeyboardKeys key) { if (base.OnKeyDown(key)) return true; switch (key) { case KeyboardKeys.Escape: OnCancel(); return true; case KeyboardKeys.Return: OnImport(); return true; } return false; } } }