// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using FlaxEditor.GUI.Tabs; using FlaxEditor.Modules; using FlaxEditor.SceneGraph.Actors; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Tools.Terrain { /// /// Terrain carving tab. Supports different modes for terrain editing including: carving, painting and managing tools. /// /// [HideInEditor] public class CarveTab : Tab { private readonly Tabs _modes; private readonly ContainerControl _noTerrainPanel; private readonly Button _createTerrainButton; /// /// The editor instance. /// public readonly Editor Editor; /// /// The cached selected terrain. It's synchronized with . /// public FlaxEngine.Terrain SelectedTerrain; /// /// Occurs when selected terrain gets changed (to a different value). /// public event Action SelectedTerrainChanged; /// /// The sculpt tab; /// public SculptTab Sculpt; /// /// The paint tab; /// public PaintTab Paint; /// /// The edit tab; /// public EditTab Edit; /// /// Initializes a new instance of the class. /// /// The icon. /// The editor instance. public CarveTab(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, Offsets = Margin.Zero, AnchorPreset = AnchorPresets.StretchAll, TabsSize = new Float2(50, 32), Parent = this }; // Init tool modes InitSculptMode(); InitPaintMode(); InitEditMode(); _modes.SelectedTabIndex = 0; _noTerrainPanel = new ContainerControl { AnchorPreset = AnchorPresets.StretchAll, Offsets = Margin.Zero, BackgroundColor = Style.Current.Background, Parent = this }; var noTerrainLabel = new Label { Text = "Select terrain to edit\nor\n\n\n\n", AnchorPreset = AnchorPresets.StretchAll, Offsets = Margin.Zero, Parent = _noTerrainPanel }; var buttonText = "Create new terrain"; _createTerrainButton = new Button { Text = buttonText, AnchorPreset = AnchorPresets.MiddleCenter, Offsets = new Margin(-60, 120, -12, 24), Parent = _noTerrainPanel, Enabled = false }; var textSize = Style.Current.FontMedium.MeasureText(buttonText); if (_createTerrainButton.Width < textSize.X) { _createTerrainButton.LocalX -= (textSize.X - _createTerrainButton.Width) / 2; _createTerrainButton.Width = textSize.X + 6; } _createTerrainButton.Clicked += OnCreateNewTerrainClicked; } private void OnSceneLoaded(Scene arg1, Guid arg2) { _createTerrainButton.Enabled = true; Level.SceneUnloaded += OnSceneUnloaded; Level.SceneLoaded -= OnSceneLoaded; } private void OnSceneUnloaded(Scene arg1, Guid arg2) { _createTerrainButton.Enabled = false; Level.SceneLoaded += OnSceneLoaded; Level.SceneUnloaded -= OnSceneUnloaded; } private void OnSelected(Tab tab) { // Auto select first terrain actor to make usage easier if (Editor.SceneEditing.SelectionCount == 1 && Editor.SceneEditing.Selection[0] is SceneGraph.ActorNode actorNode && actorNode.Actor is FlaxEngine.Terrain) return; var actor = Level.FindActor(); if (actor) { Editor.SceneEditing.Select(actor); } } private void OnCreateNewTerrainClicked() { Editor.UI.CreateTerrain(); } private void OnSelectionChanged() { var terrainNode = Editor.SceneEditing.SelectionCount > 0 ? Editor.SceneEditing.Selection[0] as TerrainNode : null; var terrain = terrainNode?.Actor as FlaxEngine.Terrain; if (terrain != SelectedTerrain) { SelectedTerrain = terrain; SelectedTerrainChanged?.Invoke(); } _noTerrainPanel.Visible = terrain == null; } private void InitSculptMode() { var tab = _modes.AddTab(Sculpt = new SculptTab(this, Editor.Windows.EditWin.Viewport.SculptTerrainGizmo)); tab.Selected += OnTabSelected; } private void InitPaintMode() { var tab = _modes.AddTab(Paint = new PaintTab(this, Editor.Windows.EditWin.Viewport.PaintTerrainGizmo)); tab.Selected += OnTabSelected; } private void InitEditMode() { var tab = _modes.AddTab(Edit = new EditTab(this, Editor.Windows.EditWin.Viewport.EditTerrainGizmo)); tab.Selected += OnTabSelected; } /// public override void OnSelected() { base.OnSelected(); UpdateGizmoMode(); } private void OnTabSelected(Tab tab) { UpdateGizmoMode(); } /// /// Updates the active viewport gizmo mode based on the current mode. /// private void UpdateGizmoMode() { switch (_modes.SelectedTabIndex) { case 0: Editor.Windows.EditWin.Viewport.SetActiveMode(); break; case 1: Editor.Windows.EditWin.Viewport.SetActiveMode(); break; case 2: Editor.Windows.EditWin.Viewport.SetActiveMode(); break; default: throw new IndexOutOfRangeException("Invalid carve tab mode."); } } /// public override void OnDestroy() { if (_createTerrainButton.Enabled) Level.SceneUnloaded -= OnSceneUnloaded; else Level.SceneLoaded -= OnSceneLoaded; base.OnDestroy(); } } }