Files
FlaxEngine/Source/Editor/Tools/Foliage/FoliageTab.cs
ExMatics HydrogenC 47a25c7828 Add font fallback
Note: All the `First()` in the code are temperary workarounds to make it work and require refractoring
2023-11-28 07:17:46 +08:00

292 lines
9.3 KiB
C#

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.GUI.Tabs;
using FlaxEditor.Modules;
using FlaxEditor.SceneGraph.Actors;
using FlaxEditor.Viewport.Modes;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Tools.Foliage
{
/// <summary>
/// Foliage editing tab. Supports different modes for foliage editing including spawning, removing, and managing tools.
/// </summary>
/// <seealso cref="Tab" />
[HideInEditor]
public class FoliageTab : Tab
{
private readonly Tabs _modes;
private readonly ContainerControl _noFoliagePanel;
private int _selectedFoliageTypeIndex = -1;
private Button _createNewFoliage;
/// <summary>
/// The editor instance.
/// </summary>
public readonly Editor Editor;
/// <summary>
/// The cached selected foliage. It's synchronized with <see cref="SceneEditingModule.Selection"/>.
/// </summary>
public FlaxEngine.Foliage SelectedFoliage;
/// <summary>
/// Occurs when selected foliage gets changed (to a different value).
/// </summary>
public event Action SelectedFoliageChanged;
/// <summary>
/// Delegate signature for selected foliage index change.
/// </summary>
/// <param name="previousIndex">The index of the previous foliage type.</param>
/// <param name="currentIndex">The index of the current foliage type.</param>
public delegate void SelectedFoliageTypeIndexChangedDelegate(int previousIndex, int currentIndex);
/// <summary>
/// Occurs when selected foliage type index gets changed.
/// </summary>
public event SelectedFoliageTypeIndexChangedDelegate SelectedFoliageTypeIndexChanged;
/// <summary>
/// Occurs when selected foliage actors gets modification for foliage types collection (item added or removed). UI uses it to update the layout without manually tracking the collection.
/// </summary>
public event Action SelectedFoliageTypesChanged;
/// <summary>
/// Gets or sets the index of the selected foliage type.
/// </summary>
public int SelectedFoliageTypeIndex
{
get => _selectedFoliageTypeIndex;
set
{
var prev = _selectedFoliageTypeIndex;
if (value == prev)
return;
_selectedFoliageTypeIndex = value;
SelectedFoliageTypeIndexChanged?.Invoke(prev, value);
}
}
/// <summary>
/// The foliage types tab;
/// </summary>
public FoliageTypesTab FoliageTypes;
/// <summary>
/// The paint tab;
/// </summary>
public PaintTab Paint;
/// <summary>
/// The edit tab;
/// </summary>
public EditTab Edit;
/// <summary>
/// The foliage type model asset IDs checked to paint with them by default.
/// </summary>
public readonly Dictionary<Guid, bool> FoliageTypeModelIdsToPaint = new Dictionary<Guid, bool>();
/// <summary>
/// Initializes a new instance of the <see cref="FoliageTab"/> class.
/// </summary>
/// <param name="icon">The icon.</param>
/// <param name="editor">The editor instance.</param>
public FoliageTab(SpriteHandle icon, Editor editor)
: base(string.Empty, icon)
{
Level.SceneLoaded += OnSceneLoaded;
Editor = editor;
Editor.SceneEditing.SelectionChanged += OnSelectionChanged;
Selected += OnSelected;
_modes = new Tabs
{
Orientation = Orientation.Vertical,
UseScroll = true,
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
TabsSize = new Float2(50, 32),
Parent = this
};
// Init tool modes
InitSculptMode();
InitPaintMode();
InitEditMode();
_modes.SelectedTabIndex = 0;
_noFoliagePanel = new ContainerControl
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
BackgroundColor = Style.Current.Background,
Parent = this
};
var noFoliageLabel = new Label
{
Text = "Select foliage to edit\nor\n\n\n\n",
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = _noFoliagePanel
};
var buttonText = "Create new foliage";
_createNewFoliage = new Button
{
Text = buttonText,
AnchorPreset = AnchorPresets.MiddleCenter,
Offsets = new Margin(-60, 120, -12, 24),
Parent = _noFoliagePanel,
Enabled = false
};
var textSize = Style.Current.FontMedium.First().MeasureText(buttonText);
if (_createNewFoliage.Width < textSize.X)
{
_createNewFoliage.LocalX -= (textSize.X - _createNewFoliage.Width) / 2;
_createNewFoliage.Width = textSize.X + 6;
}
_createNewFoliage.Clicked += OnCreateNewFoliageClicked;
}
private void OnSceneLoaded(Scene arg1, Guid arg2)
{
_createNewFoliage.Enabled = true;
Level.SceneUnloaded += OnSceneUnloaded;
Level.SceneLoaded -= OnSceneLoaded;
}
private void OnSceneUnloaded(Scene arg1, Guid arg2)
{
_createNewFoliage.Enabled = false;
Level.SceneLoaded += OnSceneLoaded;
Level.SceneUnloaded -= OnSceneUnloaded;
}
private void OnSelected(Tab tab)
{
// Auto select first foliage actor to make usage easier
if (Editor.SceneEditing.SelectionCount == 1 && Editor.SceneEditing.Selection[0] is SceneGraph.ActorNode actorNode && actorNode.Actor is FlaxEngine.Foliage)
return;
var actor = Level.FindActor<FlaxEngine.Foliage>();
if (actor)
{
Editor.SceneEditing.Select(actor);
}
}
private void OnCreateNewFoliageClicked()
{
// Create
var actor = new FlaxEngine.Foliage
{
StaticFlags = StaticFlags.FullyStatic,
Name = "Foliage"
};
// Spawn and select
Editor.SceneEditing.Spawn(actor);
}
private void OnSelectionChanged()
{
var node = Editor.SceneEditing.SelectionCount > 0 ? Editor.SceneEditing.Selection[0] as FoliageNode : null;
var foliage = node?.Actor as FlaxEngine.Foliage;
if (foliage != SelectedFoliage)
{
SelectedFoliageTypeIndex = -1;
SelectedFoliage = foliage;
SelectedFoliageChanged?.Invoke();
}
_noFoliagePanel.Visible = foliage == null;
}
private void InitSculptMode()
{
var tab = _modes.AddTab(FoliageTypes = new FoliageTypesTab(this));
tab.Selected += OnTabSelected;
}
private void InitPaintMode()
{
var tab = _modes.AddTab(Paint = new PaintTab(this, Editor.Windows.EditWin.Viewport.PaintFoliageGizmo));
tab.Selected += OnTabSelected;
}
private void InitEditMode()
{
var tab = _modes.AddTab(Edit = new EditTab(this, Editor.Windows.EditWin.Viewport.EditFoliageGizmo));
tab.Selected += OnTabSelected;
}
/// <inheritdoc />
public override void OnSelected()
{
base.OnSelected();
UpdateGizmoMode();
}
private void OnTabSelected(Tab tab)
{
UpdateGizmoMode();
}
/// <summary>
/// Updates the active viewport gizmo mode based on the current mode.
/// </summary>
private void UpdateGizmoMode()
{
switch (_modes.SelectedTabIndex)
{
case 0:
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<NoGizmoMode>();
break;
case 1:
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<PaintFoliageGizmoMode>();
break;
case 2:
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<EditFoliageGizmoMode>();
break;
default: throw new IndexOutOfRangeException("Invalid foliage tab mode.");
}
}
/// <inheritdoc />
public override void Update(float deltaTime)
{
FoliageTypes.CheckFoliageTypesCount();
base.Update(deltaTime);
}
internal void OnSelectedFoliageTypesChanged()
{
SelectedFoliageTypesChanged?.Invoke();
}
/// <inheritdoc />
public override void OnDestroy()
{
if (_createNewFoliage.Enabled)
Level.SceneUnloaded -= OnSceneUnloaded;
else
Level.SceneLoaded -= OnSceneLoaded;
base.OnDestroy();
}
}
}