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/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs
index 5804dc687..d5782c10f 100644
--- a/Source/Editor/GUI/Tree/TreeNode.cs
+++ b/Source/Editor/GUI/Tree/TreeNode.cs
@@ -730,12 +730,15 @@ namespace FlaxEditor.GUI.Tree
// 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)
+ if (GetChildGlobalRectangle(children[firstVisibleChild], ref globalTransform).Top > globalClipping.Top || !children[firstVisibleChild].Visible)
{
- // Overshoot...
+ // 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;
}
@@ -744,18 +747,16 @@ namespace FlaxEditor.GUI.Tree
for (int i = firstVisibleChild; i < children.Count; i++)
{
var child = children[i];
- if (child.Visible)
- {
- var childGlobalRect = GetChildGlobalRectangle(child, ref globalTransform);
- if (globalClipping.Intersects(ref childGlobalRect))
- {
- Render2D.PushTransform(ref child._cachedTransform);
- child.Draw();
- Render2D.PopTransform();
- }
- else
- break;
- }
+ 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)
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/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 387ae93fa..d849c9d79 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
@@ -485,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/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/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/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs
index 7837b1f83..3d0581c4e 100644
--- a/Source/Engine/UI/GUI/Common/TextBox.cs
+++ b/Source/Engine/UI/GUI/Common/TextBox.cs
@@ -214,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);