diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml
index 139bf2416..a8ebb4c62 100644
--- a/.github/workflows/build_mac.yml
+++ b/.github/workflows/build_mac.yml
@@ -9,7 +9,7 @@ jobs:
# Editor
editor-mac:
- name: Editor (Mac, Development x64)
+ name: Editor (Mac, Development ARM64)
runs-on: "macos-latest"
steps:
- name: Checkout repo
@@ -30,11 +30,11 @@ jobs:
git lfs pull
- name: Build
run: |
- ./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
+ ./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=8 -arch=ARM64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
# Game
game-mac:
- name: Game (Mac, Release x64)
+ name: Game (Mac, Release ARM64)
runs-on: "macos-latest"
steps:
- name: Checkout repo
@@ -55,4 +55,4 @@ jobs:
git lfs pull
- name: Build
run: |
- ./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
+ ./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=8 -arch=ARM64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
index 70f275eac..d83b40363 100644
--- a/.github/workflows/cd.yml
+++ b/.github/workflows/cd.yml
@@ -166,7 +166,7 @@ jobs:
dotnet workload --info
- name: Build
run: |
- ./PackageEditor.command -arch=x64 -platform=Mac -deployOutput=Output
+ ./PackageEditor.command -arch=ARM64 -platform=Mac -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
with:
@@ -194,7 +194,7 @@ jobs:
dotnet workload --info
- name: Build
run: |
- ./PackagePlatforms.command -arch=x64 -platform=Mac -deployOutput=Output
+ ./PackagePlatforms.command -arch=ARM64 -platform=Mac -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
with:
diff --git a/Source/Editor/Content/Proxy/PrefabProxy.cs b/Source/Editor/Content/Proxy/PrefabProxy.cs
index 18860995e..c0c4e5c88 100644
--- a/Source/Editor/Content/Proxy/PrefabProxy.cs
+++ b/Source/Editor/Content/Proxy/PrefabProxy.cs
@@ -89,7 +89,7 @@ namespace FlaxEditor.Content
// Cleanup it after usage
Object.Destroy(actor, 20.0f);
}
- else if (actor.Scene != null)
+ else if (actor.HasScene)
{
// Create prefab with identity transform so the actor instance on a level will have it customized
resetTransform = true;
diff --git a/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp b/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp
index d55ad01e3..5ad88db24 100644
--- a/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp
@@ -203,16 +203,16 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
switch (defaultOrienation)
{
case AndroidPlatformSettings::ScreenOrientation::Portrait:
- orientation = String("portrait");
+ orientation = String("userPortrait");
break;
- case AndroidPlatformSettings::ScreenOrientation::PortraitReverse:
- orientation = String("reversePortrait");
+ case AndroidPlatformSettings::ScreenOrientation::Landscape:
+ orientation = String("userLandscape");
break;
- case AndroidPlatformSettings::ScreenOrientation::LandscapeRight:
- orientation = String("landscape");
+ case AndroidPlatformSettings::ScreenOrientation::SensorPortrait:
+ orientation = String("sensorPortrait");
break;
- case AndroidPlatformSettings::ScreenOrientation::LandscapeLeft:
- orientation = String("reverseLandscape");
+ case AndroidPlatformSettings::ScreenOrientation::SensorLandscape:
+ orientation = String("sensorLandscape");
break;
case AndroidPlatformSettings::ScreenOrientation::AutoRotation:
orientation = String("fullSensor");
@@ -266,9 +266,33 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
}
}
+ String versionCode = platformSettings->VersionCode;
+ if (versionCode.IsEmpty())
+ {
+ LOG(Error, "AndroidSettings: Invalid version code");
+ return true;
+ }
+
+ String minimumSdk = platformSettings->MinimumAPILevel;
+ if (minimumSdk.IsEmpty())
+ {
+ LOG(Error, "AndroidSettings: Invalid minimum API level");
+ return true;
+ }
+
+ String targetSdk = platformSettings->TargetAPILevel;
+ if (targetSdk.IsEmpty())
+ {
+ LOG(Error, "AndroidSettings: Invalid target API level");
+ return true;
+ }
+
// Format project template files
const String buildGradlePath = data.OriginalOutputPath / TEXT("app/build.gradle");
EditorUtilities::ReplaceInFile(buildGradlePath, TEXT("${PackageName}"), packageName);
+ EditorUtilities::ReplaceInFile(buildGradlePath, TEXT("${VersionCode}"), versionCode);
+ EditorUtilities::ReplaceInFile(buildGradlePath, TEXT("${MinimumSdk}"), minimumSdk);
+ EditorUtilities::ReplaceInFile(buildGradlePath, TEXT("${TargetSdk}"), targetSdk);
EditorUtilities::ReplaceInFile(buildGradlePath, TEXT("${ProjectVersion}"), projectVersion);
EditorUtilities::ReplaceInFile(buildGradlePath, TEXT("${PackageAbi}"), abi);
const String manifestPath = data.OriginalOutputPath / TEXT("app/src/main/AndroidManifest.xml");
diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs
index 1561e6245..bdbf22ee9 100644
--- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs
@@ -291,7 +291,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
if (editor.ChildrenEditors.Count == 0 || (isRefEdited && editor is CollectionEditor))
result = CreateDiffNode(editor);
bool isScriptEditorWithRefValue = editor is ScriptsEditor && editor.Values.HasReferenceValue;
- bool isActorEditorInLevel = editor is ActorEditor && editor.Values[0] is Actor actor && actor.IsPrefabRoot && actor.Scene != null;
+ bool isActorEditorInLevel = editor is ActorEditor && editor.Values[0] is Actor actor && actor.IsPrefabRoot && actor.HasScene;
for (int i = 0; i < editor.ChildrenEditors.Count; i++)
{
var childEditor = editor.ChildrenEditors[i];
diff --git a/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs b/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs
index 194bc23ea..fbb817768 100644
--- a/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/ModelPrefabEditor.cs
@@ -45,6 +45,12 @@ public class ModelPrefabEditor : GenericEditor
break;
_prefabId = prefabObject.PrefabID;
}
+ else
+ {
+ // The model was removed earlier
+ _prefabId = Guid.Empty;
+ break;
+ }
}
var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
diff --git a/Source/Editor/CustomEditors/Editors/StringEditor.cs b/Source/Editor/CustomEditors/Editors/StringEditor.cs
index 9e38fd0ac..9f6b4ce32 100644
--- a/Source/Editor/CustomEditors/Editors/StringEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/StringEditor.cs
@@ -13,6 +13,9 @@ namespace FlaxEditor.CustomEditors.Editors
public sealed class StringEditor : CustomEditor
{
private TextBoxElement _element;
+ private string _watermarkText;
+ private Color _watermarkColor;
+ private Color _defaultWatermarkColor;
///
public override DisplayStyle Style => DisplayStyle.Inline;
@@ -21,15 +24,26 @@ namespace FlaxEditor.CustomEditors.Editors
public override void Initialize(LayoutElementsContainer layout)
{
bool isMultiLine = false;
+ _watermarkText = string.Empty;
var attributes = Values.GetAttributes();
var multiLine = attributes?.FirstOrDefault(x => x is MultilineTextAttribute);
+ var watermarkAttribute = attributes?.FirstOrDefault(x => x is WatermarkAttribute);
if (multiLine != null)
{
isMultiLine = true;
}
_element = layout.TextBox(isMultiLine);
+ _defaultWatermarkColor = _element.TextBox.WatermarkTextColor;
+ if (watermarkAttribute is WatermarkAttribute watermark)
+ {
+ _watermarkText = watermark.WatermarkText;
+ var watermarkColor = watermark.WatermarkColor > 0 ? Color.FromRGBA(watermark.WatermarkColor) : FlaxEngine.GUI.Style.Current.ForegroundDisabled;
+ _watermarkColor = watermarkColor;
+ _element.TextBox.WatermarkText = watermark.WatermarkText;
+ _element.TextBox.WatermarkTextColor = watermarkColor;
+ }
_element.TextBox.EditEnd += () => SetValue(_element.Text);
}
@@ -41,12 +55,14 @@ namespace FlaxEditor.CustomEditors.Editors
if (HasDifferentValues)
{
_element.TextBox.Text = string.Empty;
+ _element.TextBox.WatermarkTextColor = _defaultWatermarkColor;
_element.TextBox.WatermarkText = "Different values";
}
else
{
_element.TextBox.Text = (string)Values[0];
- _element.TextBox.WatermarkText = string.Empty;
+ _element.TextBox.WatermarkTextColor = _watermarkColor;
+ _element.TextBox.WatermarkText = _watermarkText;
}
}
}
diff --git a/Source/Editor/GUI/Drag/DragControlType.cs b/Source/Editor/GUI/Drag/DragControlType.cs
new file mode 100644
index 000000000..d1286053c
--- /dev/null
+++ b/Source/Editor/GUI/Drag/DragControlType.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using FlaxEditor.SceneGraph;
+using FlaxEditor.Scripting;
+using FlaxEngine;
+using FlaxEngine.GUI;
+using FlaxEngine.Utilities;
+
+namespace FlaxEditor.GUI.Drag;
+
+///
+/// Control type drag handler.
+///
+public sealed class DragControlType : DragActorType
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The validation function
+ public DragControlType(Func validateFunction)
+ : base(validateFunction)
+ {
+ }
+}
+
+///
+/// Helper class for handling control type drag and drop (for spawning).
+///
+///
+///
+public class DragControlType : DragHelper where U : DragEventArgs
+{
+ ///
+ /// The default prefix for drag data used for actor type drag and drop.
+ ///
+ public const string DragPrefix = "CTYPE!?";
+
+ ///
+ /// Creates a new DragHelper
+ ///
+ /// The validation function
+ public DragControlType(Func validateFunction)
+ : base(validateFunction)
+ {
+ }
+
+ ///
+ public override DragData ToDragData(ScriptType item) => GetDragData(item);
+
+ ///
+ public override DragData ToDragData(IEnumerable items)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Gets the drag data.
+ ///
+ /// The control type.
+ /// The data
+ public static DragData GetDragData(Type item)
+ {
+ if (item == null)
+ throw new ArgumentNullException();
+ return new DragDataText(DragPrefix + item.FullName);
+ }
+
+ ///
+ /// Gets the drag data.
+ ///
+ /// The control type.
+ /// The data
+ public static DragData GetDragData(ScriptType item)
+ {
+ if (item == ScriptType.Null)
+ throw new ArgumentNullException();
+ return new DragDataText(DragPrefix + item.TypeName);
+ }
+
+ ///
+ /// Tries to parse the drag data to extract collection.
+ ///
+ /// The data.
+ /// Gathered objects or empty array if cannot get any valid.
+ public override IEnumerable FromDragData(DragData data)
+ {
+ if (data is DragDataText dataText)
+ {
+ if (dataText.Text.StartsWith(DragPrefix))
+ {
+ // Remove prefix and parse spitted names
+ var types = dataText.Text.Remove(0, DragPrefix.Length).Split('\n');
+ var results = new List(types.Length);
+ for (int i = 0; i < types.Length; i++)
+ {
+ // Find type
+ var obj = TypeUtils.GetType(types[i]);
+ if (obj)
+ results.Add(obj);
+ }
+ return results;
+ }
+ }
+ return Utils.GetEmptyArray();
+ }
+}
+
diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs
index 36331d6d2..d5782c10f 100644
--- a/Source/Editor/GUI/Tree/TreeNode.cs
+++ b/Source/Editor/GUI/Tree/TreeNode.cs
@@ -38,7 +38,6 @@ namespace FlaxEditor.GUI.Tree
private bool _isMouseDown;
private float _mouseDownTime;
private Float2 _mouseDownPos;
- private Color _cachedTextColor;
private DragItemPositioning _dragOverMode;
private bool _isDragOverHeader;
@@ -91,6 +90,11 @@ namespace FlaxEditor.GUI.Tree
}
}
+ ///
+ /// Gets a value indicating whether the node is collapsed in the hierarchy (is collapsed or any of its parents is collapsed).
+ ///
+ public bool IsCollapsedInHierarchy => IsCollapsed || (Parent is TreeNode parentNode && parentNode.IsCollapsedInHierarchy);
+
///
/// Gets or sets the text margin.
///
@@ -604,9 +608,6 @@ namespace FlaxEditor.GUI.Tree
///
public override void Update(float deltaTime)
{
- // Cache text color
- _cachedTextColor = CacheTextColor();
-
// Drop/down animation
if (_animationProgress < 1.0f)
{
@@ -676,7 +677,8 @@ namespace FlaxEditor.GUI.Tree
}
// Draw text
- Render2D.DrawText(TextFont.GetFont(), _text, textRect, _cachedTextColor, TextAlignment.Near, TextAlignment.Center);
+ Color textColor = CacheTextColor();
+ Render2D.DrawText(TextFont.GetFont(), _text, textRect, textColor, TextAlignment.Near, TextAlignment.Center);
// Draw drag and drop effect
if (IsDragOver && _tree.DraggedOverNode == this)
@@ -712,6 +714,72 @@ namespace FlaxEditor.GUI.Tree
}
}
+ ///
+ protected override void DrawChildren()
+ {
+ // Draw all visible child controls
+ var children = _children;
+ if (children.Count == 0)
+ return;
+
+ if (CullChildren)
+ {
+ Render2D.PeekClip(out var globalClipping);
+ Render2D.PeekTransform(out var globalTransform);
+
+ // Try to estimate the rough location of the first node, assuming the node height is constant
+ var firstChildGlobalRect = GetChildGlobalRectangle(children[0], ref globalTransform);
+ var firstVisibleChild = Math.Clamp((int)Math.Floor((globalClipping.Y - firstChildGlobalRect.Top) / firstChildGlobalRect.Height) + 1, 0, children.Count - 1);
+ if (GetChildGlobalRectangle(children[firstVisibleChild], ref globalTransform).Top > globalClipping.Top || !children[firstVisibleChild].Visible)
+ {
+ // Estimate overshoot, either it's partially visible or hidden in the tree
+ for (; firstVisibleChild > 0; firstVisibleChild--)
+ {
+ var child = children[firstVisibleChild];
+ if (!child.Visible)
+ continue;
+
+ if (GetChildGlobalRectangle(child, ref globalTransform).Top < globalClipping.Top)
+ break;
+ }
+ }
+
+ for (int i = firstVisibleChild; i < children.Count; i++)
+ {
+ var child = children[i];
+ if (!child.Visible)
+ continue;
+
+ var childGlobalRect = GetChildGlobalRectangle(child, ref globalTransform);
+ if (!globalClipping.Intersects(ref childGlobalRect))
+ break;
+
+ Render2D.PushTransform(ref child._cachedTransform);
+ child.Draw();
+ Render2D.PopTransform();
+ }
+
+ static Rectangle GetChildGlobalRectangle(Control control, ref Matrix3x3 globalTransform)
+ {
+ Matrix3x3.Multiply(ref control._cachedTransform, ref globalTransform, out var globalChildTransform);
+ return new Rectangle(globalChildTransform.M31, globalChildTransform.M32, control.Width * globalChildTransform.M11, control.Height * globalChildTransform.M22);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < children.Count; i++)
+ {
+ var child = children[i];
+ if (child.Visible)
+ {
+ Render2D.PushTransform(ref child._cachedTransform);
+ child.Draw();
+ Render2D.PopTransform();
+ }
+ }
+ }
+ }
+
///
public override bool OnMouseDown(Float2 location, MouseButton button)
{
@@ -996,7 +1064,7 @@ namespace FlaxEditor.GUI.Tree
// Expand node if mouse goes over arrow
if (ArrowRect.Contains(location) && HasAnyVisibleChild)
Expand(true);
-
+
if (!_isDragOverHeader)
result = OnDragEnterHeader(data);
else
@@ -1104,7 +1172,6 @@ namespace FlaxEditor.GUI.Tree
{
// TODO: perform layout for any non-TreeNode controls
_cachedHeight = _headerHeight;
- _cachedTextColor = CacheTextColor();
Size = new Float2(width, _headerHeight);
}
@@ -1154,7 +1221,6 @@ namespace FlaxEditor.GUI.Tree
}
_cachedHeight = height;
- _cachedTextColor = CacheTextColor();
Height = Mathf.Max(_headerHeight, y);
}
diff --git a/Source/Editor/Modules/PrefabsModule.cs b/Source/Editor/Modules/PrefabsModule.cs
index e0e464c04..e0ae29299 100644
--- a/Source/Editor/Modules/PrefabsModule.cs
+++ b/Source/Editor/Modules/PrefabsModule.cs
@@ -227,7 +227,7 @@ namespace FlaxEditor.Modules
// When applying changes to prefab from actor in level ignore it's root transformation (see ActorEditor.ProcessDiff)
var originalTransform = instance.LocalTransform;
- if (instance.IsPrefabRoot && instance.Scene != null)
+ if (instance.IsPrefabRoot && instance.HasScene)
instance.LocalTransform = prefab.GetDefaultInstance().Transform;
// Call backend
diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs
index bf505394c..9bd5385fd 100644
--- a/Source/Editor/Modules/UIModule.cs
+++ b/Source/Editor/Modules/UIModule.cs
@@ -640,7 +640,7 @@ namespace FlaxEditor.Modules
cm.AddButton("Visual Script Debugger", Editor.Windows.VisualScriptDebuggerWin.FocusOrShow);
cm.AddSeparator();
cm.AddButton("Save window layout", Editor.Windows.SaveLayout);
- _menuWindowApplyWindowLayout = cm.AddChildMenu("Apply window layout");
+ _menuWindowApplyWindowLayout = cm.AddChildMenu("Window layouts");
cm.AddButton("Restore default layout", Editor.Windows.LoadDefaultLayout);
// Help
diff --git a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
index 6056cf68b..3bd317749 100644
--- a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
+++ b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
@@ -29,6 +29,7 @@ namespace FlaxEditor.SceneGraph.GUI
private DragScripts _dragScripts;
private DragAssets _dragAssets;
private DragActorType _dragActorType;
+ private DragControlType _dragControlType;
private DragScriptItems _dragScriptItems;
private DragHandlers _dragHandlers;
private List _highlights;
@@ -68,7 +69,7 @@ namespace FlaxEditor.SceneGraph.GUI
Visible = (actor.HideFlags & HideFlags.HideInHierarchy) == 0;
// Pick the correct id when inside a prefab window.
- var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID;
+ var id = actor.HasPrefabLink && !actor.HasScene ? actor.PrefabObjectID : actor.ID;
if (Editor.Instance.ProjectCache.IsExpandedActor(ref id))
{
Expand(true);
@@ -97,7 +98,7 @@ namespace FlaxEditor.SceneGraph.GUI
parentTreeNode.IsLayoutLocked = false;
// Skip UI update if node won't be in a view
- if (parentTreeNode.IsCollapsed)
+ if (parentTreeNode.IsCollapsedInHierarchy)
{
UnlockChildrenRecursive();
}
@@ -291,7 +292,7 @@ namespace FlaxEditor.SceneGraph.GUI
return Style.Current.ForegroundGrey;
}
- if (actor.Scene != null && Editor.Instance.StateMachine.IsPlayMode && actor.IsStatic)
+ if (actor.HasScene && Editor.Instance.StateMachine.IsPlayMode && actor.IsStatic)
{
// Static
return color * 0.85f;
@@ -366,7 +367,7 @@ namespace FlaxEditor.SceneGraph.GUI
if (!IsLayoutLocked && actor)
{
// Pick the correct id when inside a prefab window.
- var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID;
+ var id = actor.HasPrefabLink && !actor.HasScene ? actor.PrefabObjectID : actor.ID;
Editor.Instance.ProjectCache.SetExpandedActor(ref id, IsExpanded);
}
}
@@ -439,6 +440,17 @@ namespace FlaxEditor.SceneGraph.GUI
}
if (_dragActorType.OnDragEnter(data))
return _dragActorType.Effect;
+
+ // Check if drag control type
+ if (_dragControlType == null)
+ {
+ _dragControlType = new DragControlType(ValidateDragControlType);
+ _dragHandlers.Add(_dragControlType);
+ }
+ if (_dragControlType.OnDragEnter(data))
+ return _dragControlType.Effect;
+
+ // Check if drag script item
if (_dragScriptItems == null)
{
_dragScriptItems = new DragScriptItems(ValidateDragScriptItem);
@@ -572,10 +584,33 @@ namespace FlaxEditor.SceneGraph.GUI
Editor.LogWarning("Failed to spawn actor of type " + item.TypeName);
continue;
}
- actor.StaticFlags = Actor.StaticFlags;
+ actor.StaticFlags = newParent.StaticFlags;
actor.Name = item.Name;
- actor.Transform = Actor.Transform;
- ActorNode.Root.Spawn(actor, Actor);
+ ActorNode.Root.Spawn(actor, newParent);
+ actor.OrderInParent = newOrder;
+ }
+ result = DragDropEffect.Move;
+ }
+ // Drag control type
+ else if (_dragControlType != null && _dragControlType.HasValidDrag)
+ {
+ for (int i = 0; i < _dragControlType.Objects.Count; i++)
+ {
+ var item = _dragControlType.Objects[i];
+ var control = item.CreateInstance() as Control;
+ if (control == null)
+ {
+ Editor.LogWarning("Failed to spawn UIControl with control type " + item.TypeName);
+ continue;
+ }
+ var uiControl = new UIControl
+ {
+ Control = control,
+ StaticFlags = newParent.StaticFlags,
+ Name = item.Name,
+ };
+ ActorNode.Root.Spawn(uiControl, newParent);
+ uiControl.OrderInParent = newOrder;
}
result = DragDropEffect.Move;
}
@@ -640,8 +675,8 @@ namespace FlaxEditor.SceneGraph.GUI
private bool ValidateDragScript(Script script)
{
// Reject dragging scripts not linked to scene (eg. from prefab) or in the opposite way
- var thisHasScene = Actor.Scene != null;
- var otherHasScene = script.Scene != null;
+ var thisHasScene = Actor.HasScene;
+ var otherHasScene = script.HasScene;
if (thisHasScene != otherHasScene)
return false;
@@ -656,7 +691,12 @@ namespace FlaxEditor.SceneGraph.GUI
private static bool ValidateDragActorType(ScriptType actorType)
{
- return true;
+ return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
+ }
+
+ private static bool ValidateDragControlType(ScriptType controlType)
+ {
+ return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
}
private static bool ValidateDragScriptItem(ScriptItem script)
@@ -704,6 +744,7 @@ namespace FlaxEditor.SceneGraph.GUI
_dragScripts = null;
_dragAssets = null;
_dragActorType = null;
+ _dragControlType = null;
_dragScriptItems = null;
_dragHandlers?.Clear();
_dragHandlers = null;
diff --git a/Source/Editor/SceneGraph/LocalSceneGraph.cs b/Source/Editor/SceneGraph/LocalSceneGraph.cs
index f0f99a6ed..3c92c9bc8 100644
--- a/Source/Editor/SceneGraph/LocalSceneGraph.cs
+++ b/Source/Editor/SceneGraph/LocalSceneGraph.cs
@@ -91,7 +91,7 @@ namespace FlaxEditor.SceneGraph
private void OnActorSpawned(Actor actor)
{
// Skip actors from game
- if (actor.Scene != null)
+ if (actor.HasScene)
return;
// Check if it has parent
diff --git a/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs b/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs
index 80419ba90..c3bf7d0a5 100644
--- a/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs
+++ b/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs
@@ -186,6 +186,18 @@ namespace FlaxEditor.Surface.Archetypes
base.OnEndMouseCapture();
}
+
+ ///
+ public override bool OnKeyDown(KeyboardKeys key)
+ {
+ switch (key)
+ {
+ case KeyboardKeys.Delete:
+ _editor.SetAsset(_index, Guid.Empty);
+ return true;
+ }
+ return base.OnKeyDown(key);
+ }
}
///
diff --git a/Source/Editor/Surface/Undo/AddRemoveNodeAction.cs b/Source/Editor/Surface/Undo/AddRemoveNodeAction.cs
index 300ca700f..2c72f041f 100644
--- a/Source/Editor/Surface/Undo/AddRemoveNodeAction.cs
+++ b/Source/Editor/Surface/Undo/AddRemoveNodeAction.cs
@@ -66,6 +66,8 @@ namespace FlaxEditor.Surface.Undo
// Initialize
if (node.Values != null && node.Values.Length == _nodeValues.Length)
Array.Copy(_nodeValues, node.Values, _nodeValues.Length);
+ else if (_nodeValues != null && (node.Archetype.Flags & NodeFlags.VariableValuesSize) != 0)
+ node.Values = (object[])_nodeValues.Clone();
else if (_nodeValues != null && _nodeValues.Length != 0)
throw new InvalidOperationException("Invalid node values.");
node.Location = _nodeLocation;
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
index 21e037fbc..d849c9d79 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
@@ -65,6 +65,7 @@ namespace FlaxEditor.Windows.Assets
private PrefabWindow _window;
private DragAssets _dragAssets;
private DragActorType _dragActorType;
+ private DragControlType _dragControlType;
private DragScriptItems _dragScriptItems;
private DragHandlers _dragHandlers;
@@ -83,7 +84,12 @@ namespace FlaxEditor.Windows.Assets
private static bool ValidateDragActorType(ScriptType actorType)
{
- return true;
+ return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
+ }
+
+ private static bool ValidateDragControlType(ScriptType controlType)
+ {
+ return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
}
private static bool ValidateDragScriptItem(ScriptItem script)
@@ -113,6 +119,13 @@ namespace FlaxEditor.Windows.Assets
}
if (_dragActorType.OnDragEnter(data))
return _dragActorType.Effect;
+ if (_dragControlType == null)
+ {
+ _dragControlType = new DragControlType(ValidateDragControlType);
+ _dragHandlers.Add(_dragControlType);
+ }
+ if (_dragControlType.OnDragEnter(data))
+ return _dragControlType.Effect;
if (_dragScriptItems == null)
{
_dragScriptItems = new DragScriptItems(ValidateDragScriptItem);
@@ -176,6 +189,27 @@ namespace FlaxEditor.Windows.Assets
}
result = DragDropEffect.Move;
}
+ // Drag control type
+ else if (_dragControlType != null && _dragControlType.HasValidDrag)
+ {
+ for (int i = 0; i < _dragControlType.Objects.Count; i++)
+ {
+ var item = _dragControlType.Objects[i];
+ var control = item.CreateInstance() as Control;
+ if (control == null)
+ {
+ Editor.LogWarning("Failed to spawn UIControl with control type " + item.TypeName);
+ continue;
+ }
+ var uiControl = new UIControl
+ {
+ Control = control,
+ Name = item.Name,
+ };
+ _window.Spawn(uiControl);
+ }
+ result = DragDropEffect.Move;
+ }
// Drag script item
else if (_dragScriptItems != null && _dragScriptItems.HasValidDrag)
{
@@ -207,6 +241,7 @@ namespace FlaxEditor.Windows.Assets
_window = null;
_dragAssets = null;
_dragActorType = null;
+ _dragControlType = null;
_dragScriptItems = null;
_dragHandlers?.Clear();
_dragHandlers = null;
@@ -450,6 +485,7 @@ namespace FlaxEditor.Windows.Assets
// Create undo action
var action = new CustomDeleteActorsAction(new List(1) { actorNode }, true);
Undo.AddAction(action);
+ Focus();
Select(actorNode);
}
diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs
index a7e4e0e44..fe68896a8 100644
--- a/Source/Editor/Windows/SceneTreeWindow.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.cs
@@ -30,6 +30,7 @@ namespace FlaxEditor.Windows
private DragAssets _dragAssets;
private DragActorType _dragActorType;
+ private DragControlType _dragControlType;
private DragScriptItems _dragScriptItems;
private DragHandlers _dragHandlers;
@@ -275,7 +276,12 @@ namespace FlaxEditor.Windows
private static bool ValidateDragActorType(ScriptType actorType)
{
- return true;
+ return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
+ }
+
+ private static bool ValidateDragControlType(ScriptType controlType)
+ {
+ return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
}
private static bool ValidateDragScriptItem(ScriptItem script)
@@ -390,6 +396,13 @@ namespace FlaxEditor.Windows
}
if (_dragActorType.OnDragEnter(data) && result == DragDropEffect.None)
return _dragActorType.Effect;
+ if (_dragControlType == null)
+ {
+ _dragControlType = new DragControlType(ValidateDragControlType);
+ _dragHandlers.Add(_dragControlType);
+ }
+ if (_dragControlType.OnDragEnter(data) && result == DragDropEffect.None)
+ return _dragControlType.Effect;
if (_dragScriptItems == null)
{
_dragScriptItems = new DragScriptItems(ValidateDragScriptItem);
@@ -462,6 +475,28 @@ namespace FlaxEditor.Windows
}
result = DragDropEffect.Move;
}
+ // Drag control type
+ else if (_dragControlType != null && _dragControlType.HasValidDrag)
+ {
+ for (int i = 0; i < _dragControlType.Objects.Count; i++)
+ {
+ var item = _dragControlType.Objects[i];
+ var control = item.CreateInstance() as Control;
+ if (control == null)
+ {
+ Editor.LogWarning("Failed to spawn UIControl with control type " + item.TypeName);
+ continue;
+ }
+ var uiControl = new UIControl
+ {
+ Control = control,
+ Name = item.Name,
+ };
+ Level.SpawnActor(uiControl);
+ Editor.Scene.MarkSceneEdited(uiControl.Scene);
+ }
+ result = DragDropEffect.Move;
+ }
// Drag script item
else if (_dragScriptItems != null && _dragScriptItems.HasValidDrag)
{
@@ -495,6 +530,7 @@ namespace FlaxEditor.Windows
{
_dragAssets = null;
_dragActorType = null;
+ _dragControlType = null;
_dragScriptItems = null;
_dragHandlers?.Clear();
_dragHandlers = null;
diff --git a/Source/Editor/Windows/ToolboxWindow.cs b/Source/Editor/Windows/ToolboxWindow.cs
index ab9c218c5..7c15d29c9 100644
--- a/Source/Editor/Windows/ToolboxWindow.cs
+++ b/Source/Editor/Windows/ToolboxWindow.cs
@@ -191,6 +191,52 @@ namespace FlaxEditor.Windows
CreateGroupWithList(_actorGroups, "GUI");
CreateGroupWithList(_actorGroups, "Other");
+ // Add control types to tabs
+ foreach (var controlType in Editor.Instance.CodeEditing.Controls.Get())
+ {
+ if (controlType.IsAbstract)
+ continue;
+ _groupSearch.AddChild(CreateControlItem(Utilities.Utils.GetPropertyNameUI(controlType.Name), controlType));
+ ActorToolboxAttribute attribute = null;
+ foreach (var e in controlType.GetAttributes(false))
+ {
+ if (e is ActorToolboxAttribute actorToolboxAttribute)
+ {
+ attribute = actorToolboxAttribute;
+ break;
+ }
+ }
+ if (attribute == null)
+ continue;
+ var groupName = attribute.Group.Trim();
+
+ // Check if tab already exists and add it to the tab
+ var actorTabExists = false;
+ foreach (var child in _actorGroups.Children)
+ {
+ if (child is Tab tab)
+ {
+ if (string.Equals(tab.Text, groupName, StringComparison.OrdinalIgnoreCase))
+ {
+ var tree = tab.GetChild().GetChild();
+ if (tree != null)
+ {
+ tree.AddChild(string.IsNullOrEmpty(attribute.Name) ? CreateControlItem(Utilities.Utils.GetPropertyNameUI(controlType.Name), controlType) : CreateControlItem(attribute.Name, controlType));
+ tree.SortChildren();
+ }
+ actorTabExists = true;
+ break;
+ }
+ }
+ }
+ if (actorTabExists)
+ continue;
+
+ var group = CreateGroupWithList(_actorGroups, groupName);
+ group.AddChild(string.IsNullOrEmpty(attribute.Name) ? CreateControlItem(Utilities.Utils.GetPropertyNameUI(controlType.Name), controlType) : CreateControlItem(attribute.Name, controlType));
+ group.SortChildren();
+ }
+
// Add other actor types to respective tab based on attribute
foreach (var actorType in Editor.CodeEditing.Actors.Get())
{
@@ -304,6 +350,11 @@ namespace FlaxEditor.Windows
return new ScriptTypeItem(name, type, GUI.Drag.DragActorType.GetDragData(type));
}
+ private Item CreateControlItem(string name, ScriptType type)
+ {
+ return new ScriptTypeItem(name, type, GUI.Drag.DragControlType.GetDragData(type));
+ }
+
private ContainerControl CreateGroupWithList(Tabs parentTabs, string title, float topOffset = 0)
{
var tab = parentTabs.AddTab(new Tab(title));
diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp
index 0a500eaf4..20063ca0f 100644
--- a/Source/Engine/Engine/Engine.cpp
+++ b/Source/Engine/Engine/Engine.cpp
@@ -286,14 +286,14 @@ void Engine::OnLateFixedUpdate()
{
PROFILE_CPU_NAMED("Late Fixed Update");
+ // Collect physics simulation results (does nothing if Simulate hasn't been called in the previous loop step)
+ Physics::CollectResults();
+
// Call event
LateFixedUpdate();
// Update services
EngineService::OnLateFixedUpdate();
-
- // Collect physics simulation results (does nothing if Simulate hasn't been called in the previous loop step)
- Physics::CollectResults();
}
void Engine::OnUpdate()
diff --git a/Source/Engine/GraphicsDevice/Vulkan/Config.h b/Source/Engine/GraphicsDevice/Vulkan/Config.h
index d31cb9a06..16a19030e 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/Config.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/Config.h
@@ -33,6 +33,14 @@
#define VULKAN_USE_DEBUG_LAYER GPU_ENABLE_DIAGNOSTICS
#define VULKAN_USE_DEBUG_DATA (GPU_ENABLE_DIAGNOSTICS && COMPILE_WITH_DEV_ENV)
+#ifndef VULKAN_USE_VALIDATION_CACHE
+#ifdef VK_EXT_validation_cache
+#define VULKAN_USE_VALIDATION_CACHE VK_EXT_validation_cache
+#else
+#define VULKAN_USE_VALIDATION_CACHE 0
+#endif
+#endif
+
#ifndef VULKAN_USE_QUERIES
#define VULKAN_USE_QUERIES 1
#endif
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp
index 9b590cb16..c8ee2ccd9 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp
@@ -39,7 +39,7 @@ static const char* GInstanceExtensions[] =
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
#endif
-#if VK_EXT_validation_cache
+#if VULKAN_USE_VALIDATION_CACHE
VK_EXT_VALIDATION_CACHE_EXTENSION_NAME,
#endif
#if defined(VK_KHR_display) && 0
@@ -57,7 +57,7 @@ static const char* GDeviceExtensions[] =
#if VK_KHR_maintenance1
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
#endif
-#if VK_EXT_validation_cache
+#if VULKAN_USE_VALIDATION_CACHE
VK_EXT_VALIDATION_CACHE_EXTENSION_NAME,
#endif
#if VK_KHR_sampler_mirror_clamp_to_edge
@@ -582,7 +582,7 @@ void GPUDeviceVulkan::ParseOptionalDeviceExtensions(const Array& de
OptionalDeviceExtensions.HasKHRMaintenance2 = RenderToolsVulkan::HasExtension(deviceExtensions, VK_KHR_MAINTENANCE2_EXTENSION_NAME);
#endif
OptionalDeviceExtensions.HasMirrorClampToEdge = RenderToolsVulkan::HasExtension(deviceExtensions, VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME);
-#if VK_EXT_validation_cache
+#if VULKAN_USE_VALIDATION_CACHE
OptionalDeviceExtensions.HasEXTValidationCache = RenderToolsVulkan::HasExtension(deviceExtensions, VK_EXT_VALIDATION_CACHE_EXTENSION_NAME);
#endif
}
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index 565037e47..febeb22a1 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -1439,7 +1439,7 @@ bool GPUDeviceVulkan::SavePipelineCache()
return File::WriteAllBytes(path, data);
}
-#if VK_EXT_validation_cache
+#if VULKAN_USE_VALIDATION_CACHE
void GetValidationCachePath(String& path)
{
@@ -1900,7 +1900,7 @@ bool GPUDeviceVulkan::Init()
const VkResult result = vkCreatePipelineCache(Device, &pipelineCacheCreateInfo, nullptr, &PipelineCache);
LOG_VULKAN_RESULT(result);
}
-#if VK_EXT_validation_cache
+#if VULKAN_USE_VALIDATION_CACHE
if (OptionalDeviceExtensions.HasEXTValidationCache && vkCreateValidationCacheEXT && vkDestroyValidationCacheEXT)
{
Array data;
@@ -1915,16 +1915,16 @@ bool GPUDeviceVulkan::Init()
int32* dataPtr = (int32*)data.Get();
if (*dataPtr > 0)
{
- dataPtr++;
- const int32 version = *dataPtr++;
- const int32 versionExpected = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
- if (version == versionExpected)
+ const int32 cacheSize = *dataPtr++;
+ const int32 cacheVersion = *dataPtr++;
+ const int32 cacheVersionExpected = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
+ if (cacheVersion == cacheVersionExpected)
{
dataPtr += VK_UUID_SIZE / sizeof(int32);
}
else
{
- LOG(Warning, "Bad validation cache file, version: {0}, expected: {1}", version, versionExpected);
+ LOG(Warning, "Bad validation cache file, version: {0}, expected: {1}", cacheVersion, cacheVersionExpected);
data.Clear();
}
}
@@ -2003,7 +2003,7 @@ void GPUDeviceVulkan::Dispose()
vkDestroyPipelineCache(Device, PipelineCache, nullptr);
PipelineCache = VK_NULL_HANDLE;
}
-#if VK_EXT_validation_cache
+#if VULKAN_USE_VALIDATION_CACHE
if (ValidationCache != VK_NULL_HANDLE)
{
if (SaveValidationCache())
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
index a77744766..ee08b3eee 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
@@ -400,7 +400,9 @@ public:
uint32 HasKHRMaintenance1 : 1;
uint32 HasKHRMaintenance2 : 1;
uint32 HasMirrorClampToEdge : 1;
+#if VULKAN_USE_VALIDATION_CACHE
uint32 HasEXTValidationCache : 1;
+#endif
};
static void GetInstanceLayersAndExtensions(Array& outInstanceExtensions, Array& outInstanceLayers, bool& outDebugUtils);
@@ -496,13 +498,11 @@ public:
///
VkPipelineCache PipelineCache = VK_NULL_HANDLE;
-#if VK_EXT_validation_cache
-
+#if VULKAN_USE_VALIDATION_CACHE
///
/// The optional validation cache.
///
VkValidationCacheEXT ValidationCache = VK_NULL_HANDLE;
-
#endif
///
@@ -584,12 +584,10 @@ public:
bool SavePipelineCache();
#if VK_EXT_validation_cache
-
///
/// Saves the validation cache.
///
bool SaveValidationCache();
-
#endif
private:
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp
index b62324529..854500527 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp
@@ -116,7 +116,7 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
RenderToolsVulkan::ZeroStruct(createInfo, VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO);
createInfo.codeSize = (size_t)spirv.Length();
createInfo.pCode = (const uint32_t*)spirv.Get();
-#if VK_EXT_validation_cache
+#if VULKAN_USE_VALIDATION_CACHE
VkShaderModuleValidationCacheCreateInfoEXT validationInfo;
if (_device->ValidationCache != VK_NULL_HANDLE)
{
diff --git a/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h b/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h
index e01e980d7..887e5f89d 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h
@@ -14,6 +14,7 @@
#include
#undef VK_EXT_debug_utils
#undef VK_EXT_validation_cache
+#define VULKAN_USE_VALIDATION_CACHE 0
#pragma clang diagnostic ignored "-Wpointer-bool-conversion"
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
diff --git a/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h b/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h
index 3c8ee101e..a0e95cb2f 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h
@@ -9,6 +9,9 @@
// Support more backbuffers in case driver decides to use more (https://gitlab.freedesktop.org/apinheiro/mesa/-/issues/9)
#define VULKAN_BACK_BUFFERS_COUNT_MAX 8
+// Prevent wierd error 'Invalid VkValidationCacheEXT Object'
+#define VULKAN_USE_VALIDATION_CACHE 0
+
///
/// The implementation for the Vulkan API support for Linux platform.
///
diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h
index fdbcd1bd0..98045fc85 100644
--- a/Source/Engine/Level/Actor.h
+++ b/Source/Engine/Level/Actor.h
@@ -382,6 +382,15 @@ public:
return _isActiveInHierarchy != 0;
}
+ ///
+ /// Gets value indicating if actor is in a scene.
+ ///
+ API_PROPERTY(Attributes="HideInEditor, NoSerialize")
+ FORCE_INLINE bool HasScene() const
+ {
+ return _scene != nullptr;
+ }
+
///
/// Returns true if object is fully static on the scene, otherwise false.
///
diff --git a/Source/Engine/Level/Prefabs/Prefab.cpp b/Source/Engine/Level/Prefabs/Prefab.cpp
index 310de590f..066ae04be 100644
--- a/Source/Engine/Level/Prefabs/Prefab.cpp
+++ b/Source/Engine/Level/Prefabs/Prefab.cpp
@@ -8,9 +8,7 @@
#include "Engine/Level/Prefabs/PrefabManager.h"
#include "Engine/Level/Actor.h"
#include "Engine/Threading/Threading.h"
-#if USE_EDITOR
#include "Engine/Scripting/Scripting.h"
-#endif
REGISTER_JSON_ASSET(Prefab, "FlaxEngine.Prefab", true);
@@ -163,10 +161,10 @@ Asset::LoadResult Prefab::loadAsset()
}
}
-#if USE_EDITOR
// Register for scripts reload and unload (need to cleanup all user objects including scripts that may be attached to the default instance - it can be always restored)
- Scripting::ScriptsReloading.Bind(this);
Scripting::ScriptsUnload.Bind(this);
+#if USE_EDITOR
+ Scripting::ScriptsReloading.Bind(this);
#endif
return LoadResult::Ok;
@@ -174,10 +172,10 @@ Asset::LoadResult Prefab::loadAsset()
void Prefab::unload(bool isReloading)
{
-#if USE_EDITOR
// Unlink
- Scripting::ScriptsReloading.Unbind(this);
Scripting::ScriptsUnload.Unbind(this);
+#if USE_EDITOR
+ Scripting::ScriptsReloading.Unbind(this);
#endif
// Base
diff --git a/Source/Engine/Level/Tags.cpp b/Source/Engine/Level/Tags.cpp
index c12fed765..f1edeb91c 100644
--- a/Source/Engine/Level/Tags.cpp
+++ b/Source/Engine/Level/Tags.cpp
@@ -55,6 +55,11 @@ Tag Tags::Get(const StringView& tagName)
return tag;
}
+Tag Tags::Find(const StringView& tagName)
+{
+ return Tag(List.Find(tagName) + 1);
+}
+
Array Tags::GetSubTags(Tag parentTag)
{
Array subTags;
diff --git a/Source/Engine/Level/Tags.h b/Source/Engine/Level/Tags.h
index 7c261f313..350c88796 100644
--- a/Source/Engine/Level/Tags.h
+++ b/Source/Engine/Level/Tags.h
@@ -92,6 +92,13 @@ API_CLASS(Static) class FLAXENGINE_API Tags
/// The tag.
API_FUNCTION() static Tag Get(const StringView& tagName);
+ ///
+ /// Gets the tag. Returns empty one if it doesn't exist.
+ ///
+ /// The tag name.
+ /// The tag (might be empty).
+ API_FUNCTION() static Tag Find(const StringView& tagName);
+
///
/// Get all subtags of the specific Tag
///
diff --git a/Source/Engine/Platform/Android/AndroidPlatformSettings.h b/Source/Engine/Platform/Android/AndroidPlatformSettings.h
index 390a3936e..c42270a05 100644
--- a/Source/Engine/Platform/Android/AndroidPlatformSettings.h
+++ b/Source/Engine/Platform/Android/AndroidPlatformSettings.h
@@ -23,24 +23,24 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API
API_ENUM() enum class FLAXENGINE_API ScreenOrientation
{
///
- /// "portrait" mode
+ /// "userPortrait" mode
///
Portrait,
///
- /// "reversePortrait" mode
+ /// "userLandscape" mode
///
- PortraitReverse,
+ Landscape,
///
- /// "landscape" mode
+ /// "sensorPortrait" mode
///
- LandscapeRight,
+ SensorPortrait,
///
- /// "reverseLandscape" mode
+ /// "sensorLandscape" mode
///
- LandscapeLeft,
+ SensorLandscape,
///
/// "fullSensor" mode
@@ -72,6 +72,24 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"General\")")
String PackageName = TEXT("com.${COMPANY_NAME}.${PROJECT_NAME}");
+ ///
+ /// The application version code (eg. 1, 12, 123).
+ ///
+ API_FIELD(Attributes="EditorOrder(10), EditorDisplay(\"General\")")
+ String VersionCode = TEXT("1");
+
+ ///
+ /// The minimum Android API level (eg. 20, 28, 34).
+ ///
+ API_FIELD(Attributes = "EditorOrder(20), EditorDisplay(\"General\")")
+ String MinimumAPILevel = TEXT("23");
+
+ ///
+ /// The target Android API level (eg. 20, 28, 34).
+ ///
+ API_FIELD(Attributes = "EditorOrder(30), EditorDisplay(\"General\")")
+ String TargetAPILevel = TEXT("33");
+
///
/// The application permissions list (eg. android.media.action.IMAGE_CAPTURE). Added to the generated manifest file.
///
diff --git a/Source/Engine/Scripting/Attributes/Editor/WatermarkAttribute.cs b/Source/Engine/Scripting/Attributes/Editor/WatermarkAttribute.cs
new file mode 100644
index 000000000..73814d11c
--- /dev/null
+++ b/Source/Engine/Scripting/Attributes/Editor/WatermarkAttribute.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace FlaxEngine;
+
+///
+/// Used to add a watermark to a string textbox in the editor field
+///
+[Serializable]
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+public class WatermarkAttribute : Attribute
+{
+ ///
+ /// The watermark text.
+ ///
+ public string WatermarkText;
+
+ ///
+ /// The watermark color.
+ ///
+ public uint WatermarkColor;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The watermark text.
+ public WatermarkAttribute(string text)
+ {
+ WatermarkText = text;
+ WatermarkColor = 0; // default color of watermark in textbox
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The watermark text.
+ /// The watermark color. 0 to use default.
+ public WatermarkAttribute(string text, uint color)
+ {
+ WatermarkText = text;
+ WatermarkColor = color;
+ }
+}
diff --git a/Source/Engine/Scripting/Script.cs b/Source/Engine/Scripting/Script.cs
index f7d6c0242..b980baf3f 100644
--- a/Source/Engine/Scripting/Script.cs
+++ b/Source/Engine/Scripting/Script.cs
@@ -17,6 +17,12 @@ namespace FlaxEngine
}
}
+ ///
+ /// Gets value indicating if the actor owning the script is in a scene.
+ ///
+ [HideInEditor, NoSerialize]
+ public bool HasScene => Actor?.HasScene ?? false;
+
///
/// Gets or sets the world space transformation of the actors owning this script.
///
diff --git a/Source/Engine/UI/GUI/CanvasScaler.cs b/Source/Engine/UI/GUI/CanvasScaler.cs
index 612de3f59..abcd97a38 100644
--- a/Source/Engine/UI/GUI/CanvasScaler.cs
+++ b/Source/Engine/UI/GUI/CanvasScaler.cs
@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI
///
/// UI canvas scaling component for user interface that targets multiple different game resolutions (eg. mobile screens).
///
+ [ActorToolbox("GUI")]
public class CanvasScaler : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/Border.cs b/Source/Engine/UI/GUI/Common/Border.cs
index 58c281a3d..8c9433a98 100644
--- a/Source/Engine/UI/GUI/Common/Border.cs
+++ b/Source/Engine/UI/GUI/Common/Border.cs
@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
///
/// Border control that draws the border around the control edges (inner and outer sides).
///
+ [ActorToolbox("GUI")]
public class Border : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/Button.cs b/Source/Engine/UI/GUI/Common/Button.cs
index ff4a5fe79..ff0b776f9 100644
--- a/Source/Engine/UI/GUI/Common/Button.cs
+++ b/Source/Engine/UI/GUI/Common/Button.cs
@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI
///
/// Button control
///
+ [ActorToolbox("GUI")]
public class Button : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/CheckBox.cs b/Source/Engine/UI/GUI/Common/CheckBox.cs
index d5ab3483c..de880c039 100644
--- a/Source/Engine/UI/GUI/Common/CheckBox.cs
+++ b/Source/Engine/UI/GUI/Common/CheckBox.cs
@@ -29,6 +29,7 @@ namespace FlaxEngine.GUI
/// Check box control.
///
///
+ [ActorToolbox("GUI")]
public class CheckBox : Control
{
///
diff --git a/Source/Engine/UI/GUI/Common/Dropdown.cs b/Source/Engine/UI/GUI/Common/Dropdown.cs
index 60e8e801b..1dbac95ab 100644
--- a/Source/Engine/UI/GUI/Common/Dropdown.cs
+++ b/Source/Engine/UI/GUI/Common/Dropdown.cs
@@ -9,6 +9,7 @@ namespace FlaxEngine.GUI
/// Dropdown menu control allows to choose one item from the provided collection of options.
///
///
+ [ActorToolbox("GUI")]
public class Dropdown : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/Image.cs b/Source/Engine/UI/GUI/Common/Image.cs
index 0a0129db0..897c82b3f 100644
--- a/Source/Engine/UI/GUI/Common/Image.cs
+++ b/Source/Engine/UI/GUI/Common/Image.cs
@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// The basic GUI image control. Shows texture, sprite or render target.
///
///
+ [ActorToolbox("GUI")]
public class Image : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/Label.cs b/Source/Engine/UI/GUI/Common/Label.cs
index 46cb7415e..61282e7a5 100644
--- a/Source/Engine/UI/GUI/Common/Label.cs
+++ b/Source/Engine/UI/GUI/Common/Label.cs
@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// The basic GUI label control.
///
///
+ [ActorToolbox("GUI")]
public class Label : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/ProgressBar.cs b/Source/Engine/UI/GUI/Common/ProgressBar.cs
index 6a17535b0..ff048600e 100644
--- a/Source/Engine/UI/GUI/Common/ProgressBar.cs
+++ b/Source/Engine/UI/GUI/Common/ProgressBar.cs
@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Progress bar control shows visual progress of the action or set of actions.
///
///
+ [ActorToolbox("GUI")]
public class ProgressBar : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs b/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs
index 499668d93..664a20df9 100644
--- a/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs
+++ b/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs
@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
///
/// UI container control that can render children to texture and display pre-cached texture instead of drawing children every frame. It can be also used to render part of UI to texture and use it in material or shader.
///
+ [ActorToolbox("GUI")]
public class RenderToTextureControl : ContainerControl
{
private bool _invalid, _redrawRegistered, _isDuringTextureDraw;
diff --git a/Source/Engine/UI/GUI/Common/RichTextBox.cs b/Source/Engine/UI/GUI/Common/RichTextBox.cs
index 77382a5d7..c4a69b08f 100644
--- a/Source/Engine/UI/GUI/Common/RichTextBox.cs
+++ b/Source/Engine/UI/GUI/Common/RichTextBox.cs
@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI
///
/// Rich text box control which can gather text input from the user and present text in highly formatted and stylized way.
///
+ [ActorToolbox("GUI")]
public partial class RichTextBox : RichTextBoxBase
{
private TextBlockStyle _textStyle;
diff --git a/Source/Engine/UI/GUI/Common/Slider.cs b/Source/Engine/UI/GUI/Common/Slider.cs
index a62cbe8ee..39023ee1f 100644
--- a/Source/Engine/UI/GUI/Common/Slider.cs
+++ b/Source/Engine/UI/GUI/Common/Slider.cs
@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI;
///
/// The slider control.
///
+[ActorToolbox("GUI")]
public class Slider : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/Spacer.cs b/Source/Engine/UI/GUI/Common/Spacer.cs
index e87cfbabc..005620d7d 100644
--- a/Source/Engine/UI/GUI/Common/Spacer.cs
+++ b/Source/Engine/UI/GUI/Common/Spacer.cs
@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// Helper control used to insert blank space into the layout.
///
///
+ [ActorToolbox("GUI")]
public sealed class Spacer : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs
index 2553dc439..3d0581c4e 100644
--- a/Source/Engine/UI/GUI/Common/TextBox.cs
+++ b/Source/Engine/UI/GUI/Common/TextBox.cs
@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
///
/// Text box control which can gather text input from the user.
///
+ [ActorToolbox("GUI")]
public class TextBox : TextBoxBase
{
private TextLayoutOptions _layout;
@@ -213,7 +214,7 @@ namespace FlaxEngine.GUI
color *= 0.6f;
Render2D.DrawText(font, _text, color, ref _layout, TextMaterial);
}
- else if (!string.IsNullOrEmpty(_watermarkText) && !IsFocused)
+ else if (!string.IsNullOrEmpty(_watermarkText))
{
Render2D.DrawText(font, _watermarkText, WatermarkTextColor, ref _layout, TextMaterial);
}
diff --git a/Source/Engine/UI/GUI/Common/TextBoxBase.cs b/Source/Engine/UI/GUI/Common/TextBoxBase.cs
index 460d6f4b1..2db8c33e2 100644
--- a/Source/Engine/UI/GUI/Common/TextBoxBase.cs
+++ b/Source/Engine/UI/GUI/Common/TextBoxBase.cs
@@ -1203,7 +1203,7 @@ namespace FlaxEngine.GUI
if (base.OnMouseDown(location, button))
return true;
- if (button == MouseButton.Left && _text.Length > 0 && _isSelectable)
+ if (button == MouseButton.Left && _isSelectable)
{
Focus();
OnSelectingBegin();
@@ -1219,6 +1219,10 @@ namespace FlaxEngine.GUI
else
SetSelection(_selectionStart, hitPos);
}
+ else if (string.IsNullOrEmpty(_text))
+ {
+ SetSelection(0);
+ }
else
{
SetSelection(hitPos);
diff --git a/Source/Engine/UI/GUI/Panels/AlphaPanel.cs b/Source/Engine/UI/GUI/Panels/AlphaPanel.cs
index a67d47fac..dd421571a 100644
--- a/Source/Engine/UI/GUI/Panels/AlphaPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/AlphaPanel.cs
@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
///
/// Changes alpha of all its children
///
+ [ActorToolbox("GUI")]
public class AlphaPanel : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Panels/BlurPanel.cs b/Source/Engine/UI/GUI/Panels/BlurPanel.cs
index 44a9e3b4d..963dadd8e 100644
--- a/Source/Engine/UI/GUI/Panels/BlurPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/BlurPanel.cs
@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// The blur panel that applied the Gaussian-blur to all content beneath the control.
///
///
+ [ActorToolbox("GUI")]
public class BlurPanel : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Panels/DropPanel.cs b/Source/Engine/UI/GUI/Panels/DropPanel.cs
index e0785a99d..e053edd9c 100644
--- a/Source/Engine/UI/GUI/Panels/DropPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/DropPanel.cs
@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Drop Panel arranges control vertically and provides feature to collapse contents.
///
///
+ [ActorToolbox("GUI")]
public class DropPanel : ContainerControl
{
///
diff --git a/Source/Engine/UI/GUI/Panels/GridPanel.cs b/Source/Engine/UI/GUI/Panels/GridPanel.cs
index 629343f44..2b1a0a123 100644
--- a/Source/Engine/UI/GUI/Panels/GridPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/GridPanel.cs
@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// A panel that divides up available space between all of its children.
///
///
+ [ActorToolbox("GUI")]
public class GridPanel : ContainerControl
{
private Margin _slotPadding;
diff --git a/Source/Engine/UI/GUI/Panels/HorizontalPanel.cs b/Source/Engine/UI/GUI/Panels/HorizontalPanel.cs
index 29bb498dd..6d3256a00 100644
--- a/Source/Engine/UI/GUI/Panels/HorizontalPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/HorizontalPanel.cs
@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// This panel arranges child controls horizontally.
///
///
+ [ActorToolbox("GUI")]
public class HorizontalPanel : PanelWithMargins
{
///
diff --git a/Source/Engine/UI/GUI/Panels/Panel.cs b/Source/Engine/UI/GUI/Panels/Panel.cs
index 8435854f5..61a2d2b8c 100644
--- a/Source/Engine/UI/GUI/Panels/Panel.cs
+++ b/Source/Engine/UI/GUI/Panels/Panel.cs
@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Panel UI control.
///
///
+ [ActorToolbox("GUI")]
public class Panel : ScrollableControl
{
private bool _layoutChanged;
diff --git a/Source/Engine/UI/GUI/Panels/TilesPanel.cs b/Source/Engine/UI/GUI/Panels/TilesPanel.cs
index 13e40d8bf..8b2148bce 100644
--- a/Source/Engine/UI/GUI/Panels/TilesPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/TilesPanel.cs
@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Panel that arranges child controls like tiles.
///
///
+ [ActorToolbox("GUI")]
public class TilesPanel : ContainerControl
{
private Margin _tileMargin;
diff --git a/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs b/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs
index ed6ed1d8a..6c112d9d5 100644
--- a/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/UniformGridPanel.cs
@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// A panel that evenly divides up available space between all of its children.
///
///
+ [ActorToolbox("GUI")]
public class UniformGridPanel : ContainerControl
{
private Margin _slotPadding;
diff --git a/Source/Engine/UI/GUI/Panels/VerticalPanel.cs b/Source/Engine/UI/GUI/Panels/VerticalPanel.cs
index 39bd6a294..b2fcdeae9 100644
--- a/Source/Engine/UI/GUI/Panels/VerticalPanel.cs
+++ b/Source/Engine/UI/GUI/Panels/VerticalPanel.cs
@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// This panel arranges child controls vertically.
///
///
+ [ActorToolbox("GUI")]
public class VerticalPanel : PanelWithMargins
{
///
diff --git a/Source/Engine/UI/SpriteRender.h b/Source/Engine/UI/SpriteRender.h
index dbec117e4..d9eb769c2 100644
--- a/Source/Engine/UI/SpriteRender.h
+++ b/Source/Engine/UI/SpriteRender.h
@@ -10,7 +10,7 @@
///
/// Sprite rendering object.
///
-API_CLASS(Attributes="ActorContextMenu(\"New/UI/Sprite Render\"), ActorToolbox(\"GUI\")")
+API_CLASS(Attributes="ActorContextMenu(\"New/UI/Sprite Render\"), ActorToolbox(\"Visuals\")")
class FLAXENGINE_API SpriteRender : public Actor
{
DECLARE_SCENE_OBJECT(SpriteRender);
diff --git a/Source/Engine/UI/TextRender.h b/Source/Engine/UI/TextRender.h
index a99a53318..cc89fbee1 100644
--- a/Source/Engine/UI/TextRender.h
+++ b/Source/Engine/UI/TextRender.h
@@ -18,7 +18,7 @@
///
/// Text rendering object.
///
-API_CLASS(Attributes="ActorContextMenu(\"New/UI/Text Render\"), ActorToolbox(\"GUI\")")
+API_CLASS(Attributes="ActorContextMenu(\"New/UI/Text Render\"), ActorToolbox(\"Visuals\")")
class FLAXENGINE_API TextRender : public Actor
{
DECLARE_SCENE_OBJECT(TextRender);
diff --git a/Source/Engine/UI/UIControl.h b/Source/Engine/UI/UIControl.h
index e76aca65a..7cdbbe7ac 100644
--- a/Source/Engine/UI/UIControl.h
+++ b/Source/Engine/UI/UIControl.h
@@ -8,7 +8,7 @@
///
/// Contains a single GUI control (on C# side).
///
-API_CLASS(Sealed, Attributes="ActorContextMenu(\"New/UI/UI Control\"), ActorToolbox(\"GUI\")")
+API_CLASS(Sealed, Attributes="ActorContextMenu(\"New/UI/UI Control\"), ActorToolbox(\"GUI\", \"Empty UIControl\")")
class FLAXENGINE_API UIControl : public Actor
{
DECLARE_SCENE_OBJECT(UIControl);
diff --git a/Source/Platforms/Android/Binaries/Project/app/build.gradle b/Source/Platforms/Android/Binaries/Project/app/build.gradle
index 2f5da0a56..fd7764060 100644
--- a/Source/Platforms/Android/Binaries/Project/app/build.gradle
+++ b/Source/Platforms/Android/Binaries/Project/app/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 24
+ compileSdk ${TargetSdk}
namespace "${PackageName}"
defaultConfig {
applicationId "${PackageName}"
- minSdkVersion 24
- targetSdkVersion 24
- versionCode 1
+ minSdk ${MinimumSdk}
+ targetSdk ${TargetSdk}
+ versionCode ${VersionCode}
versionName "${ProjectVersion}"
ndk {
abiFilter "${PackageAbi}"
diff --git a/Source/Platforms/Android/Binaries/Project/app/src/main/AndroidManifest.xml b/Source/Platforms/Android/Binaries/Project/app/src/main/AndroidManifest.xml
index 5169e3846..6e84915ca 100644
--- a/Source/Platforms/Android/Binaries/Project/app/src/main/AndroidManifest.xml
+++ b/Source/Platforms/Android/Binaries/Project/app/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
android:extractNativeLibs="true"
android:hasCode="true">